Repository: zcash/zcash (language: rust)

Issue:
Redesign and drastically simplify tx prioritization policy
Bitcoin fee/prioritisation policy was based on the assumption of the monetary amounts transferred being visible. This assumption no longer holds. IMHO there is no reason for these amounts to be an input to tx prioritisation at all. We should be trying to minimise tx acceptance latency; the simplest way to do that is for priority to be based mainly on transaction age, with as little complication as possible introduced to mitigate denial of service attacks.


Discussion / hints:

Fix patch:
diff --git a/contrib/debian/examples/zcash.conf b/contrib/debian/examples/zcash.conf
index 97870afe015..c2219621026 100644
--- a/contrib/debian/examples/zcash.conf
+++ b/contrib/debian/examples/zcash.conf
@@ -2,7 +2,9 @@
 ## zcash.conf configuration file. Lines beginning with # are comments.
 ##
 
-# Network-related settings:
+##
+## Network-related settings
+##
 
 # Run on the test network instead of the real zcash network.
 #testnet=0
@@ -56,9 +58,9 @@
 # Maximum number of inbound+outbound connections.
 #maxconnections=
 
-#
-# JSON-RPC options (for controlling a running Zcash/zcashd process)
-#
+##
+## JSON-RPC options (for controlling a running Zcash/zcashd process)
+##
 
 # server=1 tells zcashd to accept JSON-RPC commands (set as default if not specified)
 #server=1
@@ -95,18 +97,39 @@
 # this option:
 #rpcconnect=127.0.0.1
 
-# Transaction Fee
+##
+## Transaction creation options for 'z_*' APIs.
+##
+
+# Set the maximum number of Orchard actions permitted in a transaction.
+#orchardactionlimit=50
+
+##
+## Transaction creation options for legacy APIs (sendtoaddress, sendmany,
+## and fundrawtransaction).
+##
 
-# Send transactions as zero-fee transactions if possible (default: 0)
-#sendfreetransactions=0
+# The preferred fee rate (in ZEC per 1000 bytes) used for transactions
+# created by legacy APIs. If the transaction is less than 1000 bytes then
+# the fee rate is applied as though it were 1000 bytes.
+#paytxfee=<amt>
 
-# Create transactions that have enough fees (or priority) so they are likely to # begin confirmation within n blocks (default: 1).
-# This setting is overridden by the -paytxfee option.
-#txconfirmtarget=n
+# If paytxfee is not set, include enough fee that transactions created by
+# legacy APIs begin confirmation on average within n blocks. This is only
+# used if there is sufficient mempool data to estimate the fee; if not,
+# the fallback fee set by mintxfee is used.
+#txconfirmtarget=2
 
-# Miscellaneous options
+# The fallback fee rate (in ZEC per 1000 bytes) used by legacy APIs when
+# paytxfee has not been set and there is insufficient mempool data to
+# estimate a fee according to the txconfirmtarget option.
+#mintxfee=0.00001
+
+##
+## Miscellaneous options
+##
 
-# Enable attempt to mine zcash.
+# Enable attempt to CPU-mine zcash. This is only useful on testnet.
 #gen=0
 
 # Set the number of threads to be used for mining zcash (-1 = all cores).
@@ -119,11 +142,3 @@
 # Pre-generate this many public/private key pairs, so wallet backups will be valid for
 # both prior transactions and several dozen future transactions.
 #keypool=100
-
-# Pay an optional transaction fee every time you send zcash.  Transactions with fees
-# are more likely than free transactions to be included in generated blocks, so may
-# be validated sooner. This setting does not affect private transactions created with 
-# 'z_sendmany'.
-#paytxfee=0.00
-
-
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 79b7796b783..c489eb3550b 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -29,6 +29,35 @@ RPC Changes
   is unable to construct the transaction without selecting funds from the transparent 
   pool, so the impact of this change is that for such transactions, the user must specify
   `AllowFullyTransparent`.
+- The `estimatepriority` RPC call has been removed.
+- The `priority_delta` argument to the `prioritisetransaction` RPC call now has
+  no effect and must be set to a dummy value (0 or null).
+
+Changes to Transaction Fee Selection
+------------------------------------
+
+- The `-sendfreetransactions` option has been removed. This option used to
+  instruct the wallet's legacy transaction creation APIs (`sendtoaddress`,
+  `sendmany`, and `fundrawtransaction`) to use a zero fee for "small" transactions
+  that spend "old" inputs. It will now cause a warning on node startup if used.
+
+Changes to Block Template Construction
+--------------------------------------
+
+- The block template construction algorithm no longer favours transactions that
+  were previously considered "high priority" because they spent older inputs. The
+  `-blockprioritysize` config option, which configured the portion of the block
+  reserved for these transactions, has been removed and will now cause a warning
+  if used.
+
+Removal of Priority Estimation
+------------------------------
+
+- Estimation of "priority" needed for a transaction to be included within a target
+  number of blocks, and the associated `estimatepriority` RPC call, have been
+  removed. The format for `fee_estimates.dat` has also changed to no longer save
+  these priority estimates. It will automatically be converted to the new format
+  which is not readable by prior versions of the software.
 
 [Deprecations](https://zcash.github.io/zcash/user/deprecation.html)
 --------------
diff --git a/src/amount.cpp b/src/amount.cpp
index 11468eca26d..1fd13c7777a 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -37,5 +37,5 @@ CAmount CFeeRate::GetFee(size_t nSize) const
 
 std::string CFeeRate::ToString() const
 {
-    return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
+    return strprintf("%d.%08d %s per 1000 bytes", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
 }
diff --git a/src/amount.h b/src/amount.h
index bd9316dbffa..44991b26d66 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -22,8 +22,8 @@ extern const std::string MINOR_CURRENCY_UNIT;
 
 /** No amount larger than this (in zatoshi) is valid.
  *
- * Note that this constant is *not* the total money supply, which in Bitcoin
- * currently happens to be less than 21,000,000 BTC for various reasons, but
+ * Note that this constant is *not* the total money supply, which in Zcash
+ * currently happens to be less than 21,000,000 ZEC for various reasons, but
  * rather a sanity check. As this sanity check is used by consensus-critical
  * validation code, the exact value of the MAX_MONEY constant is consensus
  * critical; in unusual circumstances like a(nother) overflow bug that allowed
diff --git a/src/coins.cpp b/src/coins.cpp
index 3a0e190ed51..b6f4e047105 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -1083,39 +1083,6 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
     return true;
 }
 
-double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
-{
-    if (tx.IsCoinBase())
-        return 0.0;
-
-    // Shielded transfers do not reveal any information about the value or age of a note, so we
-    // cannot apply the priority algorithm used for transparent utxos.  Instead, we just
-    // use the maximum priority for all (partially or fully) shielded transactions.
-    // (Note that coinbase transactions cannot contain JoinSplits, or Sapling shielded Spends or Outputs.)
-
-    if (tx.vJoinSplit.size() > 0 ||
-        tx.vShieldedSpend.size() > 0 ||
-        tx.vShieldedOutput.size() > 0 ||
-        tx.GetOrchardBundle().IsPresent())
-    {
-        return MAX_PRIORITY;
-    }
-
-    // FIXME: this logic is partially duplicated between here and CreateNewBlock in miner.cpp.
-    double dResult = 0.0;
-    for (const CTxIn& txin : tx.vin)
-    {
-        const CCoins* coins = AccessCoins(txin.prevout.hash);
-        assert(coins);
-        if (!coins->IsAvailable(txin.prevout.n)) continue;
-        if (coins->nHeight < nHeight) {
-            dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
-        }
-    }
-
-    return tx.ComputePriority(dResult);
-}
-
 CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
     assert(!cache.hasModifier);
     cache.hasModifier = true;
diff --git a/src/coins.h b/src/coins.h
index 37313270202..96cf8f8150a 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -49,7 +49,7 @@
  *    - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
  *    - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
  *    - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
- *               * 8358: compact amount representation for 60000000000 (600 BTC)
+ *               * 8358: compact amount representation for 60000000000 (600 ZEC)
  *               * 00: special txout type pay-to-pubkey-hash
  *               * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
  *    - height = 203998
@@ -65,11 +65,11 @@
  *                2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
  *  - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
  *  - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
- *             * 86ef97d579: compact amount representation for 234925952 (2.35 BTC)
+ *             * 86ef97d579: compact amount representation for 234925952 (2.35 ZEC)
  *             * 00: special txout type pay-to-pubkey-hash
  *             * 61b01caab50f1b8e9c50a5057eb43c2d9563a4ee: address uint160
  *  - vout[16]: bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4
- *              * bbd123: compact amount representation for 110397 (0.001 BTC)
+ *              * bbd123: compact amount representation for 110397 (0.001 ZEC)
  *              * 00: special txout type pay-to-pubkey-hash
  *              * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
  *  - height = 120891
@@ -654,12 +654,9 @@ class CCoinsViewCache : public CCoinsViewBacked
     //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
     bool HaveInputs(const CTransaction& tx) const;
 
-    //! Check whether all joinsplit and sapling spend requirements (anchors/nullifiers) are satisfied
+    //! Check whether all shielded spend requirements (anchors/nullifiers) are satisfied
     tl::expected<void, UnsatisfiedShieldedReq> CheckShieldedRequirements(const CTransaction& tx) const;
 
-    //! Return priority of tx at height nHeight
-    double GetPriority(const CTransaction &tx, int nHeight) const;
-
     const CTxOut &GetOutputFor(const CTxIn& input) const;
 
     friend class CCoinsModifier;
diff --git a/src/init.cpp b/src/init.cpp
index a57145ea0c9..c80ece18284 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -479,19 +479,17 @@ std::string HelpMessage(HelpMessageMode mode)
     {
         strUsage += HelpMessageOpt("-clockoffset=<n>", "Applies offset of <n> seconds to the actual time. Incompatible with -mocktime (default: 0)");
         strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch. Incompatible with -clockoffset (default: 0)");
-        strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY));
-        strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY));
         strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit total size of signature and bundle caches to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
         strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
     }
-    strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"),
+    strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Transactions must have at least this fee rate (in %s per 1000 bytes) for relaying, mining and transaction creation (default: %s). This is not the only fee constraint."),
         CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)));
     strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)"),
         CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)));
     strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of the debug log"));
     if (showDebug)
     {
-        strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
+        strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
     }
     // strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink the debug log on client startup (default: 1 when no -debug)"));
 
@@ -504,7 +502,6 @@ std::string HelpMessage(HelpMessageMode mode)
     strUsage += HelpMessageGroup(_("Block creation options:"));
     strUsage += HelpMessageOpt("-blockminsize=<n>", strprintf(_("Set minimum block size in bytes (default: %u)"), DEFAULT_BLOCK_MIN_SIZE));
     strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
-    strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
     if (GetBoolArg("-help-debug", false))
         strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION));
 
@@ -1228,16 +1225,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
     if (nConnectTimeout <= 0)
         nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
 
-    // Fee-per-kilobyte amount considered the same as "free"
-    // If you are mining, be careful setting this:
-    // if you set it to zero then
-    // a transaction spammer can cheaply fill blocks using
-    // 1-satoshi-fee transactions. It should be set above the real
+    // Fee rate in zatoshis per 1000 bytes required for mempool acceptance and relay.
+    // TODO(update when ZIP 317 is implemented):
+    // If you are mining, be careful setting this. If you set it too low then a
+    // transaction spammer can cheaply fill blocks. It should be set above the real
     // cost to you of processing a transaction.
     if (mapArgs.count("-minrelaytxfee"))
     {
         CAmount n = 0;
-        if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
+        if (ParseMoney(mapArgs["-minrelaytxfee"], n))
             ::minRelayTxFee = CFeeRate(n);
         else
             return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
@@ -1296,6 +1292,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
     }
 #endif
 
+    if (GetArg("-blockprioritysize", 0) != 0) {
+        InitWarning(_("The argument -blockprioritysize is no longer supported."));
+    }
+
     if (!mapMultiArgs["-nuparams"].empty()) {
         // Allow overriding network upgrade parameters for testing
         if (chainparams.NetworkIDString() != "regtest") {
diff --git a/src/main.cpp b/src/main.cpp
index 773f4a72c7b..ec83157f5b9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1772,32 +1772,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
     return true;
 }
 
-CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned int nBytes, bool fAllowFree)
-{
-    uint256 hash = tx.GetHash();
-    double dPriorityDelta = 0;
-    CAmount nFeeDelta = 0;
-    pool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
-    if (dPriorityDelta > 0 || nFeeDelta > 0)
-        return 0;
-
-    CAmount nMinFee = ::minRelayTxFee.GetFeeForRelay(nBytes);
-
-    if (fAllowFree)
-    {
-        // There is a free transaction area in blocks created by most miners,
-        // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
-        //   to be considered to fall into this category. We don't want to encourage sending
-        //   multiple transactions instead of one big transaction to avoid fees.
-        if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
-            nMinFee = 0;
-    }
-
-    if (!MoneyRange(nMinFee))
-        nMinFee = MAX_MONEY;
-    return nMinFee;
-}
-
 /** Convert CValidationState to a human-readable message for logging */
 std::string FormatStateMessage(const CValidationState &state)
 {
@@ -1940,7 +1914,9 @@ bool AcceptToMemoryPool(
 
         CAmount nValueOut = tx.GetValueOut();
         CAmount nFees = nValueIn-nValueOut;
-        double dPriority = view.GetPriority(tx, chainActive.Height());
+        // nModifiedFees includes any fee deltas from PrioritiseTransaction
+        CAmount nModifiedFees = nFees;
+        pool.ApplyDelta(hash, nModifiedFees);
 
         // Keep track of transactions that spend a coinbase, which we re-scan
         // during reorgs to ensure COINBASE_MATURITY is still met.
@@ -1956,46 +1932,20 @@ bool AcceptToMemoryPool(
         // For v1-v4 transactions, we don't yet know if the transaction commits
         // to consensusBranchId, but if the entry gets added to the mempool, then
         // it has passed ContextualCheckInputs and therefore this is correct.
-        CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), fSpendsCoinbase, nSigOps, consensusBranchId);
+        CTxMemPoolEntry entry(tx, nFees, GetTime(), chainActive.Height(), pool.HasNoInputsOf(tx), fSpendsCoinbase, nSigOps, consensusBranchId);
         unsigned int nSize = entry.GetTxSize();
 
-        // Before zcashd 4.2.0, we had a condition here to always accept a tx if it contained
-        // JoinSplits and had at least the default fee. It is no longer necessary to treat
-        // that as a special case, because the fee returned by GetMinRelayFee is always at
-        // most DEFAULT_FEE.
-
-        CAmount txMinFee = GetMinRelayFee(tx, pool, nSize, true);
-        if (fLimitFree && nFees < txMinFee) {
-            return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
-                strprintf("%d < %d", nFees, txMinFee));
-        }
-
-        // Require that free transactions have sufficient priority to be mined in the next block.
-        if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFeeForRelay(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
-            return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
-        }
-
-        // Continuously rate-limit free (really, very-low-fee) transactions
-        // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
-        // be annoying or make others' transactions take longer to confirm.
-        if (fLimitFree && nFees < ::minRelayTxFee.GetFeeForRelay(nSize))
-        {
-            static CCriticalSection csFreeLimiter;
-            static double dFreeCount;
-            static int64_t nLastTime;
-            int64_t nNow = GetTime();
-
-            LOCK(csFreeLimiter);
-
-            // Use an exponentially decaying ~10-minute window:
-            dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
-            nLastTime = nNow;
-            // -limitfreerelay unit is thousand-bytes-per-minute
-            // At default rate it would take over a month to fill 1GB
-            if (dFreeCount >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000)
-                return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
-            LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
-            dFreeCount += nSize;
+        // No transactions are allowed with modified fee below the minimum relay fee,
+        // except from disconnected blocks. The minimum relay fee will never be more
+        // than DEFAULT_FEE zatoshis.
+        CAmount minRelayFee = ::minRelayTxFee.GetFeeForRelay(nSize);
+        if (fLimitFree && nModifiedFees < minRelayFee) {
+            LogPrint("mempool",
+                    "Not accepting transaction with txid %s, size %d bytes, effective fee %d " + MINOR_CURRENCY_UNIT +
+                    ", and fee delta %d " + MINOR_CURRENCY_UNIT + " to the mempool due to insufficient fee. " +
+                    " The minimum acceptance/relay fee for this transaction is %d " + MINOR_CURRENCY_UNIT,
+                    tx.GetHash().ToString(), nSize, nModifiedFees, nModifiedFees - nFees, minRelayFee);
+            return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
         }
 
         if (fRejectAbsurdFee && nFees > maxTxFee) {
@@ -7207,7 +7157,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string
                             LogPrint("mempool", "   invalid orphan tx %s\n", orphanHash.ToString());
                         }
                         // Has inputs but not accepted to mempool
-                        // Probably non-standard or insufficient fee/priority
+                        // Probably non-standard or insufficient fee
                         LogPrint("mempool", "   removed orphan tx %s\n", orphanHash.ToString());
                         vEraseQueue.push_back(orphanHash);
                         // Add the wtxid of this transaction to our reject filter.
diff --git a/src/main.h b/src/main.h
index df0cc243c0a..3e985bf3b01 100644
--- a/src/main.h
+++ b/src/main.h
@@ -68,13 +68,13 @@ static const unsigned int MAX_REORG_LENGTH = COINBASE_MATURITY - 1;
 static const bool DEFAULT_WHITELISTRELAY = true;
 /** Default for DEFAULT_WHITELISTFORCERELAY. */
 static const bool DEFAULT_WHITELISTFORCERELAY = true;
-/** Default for -minrelaytxfee, minimum relay fee for transactions in zatoshis/kB */
+/** Default for -minrelaytxfee, minimum relay fee rate for transactions in zatoshis per 1000 bytes. TODO(misnamed, this is a rate) */
 static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100;
-//! -maxtxfee default
+/** Default for -maxtxfee in zatoshis. */
 static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
-//! Discourage users to set fees higher than this amount (in satoshis) per kB
+/** Discourage users from setting fee rates higher than this in zatoshis per 1000 bytes. */
 static const CAmount HIGH_TX_FEE_PER_KB = 0.01 * COIN;
-//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
+/** Warn if -maxtxfee is set to a fee higher than this in zatoshis. */
 static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB;
 /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
 static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
@@ -135,8 +135,6 @@ static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
  *  Limits the impact of low-fee transaction floods. */
 static const unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
 
-static const unsigned int DEFAULT_LIMITFREERELAY = 15;
-static const bool DEFAULT_RELAYPRIORITY = false;
 static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
 
 /** Default for -permitbaremultisig */
@@ -210,9 +208,9 @@ extern bool fIBDSkipTxVerification;
 // it is unneeded for testing
 extern bool fCoinbaseEnforcedShieldingEnabled;
 extern size_t nCoinCacheUsage;
-/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
+/** Transactions must have at least this fee rate (in zatoshis per 1000 bytes) for relaying, mining and transaction creation. */
 extern CFeeRate minRelayTxFee;
-/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */
+/** Absolute maximum transaction fee (in zatoshis) used by wallet and mempool (rejects high fee in sendrawtransaction). */
 extern CAmount maxTxFee;
 extern bool fAlerts;
 /** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
@@ -359,9 +357,6 @@ struct CNodeStateStats {
 };
 
 
-
-CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-
 /**
  * Count ECDSA signature operations the old-fashioned (pre-0.6) way
  * @return number of sigops this transaction's outputs will produce when spent
diff --git a/src/miner.cpp b/src/miner.cpp
index cd86206786d..cf52e331ca4 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -57,8 +57,8 @@ using namespace std;
 //
 // Unconfirmed transactions in the memory pool often depend on other
 // transactions in the memory pool. When we select transactions from the
-// pool, we select by highest priority or fee rate, so we might consider
-// transactions that depend on transactions that aren't yet in the block.
+// pool, we select by highest fee rate, so we might consider transactions
+// that depend on transactions that aren't yet in the block.
 
 std::optional<uint64_t> last_block_num_txs;
 std::optional<uint64_t> last_block_size;
@@ -437,7 +437,6 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(
         }
     }
 
-    addPriorityTxs();
     addScoreTxs();
 
     last_block_num_txs = nBlockTx;
@@ -635,12 +634,8 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
 
     bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
     if (fPrintPriority) {
-        double dPriority = iter->GetPriority(nHeight);
-        CAmount dummy;
-        mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy);
-        LogPrintf("%s: priority %.1f fee %s txid %s\n",
+        LogPrintf("%s: fee %s txid %s\n",
                   __func__,
-                  dPriority,
                   CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
                   iter->GetTx().GetHash().ToString());
     }
@@ -704,80 +699,6 @@ void BlockAssembler::addScoreTxs()
     }
 }
 
-void BlockAssembler::addPriorityTxs()
-{
-    // How much of the block should be dedicated to high-priority transactions,
-    // included regardless of the fees they pay
-    unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
-    nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
-
-    if (nBlockPrioritySize == 0) {
-        return;
-    }
-
-    // This vector will be sorted into a priority queue:
-    vector<TxCoinAgePriority> vecPriority;
-    TxCoinAgePriorityCompare pricomparer;
-    std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash> waitPriMap;
-    typedef std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
-    double actualPriority = -1;
-
-    vecPriority.reserve(mempool.mapTx.size());
-    for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
-         mi != mempool.mapTx.end(); ++mi)
-    {
-        double dPriority = mi->GetPriority(nHeight);
-        CAmount dummy;
-        mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy);
-        vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
-    }
-    std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
-
-    CTxMemPool::txiter iter;
-    while (!vecPriority.empty() && !blockFinished) { // add a tx from priority queue to fill the blockprioritysize
-        iter = vecPriority.front().second;
-        actualPriority = vecPriority.front().first;
-        std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
-        vecPriority.pop_back();
-
-        // If tx already in block, skip
-        if (inBlock.count(iter)) {
-            assert(false); // shouldn't happen for priority txs
-            continue;
-        }
-
-        // If tx is dependent on other mempool txs which haven't yet been included
-        // then put it in the waitSet
-        if (isStillDependent(iter)) {
-            waitPriMap.insert(std::make_pair(iter, actualPriority));
-            continue;
-        }
-
-        // If this tx fits in the block add it, otherwise keep looping
-        if (TestForBlock(iter)) {
-            AddToBlock(iter);
-
-            // If now that this txs is added we've surpassed our desired priority size
-            // or have dropped below the AllowFreeThreshold, then we're done adding priority txs
-            if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) {
-                return;
-            }
-
-            // This tx was successfully added, so
-            // add transactions that depend on this one to the priority queue to try again
-            for (CTxMemPool::txiter child : mempool.GetMemPoolChildren(iter))
-            {
-                waitPriIter wpiter = waitPriMap.find(child);
-                if (wpiter != waitPriMap.end()) {
-                    vecPriority.push_back(TxCoinAgePriority(wpiter->second,child));
-                    std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
-                    waitPriMap.erase(wpiter);
-                }
-            }
-        }
-    }
-}
-
 //////////////////////////////////////////////////////////////////////////////
 //
 // Internal miner
diff --git a/src/miner.h b/src/miner.h
index 81d99ba2e93..256e532b505 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -148,8 +148,6 @@ class BlockAssembler
     // Methods for how to add transactions to a block.
     /** Add transactions based on modified feerate */
     void addScoreTxs();
-    /** Add transactions based on tx "priority" */
-    void addPriorityTxs();
 
     // helper function for addScoreTxs and addPriorityTxs
     /** Test if tx will still "fit" in the block */
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 4b29085292c..49fd4c293e9 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -12,10 +12,9 @@
 #include "util/system.h"
 
 void TxConfirmStats::Initialize(std::vector<double>& defaultBuckets,
-                                unsigned int maxConfirms, double _decay, std::string _dataTypeString)
+                                unsigned int maxConfirms, double _decay)
 {
     decay = _decay;
-    dataTypeString = _dataTypeString;
 
     buckets.insert(buckets.end(), defaultBuckets.begin(), defaultBuckets.end());
     buckets.push_back(std::numeric_limits<double>::infinity());
@@ -95,10 +94,10 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
 
     int maxbucketindex = buckets.size() - 1;
 
-    // requireGreater means we are looking for the lowest fee/priority such that all higher
-    // values pass, so we start at maxbucketindex (highest fee) and look at succesively
+    // requireGreater means we are looking for the lowest feerate such that all higher
+    // values pass, so we start at maxbucketindex (highest feerate) and look at successively
     // smaller buckets until we reach failure.  Otherwise, we are looking for the highest
-    // fee/priority such that all lower values fail, and we go in the opposite direction.
+    // feerate such that all lower values fail, and we go in the opposite direction.
     unsigned int startbucket = requireGreater ? maxbucketindex : 0;
     int step = requireGreater ? -1 : 1;
 
@@ -115,7 +114,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
     bool foundAnswer = false;
     unsigned int bins = unconfTxs.size();
 
-    // Start counting from highest(default) or lowest fee/pri transactions
+    // Start counting from highest(default) or lowest feerate transactions
     for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
         curFarBucket = bucket;
         nConf += confAvg[confTarget - 1][bucket];
@@ -153,8 +152,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
     double median = -1;
     double txSum = 0;
 
-    // Calculate the "average" fee of the best bucket range that met success conditions
-    // Find the bucket with the median transaction and then report the average fee from that bucket
+    // Calculate the "average" feerate of the best bucket range that met success conditions
+    // Find the bucket with the median transaction and then report the average feerate from that bucket
     // This is a compromise between finding the median which we can't since we don't save all tx's
     // and reporting the average which is less accurate
     unsigned int minBucket = bestNearBucket < bestFarBucket ? bestNearBucket : bestFarBucket;
@@ -174,8 +173,8 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
         }
     }
 
-    LogPrint("estimatefee", "%3d: For conf success %s %4.2f need %s %s: %12.5g from buckets %8g - %8g  Cur Bucket stats %6.2f%%  %8.1f/(%.1f+%d mempool)\n",
-             confTarget, requireGreater ? ">" : "<", successBreakPoint, dataTypeString,
+    LogPrint("estimatefee", "%3d: For conf success %s %4.2f need feerate %s: %12.5g from buckets %8g - %8g  Cur Bucket stats %6.2f%%  %8.1f/(%.1f+%d mempool)\n",
+             confTarget, requireGreater ? ">" : "<", successBreakPoint,
              requireGreater ? ">" : "<", median, buckets[minBucket], buckets[maxBucket],
              100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
 
@@ -208,10 +207,10 @@ void TxConfirmStats::Read(CAutoFile& filein)
     filein >> fileBuckets;
     numBuckets = fileBuckets.size();
     if (numBuckets <= 1 || numBuckets > 1000)
-        throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 fee/pri buckets");
+        throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
     filein >> fileAvg;
     if (fileAvg.size() != numBuckets)
-        throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri average bucket count");
+        throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
     filein >> fileTxCtAvg;
     if (fileTxCtAvg.size() != numBuckets)
         throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
@@ -221,9 +220,9 @@ void TxConfirmStats::Read(CAutoFile& filein)
         throw std::runtime_error("Corrupt estimates file.  Must maintain estimates for between 1 and 1008 (one week) confirms");
     for (unsigned int i = 0; i < maxConfirms; i++) {
         if (fileConfAvg[i].size() != numBuckets)
-            throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri conf average bucket count");
+            throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
     }
-    // Now that we've processed the entire fee estimate data file and not
+    // Now that we've processed the entire feerate estimate data file and not
     // thrown any errors, we can copy it to our data structures
     decay = fileDecay;
     buckets = fileBuckets;
@@ -250,8 +249,8 @@ void TxConfirmStats::Read(CAutoFile& filein)
     for (unsigned int i = 0; i < buckets.size(); i++)
         bucketMap[buckets[i]] = i;
 
-    LogPrint("estimatefee", "Reading estimates: %u %s buckets counting confirms up to %u blocks\n",
-             numBuckets, dataTypeString, maxConfirms);
+    LogPrint("estimatefee", "Reading estimates: %u buckets counting confirms up to %u blocks\n",
+             numBuckets, maxConfirms);
 }
 
 unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
@@ -259,7 +258,6 @@ unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
     unsigned int bucketindex = FindBucketIndex(val);
     unsigned int blockIndex = nBlockHeight % unconfTxs.size();
     unconfTxs[blockIndex][bucketindex]++;
-    LogPrint("estimatefee", "adding to %s", dataTypeString);
     return bucketindex;
 }
 
@@ -299,12 +297,10 @@ void CBlockPolicyEstimator::removeTx(uint256 hash)
                  hash.ToString().c_str());
         return;
     }
-    TxConfirmStats *stats = pos->second.stats;
     unsigned int entryHeight = pos->second.blockHeight;
     unsigned int bucketIndex = pos->second.bucketIndex;
 
-    if (stats != NULL)
-        stats->removeTx(entryHeight, nBestSeenHeight, bucketIndex);
+    feeStats.removeTx(entryHeight, nBestSeenHeight, bucketIndex);
     mapMemPoolTxs.erase(hash);
 }
 
@@ -316,47 +312,17 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
     for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
         vfeelist.push_back(bucketBoundary);
     }
-    feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "FeeRate");
-
-    minTrackedPriority = AllowFreeThreshold() < MIN_PRIORITY ? MIN_PRIORITY : AllowFreeThreshold();
-    std::vector<double> vprilist;
-    for (double bucketBoundary = minTrackedPriority; bucketBoundary <= MAX_PRIORITY; bucketBoundary *= PRI_SPACING) {
-        vprilist.push_back(bucketBoundary);
-    }
-    priStats.Initialize(vprilist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "Priority");
-
-    feeUnlikely = CFeeRate(0);
-    feeLikely = CFeeRate(INF_FEERATE);
-    priUnlikely = 0;
-    priLikely = INF_PRIORITY;
-}
-
-bool CBlockPolicyEstimator::isFeeDataPoint(const CFeeRate &fee, double pri)
-{
-    if ((pri < minTrackedPriority && fee >= minTrackedFee) ||
-        (pri < priUnlikely && fee > feeLikely)) {
-        return true;
-    }
-    return false;
-}
-
-bool CBlockPolicyEstimator::isPriDataPoint(const CFeeRate &fee, double pri)
-{
-    if ((fee < minTrackedFee && pri >= minTrackedPriority) ||
-        (fee < feeUnlikely && pri > priLikely)) {
-        return true;
-    }
-    return false;
+    feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
 }
 
 void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate)
 {
     unsigned int txHeight = entry.GetHeight();
     uint256 hash = entry.GetTx().GetHash();
-    if (mapMemPoolTxs[hash].stats != NULL) {
+    if (mapMemPoolTxs.count(hash)) {
         LogPrint("estimatefee", "Blockpolicy error mempool tx %s already being tracked\n",
                  hash.ToString().c_str());
-	return;
+        return;
     }
 
     if (txHeight < nBestSeenHeight) {
@@ -377,30 +343,11 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
         return;
     }
 
-    // Fees are stored and reported as BTC-per-kb:
+    // Feerates are stored and reported as zatoshis per 1000 bytes:
     CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
 
-    // Want the priority of the tx at confirmation. However we don't know
-    // what that will be and its too hard to continue updating it
-    // so use starting priority as a proxy
-    double curPri = entry.GetPriority(txHeight);
     mapMemPoolTxs[hash].blockHeight = txHeight;
-
-    LogPrint("estimatefee", "Blockpolicy mempool tx %s ", hash.ToString().substr(0,10));
-    // Record this as a priority estimate
-    if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
-        mapMemPoolTxs[hash].stats = &priStats;
-        mapMemPoolTxs[hash].bucketIndex =  priStats.NewTx(txHeight, curPri);
-    }
-    // Record this as a fee estimate
-    else if (isFeeDataPoint(feeRate, curPri)) {
-        mapMemPoolTxs[hash].stats = &feeStats;
-        mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
-    }
-    else {
-        LogPrint("estimatefee", "not adding");
-    }
-    LogPrint("estimatefee", "\n");
+    mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
 }
 
 void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
@@ -423,21 +370,10 @@ void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxM
         return;
     }
 
-    // Fees are stored and reported as BTC-per-kb:
+    // Feerates are stored and reported as zatoshis per 1000 bytes:
     CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
 
-    // Want the priority of the tx at confirmation.  The priority when it
-    // entered the mempool could easily be very small and change quickly
-    double curPri = entry.GetPriority(nBlockHeight);
-
-    // Record this as a priority estimate
-    if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
-        priStats.Record(blocksToConfirm, curPri);
-    }
-    // Record this as a fee estimate
-    else if (isFeeDataPoint(feeRate, curPri)) {
-        feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
-    }
+    feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
 }
 
 void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
@@ -458,41 +394,15 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
     if (!fCurrentEstimate)
         return;
 
-    // Update the dynamic cutoffs
-    // a fee/priority is "likely" the reason your tx was included in a block if >85% of such tx's
-    // were confirmed in 2 blocks and is "unlikely" if <50% were confirmed in 10 blocks
-    LogPrint("estimatefee", "Blockpolicy recalculating dynamic cutoffs:\n");
-    priLikely = priStats.EstimateMedianVal(2, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBlockHeight);
-    if (priLikely == -1)
-        priLikely = INF_PRIORITY;
-
-    double feeLikelyEst = feeStats.EstimateMedianVal(2, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBlockHeight);
-    if (feeLikelyEst == -1)
-        feeLikely = CFeeRate(INF_FEERATE);
-    else
-        feeLikely = CFeeRate(feeLikelyEst);
-
-    priUnlikely = priStats.EstimateMedianVal(10, SUFFICIENT_PRITXS, UNLIKELY_PCT, false, nBlockHeight);
-    if (priUnlikely == -1)
-        priUnlikely = 0;
-
-    double feeUnlikelyEst = feeStats.EstimateMedianVal(10, SUFFICIENT_FEETXS, UNLIKELY_PCT, false, nBlockHeight);
-    if (feeUnlikelyEst == -1)
-        feeUnlikely = CFeeRate(0);
-    else
-        feeUnlikely = CFeeRate(feeUnlikelyEst);
-
-    // Clear the current block states
+    // Clear the current block state
     feeStats.ClearCurrent(nBlockHeight);
-    priStats.ClearCurrent(nBlockHeight);
 
     // Repopulate the current block states
     for (unsigned int i = 0; i < entries.size(); i++)
         processBlockTx(nBlockHeight, entries[i]);
 
-    // Update all exponential averages with the current block states
+    // Update all exponential averages with the current block state
     feeStats.UpdateMovingAverages();
-    priStats.UpdateMovingAverages();
 
     LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n",
              entries.size(), mapMemPoolTxs.size());
@@ -512,27 +422,20 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
     return CFeeRate(median);
 }
 
-double CBlockPolicyEstimator::estimatePriority(int confTarget)
-{
-    // Return failure if trying to analyze a target we're not tracking
-    if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms())
-        return -1;
-
-    return priStats.EstimateMedianVal(confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
-}
-
 void CBlockPolicyEstimator::Write(CAutoFile& fileout)
 {
     fileout << nBestSeenHeight;
     feeStats.Write(fileout);
-    priStats.Write(fileout);
 }
 
-void CBlockPolicyEstimator::Read(CAutoFile& filein)
+void CBlockPolicyEstimator::Read(CAutoFile& filein, int nFileVersion)
 {
     int nFileBestSeenHeight;
     filein >> nFileBestSeenHeight;
     feeStats.Read(filein);
-    priStats.Read(filein);
     nBestSeenHeight = nFileBestSeenHeight;
+    if (nFileVersion < FEE_ESTIMATES_WITHOUT_PRIORITY_VERSION) {
+        TxConfirmStats priStats;
+        priStats.Read(filein);
+    }
 }
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 383d629d1d3..1618ec4c82f 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -19,51 +19,42 @@ class CFeeRate;
 class CTxMemPoolEntry;
 
 /** \class CBlockPolicyEstimator
- * The BlockPolicyEstimator is used for estimating the fee or priority needed
+ * The BlockPolicyEstimator is used for estimating the feerate needed
  * for a transaction to be included in a block within a certain number of
  * blocks.
  *
  * At a high level the algorithm works by grouping transactions into buckets
- * based on having similar priorities or fees and then tracking how long it
+ * based on having similar feerates and then tracking how long it
  * takes transactions in the various buckets to be mined.  It operates under
- * the assumption that in general transactions of higher fee/priority will be
- * included in blocks before transactions of lower fee/priority.   So for
- * example if you wanted to know what fee you should put on a transaction to
+ * the assumption that in general transactions of higher feerate will be
+ * included in blocks before transactions of lower feerate.   So for
+ * example if you wanted to know what feerate you should put on a transaction to
  * be included in a block within the next 5 blocks, you would start by looking
- * at the bucket with the highest fee transactions and verifying that a
+ * at the bucket with the highest feerate transactions and verifying that a
  * sufficiently high percentage of them were confirmed within 5 blocks and
- * then you would look at the next highest fee bucket, and so on, stopping at
- * the last bucket to pass the test.   The average fee of transactions in this
- * bucket will give you an indication of the lowest fee you can put on a
+ * then you would look at the next highest feerate bucket, and so on, stopping at
+ * the last bucket to pass the test.   The average feerate of transactions in this
+ * bucket will give you an indication of the lowest feerate you can put on a
  * transaction and still have a sufficiently high chance of being confirmed
  * within your desired 5 blocks.
  *
- * When a transaction enters the mempool or is included within a block we
- * decide whether it can be used as a data point for fee estimation, priority
- * estimation or neither.  If the value of exactly one of those properties was
- * below the required minimum it can be used to estimate the other.  In
- * addition, if a priori our estimation code would indicate that the
- * transaction would be much more quickly included in a block because of one
- * of the properties compared to the other, we can also decide to use it as
- * an estimate for that property.
- *
- * Here is a brief description of the implementation for fee estimation.
- * When a transaction that counts for fee estimation enters the mempool, we
+ * Here is a brief description of the implementation:
+ * When a transaction enters the mempool, we
  * track the height of the block chain at entry.  Whenever a block comes in,
- * we count the number of transactions in each bucket and the total amount of fee
+ * we count the number of transactions in each bucket and the total amount of feerate
  * paid in each bucket. Then we calculate how many blocks Y it took each
  * transaction to be mined and we track an array of counters in each bucket
  * for how long it to took transactions to get confirmed from 1 to a max of 25
  * and we increment all the counters from Y up to 25. This is because for any
  * number Z>=Y the transaction was successfully mined within Z blocks.  We
  * want to save a history of this information, so at any time we have a
- * counter of the total number of transactions that happened in a given fee
+ * counter of the total number of transactions that happened in a given feerate
  * bucket and the total number that were confirmed in each number 1-25 blocks
  * or less for any bucket.   We save this history by keeping an exponentially
  * decaying moving average of each one of these stats.  Furthermore we also
  * keep track of the number unmined (in mempool) transactions in each bucket
  * and for how many blocks they have been outstanding and use that to increase
- * the number of transactions we've seen in that fee bucket when calculating
+ * the number of transactions we've seen in that feerate bucket when calculating
  * an estimate for any number of confirmations below the number of blocks
  * they've been outstanding.
  */
@@ -72,12 +63,11 @@ class CTxMemPoolEntry;
 static const double DEFAULT_DECAY = .998;
 
 /**
- * We will instantiate two instances of this class, one to track transactions
- * that were included in a block due to fee, and one for txs included due to
- * priority.  We will lump transactions into a bucket according to their approximate
- * fee or priority and then track how long it took for those txs to be included
+ * We will instantiate an instance of this class to track transactions that were
+ * included in a block. We will lump transactions into a bucket according to their
+ * approximate feerate and then track how long it took for those txs to be included
  * in a block. There is always a bucket into which any given double value
- * (representing a fee or priority) falls.
+ * (representing a fee) falls.
  *
  * The tracking of unconfirmed (mempool) transactions is completely independent of the
  * historical tracking of transactions that have been confirmed in a block.
@@ -85,7 +75,7 @@ static const double DEFAULT_DECAY = .998;
 class TxConfirmStats
 {
 private:
-    //Define the buckets we will group transactions into (both fee buckets and priority buckets)
+    //Define the buckets we will group transactions into
     std::vector<double> buckets;              // The upper-bound of the range for the bucket (inclusive)
     std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
 
@@ -102,16 +92,15 @@ class TxConfirmStats
     // and calculate the totals for the current block to update the moving averages
     std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
 
-    // Sum the total priority/fee of all txs in each bucket
+    // Sum the total feerate of all tx's in each bucket
     // Track the historical moving average of this total over blocks
     std::vector<double> avg;
     // and calculate the total for the current block to update the moving average
     std::vector<double> curBlockVal;
 
     // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
-    // Combine the total value with the tx counts to calculate the avg fee/priority per bucket
+    // Combine the total value with the tx counts to calculate the avg feerate per bucket
 
-    std::string dataTypeString;
     double decay = DEFAULT_DECAY;
 
     // Mempool counts of outstanding transactions
@@ -133,9 +122,8 @@ class TxConfirmStats
      * @param defaultBuckets contains the upper limits for the bucket boundaries
      * @param maxConfirms max number of confirms to track
      * @param decay how much to decay the historical moving average per block
-     * @param dataTypeString for logging purposes
      */
-    void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay, std::string dataTypeString);
+    void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay);
 
     /** Clear the state of the curBlock variables to start counting for the new block */
     void ClearCurrent(unsigned int nBlockHeight);
@@ -143,7 +131,7 @@ class TxConfirmStats
     /**
      * Record a new transaction data point in the current block stats
      * @param blocksToConfirm the number of blocks it took this transaction to confirm
-     * @param val either the fee or the priority when entered of the transaction
+     * @param val the feerate of the transaction
      * @warning blocksToConfirm is 1-based and has to be >= 1
      */
     void Record(int blocksToConfirm, double val);
@@ -160,14 +148,14 @@ class TxConfirmStats
     void UpdateMovingAverages();
 
     /**
-     * Calculate a fee or priority estimate.  Find the lowest value bucket (or range of buckets
+     * Calculate a feerate estimate.  Find the lowest value bucket (or range of buckets
      * to make sure we have enough data points) whose transactions still have sufficient likelihood
      * of being confirmed within the target number of confirmations
      * @param confTarget target number of confirmations
      * @param sufficientTxVal required average number of transactions per block in a bucket range
      * @param minSuccess the success probability we require
-     * @param requireGreater return the lowest fee/pri such that all higher values pass minSuccess OR
-     *        return the highest fee/pri such that all lower values fail minSuccess
+     * @param requireGreater return the lowest feerate such that all higher values pass minSuccess OR
+     *        return the highest feerate such that all lower values fail minSuccess
      * @param nBlockHeight the current block height
      */
     double EstimateMedianVal(int confTarget, double sufficientTxVal,
@@ -191,35 +179,26 @@ class TxConfirmStats
 /** Track confirm delays up to 25 blocks, can't estimate beyond that */
 static const unsigned int MAX_BLOCK_CONFIRMS = 25;
 
-/** Require greater than 85% of X fee transactions to be confirmed within Y blocks for X to be big enough */
+/** Require greater than 85% of X feerate transactions to be confirmed within Y blocks for X to be big enough */
 static const double MIN_SUCCESS_PCT = .85;
 static const double UNLIKELY_PCT = .5;
 
-/** Require an avg of 1 tx in the combined fee bucket per block to have stat significance */
+/** Require an avg of 1 tx in the combined feerate bucket per block to have stat significance */
 static const double SUFFICIENT_FEETXS = 1;
 
-/** Require only an avg of 1 tx every 5 blocks in the combined pri bucket (way less pri txs) */
-static const double SUFFICIENT_PRITXS = .2;
-
-// Minimum and Maximum values for tracking fees and priorities
+// Minimum and Maximum values for tracking feerates
 static const double MIN_FEERATE = 10;
 static const double MAX_FEERATE = 1e7;
 static const double INF_FEERATE = MAX_MONEY;
-static const double MIN_PRIORITY = 10;
-static const double MAX_PRIORITY = 1e16;
-static const double INF_PRIORITY = 1e9 * MAX_MONEY;
 
-// We have to lump transactions into buckets based on fee or priority, but we want to be able
-// to give accurate estimates over a large range of potential fees and priorities
+// We have to lump transactions into buckets based on feerate, but we want to be able
+// to give accurate estimates over a large range of potential feerates
 // Therefore it makes sense to exponentially space the buckets
 /** Spacing of FeeRate buckets */
 static const double FEE_SPACING = 1.1;
 
-/** Spacing of Priority buckets */
-static const double PRI_SPACING = 2;
-
 /**
- *  We want to be able to estimate fees or priorities that are needed on txs to be included in
+ *  We want to be able to estimate feerates that are needed on tx's to be included in
  * a certain number of blocks.  Every time a block is added to the best chain, this class records
  * stats on the transactions included in that block
  */
@@ -242,44 +221,29 @@ class CBlockPolicyEstimator
     /** Remove a transaction from the mempool tracking stats*/
     void removeTx(uint256 hash);
 
-    /** Is this transaction likely included in a block because of its fee?*/
-    bool isFeeDataPoint(const CFeeRate &fee, double pri);
-
-    /** Is this transaction likely included in a block because of its priority?*/
-    bool isPriDataPoint(const CFeeRate &fee, double pri);
-
-    /** Return a fee estimate */
+    /** Return a feerate estimate */
     CFeeRate estimateFee(int confTarget);
 
-    /** Return a priority estimate */
-    double estimatePriority(int confTarget);
-
     /** Write estimation data to a file */
     void Write(CAutoFile& fileout);
 
     /** Read estimation data from a file */
-    void Read(CAutoFile& filein);
+    void Read(CAutoFile& filein, int nFileVersion);
 
 private:
     CFeeRate minTrackedFee;    //!< Passed to constructor to avoid dependency on main
-    double minTrackedPriority; //!< Set to AllowFreeThreshold
     unsigned int nBestSeenHeight;
     struct TxStatsInfo
     {
-        TxConfirmStats *stats;
         unsigned int blockHeight;
         unsigned int bucketIndex;
-        TxStatsInfo() : stats(NULL), blockHeight(0), bucketIndex(0) {}
+        TxStatsInfo() : blockHeight(0), bucketIndex(0) {}
     };
 
     // map of txids to information about that transaction
     std::map<uint256, TxStatsInfo> mapMemPoolTxs;
 
     /** Classes to track historical data on transaction confirmations */
-    TxConfirmStats feeStats, priStats;
-
-    /** Breakpoints to help determine whether a transaction was confirmed by priority or Fee */
-    CFeeRate feeLikely, feeUnlikely;
-    double priLikely, priUnlikely;
+    TxConfirmStats feeStats;
 };
 #endif // BITCOIN_POLICY_FEES_H
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 967801e787e..e44f9ac23e8 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -119,7 +119,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const CChainParam
         else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
             reason = "bare-multisig";
             return false;
-        } else if (txout.IsDust(::minRelayTxFee)) {
+        } else if (txout.IsDust()) {
             reason = "dust";
             return false;
         }
diff --git a/src/policy/policy.h b/src/policy/policy.h
index eb635b7c8ff..a2feb15b163 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -18,8 +18,7 @@ class CCoinsViewCache;
 /** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
 static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SIZE;
 static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
-/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
-static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = DEFAULT_BLOCK_MAX_SIZE / 2;
+
 /** Maximum number of signature check operations in an IsStandard() P2SH script */
 static const unsigned int MAX_P2SH_SIGOPS = 15;
 /** The maximum number of sigops we're willing to relay/mine in a single tx */
@@ -42,9 +41,56 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
 /** For convenience, standard but not mandatory verify flags. */
 static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
 
+/**
+ * The rate used to calculate the dust threshold, in zatoshis per 1000 bytes.
+ * This will effectively be multiplied by 3 (it is necessary to express it this
+ * way to ensure that rounding will be calculated the same as before #6542).
+ *
+ * Bitcoin Core added the concept of "dust" in bitcoin/bitcoin#2577. At that
+ * point the dust threshold rate was tied to three times the minRelayTxFee rate,
+ * with the motivation that if you'd pay more than a third of the minimum relay
+ * fee to spend something, it should be considered dust. This was implemented
+ * as a standard rule rejecting dust outputs.
+ *
+ * This motivation will not apply after ZIP 317 block construction is implemented:
+ * at that point the ZIP 317 marginal fee will be 5000 zats per logical action,
+ * but the dust threshold rate will still be 300 zats per 1000 bytes. Those costs
+ * would only coincide if the marginal size per logical action were
+ * 5000/300 * 1000 ~= 16667 bytes, and in practice the marginal size for any
+ * kind of input is much smaller than that.
+ *
+ * However, to avoid interoperability problems (older wallets creating transactions
+ * that newer nodes will reject because they view the outputs as dust), we will have
+ * to coordinate any increase in the dust threshold carefully.
+ *
+ * More history: in Zcash the minRelayTxFee rate was 5000 zats/1000 bytes at launch,
+ * changed to 1000 zats/1000 bytes in zcashd v1.0.3 and to 100 zats/1000 bytes in
+ * zcashd v1.0.7-1 (#2141). The relaying problem for shielded transactions (#1969)
+ * that prompted the latter change was fixed more thoroughly by the addition of
+ * `CFeeRate::GetFeeForRelay` in #4916, ensuring that a transaction paying
+ * `DEFAULT_FEE` can always be relayed. At the same time the default fee was set
+ * to 1000 zats, per ZIP 313.
+ *
+ * #6542 changed relaying policy to be more strict about enforcing minRelayTxFee.
+ * It also allowed `-minrelaytxfee=0`, which we are using to avoid some test
+ * breakage. But if the dust threshold rate were still set to three times the
+ * minRelayTxFee rate, then setting `-minrelaytxfee=0` would have the side effect
+ * of setting the dust threshold to zero, which is not intended.
+ *
+ * Bitcoin Core took a different approach to disentangling the dust threshold from
+ * the relay threshold, adding a `-dustrelayfee` option (bitcoin/bitcoin#9380).
+ * We don't want to do that because it is likely that we will change the dust policy
+ * again, and adding a user-visible config option might conflict with that. Also,
+ * it isn't a good idea for the dust threshold rate to be configurable per node;
+ * it's a standard rule parameter and should only be changed with network-wide
+ * coordination (if it is increased then wallets have to change before nodes, and
+ * vice versa if it is decreased). So for now we set it to a constant that matches
+ * the behaviour before #6542.
+ */
+static const unsigned int ONE_THIRD_DUST_THRESHOLD_RATE = 100;
+
 // Sanity check the magic numbers when we change them
 static_assert(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
-static_assert(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE);
 
 bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
     /**
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 5e7e9d17cf7..2b3b0a835ac 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -5,6 +5,7 @@
 // file COPYING or https://www.opensource.org/licenses/mit-license.php .
 
 #include "primitives/transaction.h"
+#include "policy/policy.h"
 
 #include "hash.h"
 #include "tinyformat.h"
@@ -123,6 +124,22 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
     scriptPubKey = scriptPubKeyIn;
 }
 
+CAmount CTxOut::GetDustThreshold() const
+{
+    // See the comment on ONE_THIRD_DUST_THRESHOLD_RATE in policy.h.
+    static const CFeeRate oneThirdDustThresholdRate {ONE_THIRD_DUST_THRESHOLD_RATE};
+
+    if (scriptPubKey.IsUnspendable())
+        return 0;
+
+    // A typical spendable txout is 34 bytes, and will need a txin of at
+    // least 148 bytes to spend. With ONE_THIRD_DUST_THRESHOLD_RATE == 100,
+    // the dust threshold for such a txout would be
+    // 3*floor(100*(34 + 148)/1000) zats = 54 zats.
+    size_t nSize = GetSerializeSize(*this, SER_DISK, 0) + 148u;
+    return 3*oneThirdDustThresholdRate.GetFee(nSize);
+}
+
 uint256 CTxOut::GetHash() const
 {
     return SerializeHash(*this);
@@ -360,32 +377,6 @@ CAmount CTransaction::GetShieldedValueIn() const
     return nValue;
 }
 
-double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
-{
-    nTxSize = CalculateModifiedSize(nTxSize);
-    if (nTxSize == 0) return 0.0;
-
-    return dPriorityInputs / nTxSize;
-}
-
-unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
-{
-    // In order to avoid disincentivizing cleaning up the UTXO set we don't count
-    // the constant overhead for each txin and up to 110 bytes of scriptSig (which
-    // is enough to cover a compressed pubkey p2sh redemption) for priority.
-    // Providing any more cleanup incentive than making additional inputs free would
-    // risk encouraging people to create junk outputs to redeem later.
-    if (nTxSize == 0)
-        nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
-    for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
-    {
-        unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
-        if (nTxSize > offset)
-            nTxSize -= offset;
-    }
-    return nTxSize;
-}
-
 CAmount CTransaction::GetConventionalFee() const {
     return CalculateConventionalFee(GetLogicalActionCount());
 }
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 5e5dc71b15f..0b9b01ffbf9 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -625,26 +625,11 @@ class CTxOut
 
     uint256 GetHash() const;
 
-    CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
-    {
-        // "Dust" is defined in terms of CTransaction::minRelayTxFee,
-        // which has units satoshis-per-kilobyte.
-        // If you'd pay more than 1/3 in fees
-        // to spend something, then we consider it dust.
-        // A typical spendable txout is 34 bytes big, and will
-        // need a CTxIn of at least 148 bytes to spend:
-        // so dust is a spendable txout less than
-        // 54*minRelayTxFee/1000 (in satoshis)
-        if (scriptPubKey.IsUnspendable())
-            return 0;
-
-        size_t nSize = GetSerializeSize(*this, SER_DISK, 0) + 148u;
-        return 3*minRelayTxFee.GetFee(nSize);
-    }
+    CAmount GetDustThreshold() const;
 
-    bool IsDust(const CFeeRate &minRelayTxFee) const
+    bool IsDust() const
     {
-        return (nValue < GetDustThreshold(minRelayTxFee));
+        return nValue < GetDustThreshold();
     }
 
     friend bool operator==(const CTxOut& a, const CTxOut& b)
@@ -971,12 +956,6 @@ class CTransaction
     // Return sum of (positive valueBalanceSapling or zero) and JoinSplit vpub_new
     CAmount GetShieldedValueIn() const;
 
-    // Compute priority, given priority of inputs and (optionally) tx size
-    double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
-
-    // Compute modified tx size for priority calculation (optionally given tx size)
-    unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
-
     // Return the conventional fee for this transaction calculated according to
     // <https://zips.z.cash/zip-0317#fee-calculation>.
     CAmount GetConventionalFee() const;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index ed8aa74a5a4..f9b91e53c15 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -349,11 +349,9 @@ UniValue mempoolToJSON(bool fVerbose = false)
             info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
             info.pushKV("time", e.GetTime());
             info.pushKV("height", (int)e.GetHeight());
-            info.pushKV("startingpriority", e.GetPriority(e.GetHeight()));
-            info.pushKV("currentpriority", e.GetPriority(chainActive.Height()));
             info.pushKV("descendantcount", e.GetCountWithDescendants());
             info.pushKV("descendantsize", e.GetSizeWithDescendants());
-            info.pushKV("descendantfees", e.GetFeesWithDescendants());
+            info.pushKV("descendantfees", e.GetModFeesWithDescendants());
             const CTransaction& tx = e.GetTx();
             set<string> setDepends;
             for (const CTxIn& txin : tx.vin)
@@ -407,11 +405,9 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
             "    \"modifiedfee\" : n,      (numeric) transaction fee with fee deltas used for mining priority\n"
             "    \"time\" : n,             (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
             "    \"height\" : n,           (numeric) block height when transaction entered pool\n"
-            "    \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
-            "    \"currentpriority\" : n,  (numeric) transaction priority now\n"
             "    \"descendantcount\" : n,  (numeric) number of in-mempool descendant transactions (including this one)\n"
             "    \"descendantsize\" : n,   (numeric) size of in-mempool descendants (including this one)\n"
-            "    \"descendantfees\" : n,   (numeric) fees of in-mempool descendants (including this one)\n"
+            "    \"descendantfees\" : n,   (numeric) modified fees (see \"modifiedfee\" above) of in-mempool descendants (including this one)\n"
             "    \"depends\" : [           (array) unconfirmed transactions used as inputs for this transaction\n"
             "        \"transactionid\",    (string) parent transaction id\n"
             "       ... ]\n"
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 3683d3dab80..43edc29f2b0 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -58,7 +58,6 @@ static const CRPCConvertTable rpcCvtTable =
     //     preserve that here.
     { "submitblock",                 {{s}, {s}} },
     { "estimatefee",                 {{o}, {}} },
-    { "estimatepriority",            {{o}, {}} },
     { "getblocksubsidy",             {{o}, {}} },
     // misc
     { "getinfo",                     {{}, {}} },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 23d9fe8a295..5209b9281d0 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -372,20 +372,18 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
 }
 
 
-// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
+// NOTE: Unlike wallet RPCs (which use ZEC values), mining RPCs follow GBT (BIP 22) in using zatoshi amounts.
 UniValue prioritisetransaction(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() != 3)
-        throw runtime_error(
+        throw std::runtime_error(
             "prioritisetransaction <txid> <priority delta> <fee delta>\n"
             "Accepts the transaction into mined blocks at a higher (or lower) priority\n"
             "\nArguments:\n"
             "1. \"txid\"       (string, required) The transaction id.\n"
-            "2. priority delta (numeric, required) The priority to add or subtract.\n"
-            "                  The transaction selection algorithm considers the tx as it would have a higher priority.\n"
-            "                  (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n"
-            "3. fee delta      (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
-            "                  The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
+            "2. priority_delta (numeric, optional) Fee-independent priority adjustment. Not supported, so must be zero or null.\n"
+            "3. fee_delta      (numeric, required) The fee value (in " + MINOR_CURRENCY_UNIT + ") to add (or subtract, if negative).\n"
+            "                  The modified fee is not actually paid, only the algorithm for selecting transactions into a block\n"
             "                  considers the transaction as it would have paid a higher (or lower) fee.\n"
             "\nResult\n"
             "true              (boolean) Returns true\n"
@@ -399,7 +397,11 @@ UniValue prioritisetransaction(const UniValue& params, bool fHelp)
     uint256 hash = ParseHashStr(params[0].get_str(), "txid");
     CAmount nAmount = params[2].get_int64();
 
-    mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
+    if (!(params[1].isNull() || params[1].get_real() == 0)) {
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is not supported, and adjustment thereof must be zero.");
+    }
+
+    mempool.PrioritiseTransaction(hash, params[0].get_str(), nAmount);
     return true;
 }
 
@@ -474,7 +476,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
             "             n                       (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
             "             ,...\n"
             "         ],\n"
-            "         \"fee\": n,                   (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+            "         \"fee\": n,                   (numeric) difference in value between transaction inputs and outputs (in " + MINOR_CURRENCY_UNIT + "); for coinbase transactions, this is a negative Number of the total collected block fees (i.e., not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
             "         \"sigops\" : n,               (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n"
             "         \"required\" : true|false     (boolean) if provided and true, this transaction must be in the final block\n"
             "      }\n"
@@ -483,7 +485,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
 //            "  \"coinbaseaux\" : {                  (json object) data that should be included in the coinbase's scriptSig content\n"
 //            "      \"flags\" : \"flags\"            (string) \n"
 //            "  },\n"
-//            "  \"coinbasevalue\" : n,               (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+//            "  \"coinbasevalue\" : n,               (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in " + MINOR_CURRENCY_UNIT + ")\n"
             "  \"coinbasetxn\" : { ... },           (json object) information for coinbase transaction\n"
             "  \"target\" : \"xxxx\",                 (string) The hash target\n"
             "  \"longpollid\" : \"str\",              (string) an id to include with a request to longpoll on an update to this template\n"
@@ -940,34 +942,6 @@ UniValue estimatefee(const UniValue& params, bool fHelp)
     return ValueFromAmount(feeRate.GetFeePerK());
 }
 
-UniValue estimatepriority(const UniValue& params, bool fHelp)
-{
-    if (fHelp || params.size() != 1)
-        throw runtime_error(
-            "estimatepriority nblocks\n"
-            "\nEstimates the approximate priority\n"
-            "a zero-fee transaction needs to begin confirmation\n"
-            "within nblocks blocks.\n"
-            "\nArguments:\n"
-            "1. nblocks     (numeric)\n"
-            "\nResult:\n"
-            "n :    (numeric) estimated priority\n"
-            "\n"
-            "-1.0 is returned if not enough transactions and\n"
-            "blocks have been observed to make an estimate.\n"
-            "\nExample:\n"
-            + HelpExampleCli("estimatepriority", "6")
-            );
-
-    RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
-
-    int nBlocks = params[0].get_int();
-    if (nBlocks < 1)
-        nBlocks = 1;
-
-    return mempool.estimatePriority(nBlocks);
-}
-
 UniValue getblocksubsidy(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() > 1)
@@ -1074,7 +1048,6 @@ static const CRPCCommand commands[] =
 #endif
 
     { "util",               "estimatefee",            &estimatefee,            true  },
-    { "util",               "estimatepriority",       &estimatepriority,       true  },
 };
 
 void RegisterMiningRPCCommands(CRPCTable &tableRPC)
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 330b60716ec..401e2ed2576 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -67,8 +67,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
             "  \"keypoololdest\": xxxxxx,    (numeric, optional) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool, if wallet functionality is enabled\n"
             "  \"keypoolsize\": xxxx,        (numeric, optional) how many new keys are pre-generated\n"
             "  \"unlocked_until\": ttt,      (numeric, optional) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked, if wallet functionality is available and the wallet is encrypted\n"
-            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
-            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
+            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee rate set in " + CURRENCY_UNIT + " per 1000 bytes\n"
+            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee rate for transactions in " + CURRENCY_UNIT + " per 1000 bytes\n"
             "  \"errors\": \"...\"           (string) message describing the latest or highest-priority error\n"
             "  \"errorstimestamp\": \"...\"  (string) timestamp associated with the latest or highest-priority error\n"
             "}\n"
@@ -661,7 +661,7 @@ UniValue getaddressmempool(const UniValue& params, bool fHelp)
             "    \"address\"  (string) The base58check encoded address\n"
             "    \"txid\"  (string) The related txid\n"
             "    \"index\"  (number) The related input or output index\n"
-            "    \"satoshis\"  (number) The difference of zatoshis\n"
+            "    \"satoshis\"  (number) The difference of " + MINOR_CURRENCY_UNIT + "\n"
             "    \"timestamp\"  (number) The time the transaction entered the mempool (seconds)\n"
             "    \"prevtxid\"  (string) The previous txid (if spending)\n"
             "    \"prevout\"  (string) The previous transaction output index (if spending)\n"
@@ -743,7 +743,7 @@ UniValue getaddressutxos(const UniValue& params, bool fHelp)
             "    \"height\"  (number) The block height\n"
             "    \"outputIndex\"  (number) The output index\n"
             "    \"script\"  (string) The script hex encoded\n"
-            "    \"satoshis\"  (number) The number of zatoshis of the output\n"
+            "    \"satoshis\"  (number) The number of " + MINOR_CURRENCY_UNIT + " of the output\n"
             "  }, ...\n"
             "]\n\n"
             "(or, if chainInfo is true):\n\n"
@@ -756,7 +756,7 @@ UniValue getaddressutxos(const UniValue& params, bool fHelp)
             "        \"height\"      (number)  The block height\n"
             "        \"outputIndex\" (number)  The output index\n"
             "        \"script\"      (string)  The script hex encoded\n"
-            "        \"satoshis\"    (number)  The number of zatoshis of the output\n"
+            "        \"satoshis\"    (number)  The number of " + MINOR_CURRENCY_UNIT + " of the output\n"
             "      }, ...\n"
             "    ],\n"
             "  \"hash\"              (string)  The block hash\n"
@@ -899,7 +899,7 @@ UniValue getaddressdeltas(const UniValue& params, bool fHelp)
             "\nResult:\n"
             "[\n"
             "  {\n"
-            "    \"satoshis\"  (number) The difference of zatoshis\n"
+            "    \"satoshis\"  (number) The difference of " + MINOR_CURRENCY_UNIT + "\n"
             "    \"txid\"      (string) The related txid\n"
             "    \"index\"     (number) The related input or output index\n"
             "    \"height\"    (number) The block height\n"
@@ -911,7 +911,7 @@ UniValue getaddressdeltas(const UniValue& params, bool fHelp)
             "  \"deltas\":\n"
             "    [\n"
             "      {\n"
-            "        \"satoshis\"    (number) The difference of zatoshis\n"
+            "        \"satoshis\"    (number) The difference of " + MINOR_CURRENCY_UNIT + "\n"
             "        \"txid\"        (string) The related txid\n"
             "        \"index\"       (number) The related input or output index\n"
             "        \"height\"      (number) The block height\n"
@@ -1022,8 +1022,8 @@ UniValue getaddressbalance(const UniValue& params, bool fHelp)
             "\"address\"  (string) The base58check encoded address\n"
             "\nResult:\n"
             "{\n"
-            "  \"balance\"  (string) The current balance in zatoshis\n"
-            "  \"received\"  (string) The total number of zatoshis received (including change)\n"
+            "  \"balance\"  (string) The current balance in " + MINOR_CURRENCY_UNIT + "\n"
+            "  \"received\"  (string) The total number of " + MINOR_CURRENCY_UNIT + " received (including change)\n"
             "}\n"
             "\nExamples:\n"
             + HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"tmYXBYJj1K7vhejSec5osXK2QsGa5MTisUQ\"]}'")
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index f9b4ff4b543..80fd3a30730 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -516,7 +516,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
             "  }\n"
             "  ,...\n"
             "  ],\n"
-            "  \"relayfee\": x.xxxxxxxx,                (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
+            "  \"relayfee\": x.xxxxxxxx,                (numeric) minimum relay fee rate for transactions in " + CURRENCY_UNIT + " per 1000 bytes\n"
             "  \"localaddresses\": [                    (array) list of local addresses\n"
             "  {\n"
             "    \"address\": \"xxxx\",                 (string) network address\n"
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 6bcf80474b8..68386b18ff0 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1285,7 +1285,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
         // push to local node and sync with wallets
         CValidationState state;
         bool fMissingInputs;
-        if (!AcceptToMemoryPool(chainparams, mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) {
+        if (!AcceptToMemoryPool(chainparams, mempool, state, tx, true, &fMissingInputs, !fOverrideFees)) {
             if (state.IsInvalid()) {
                 throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
             } else {
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 6cb6d8ec9dc..03aafbf12e4 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -23,20 +23,19 @@
 using namespace std;
 
 CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
-                                 int64_t _nTime, double _dPriority,
-                                 unsigned int _nHeight, bool poolHasNoInputsOf,
+                                 int64_t _nTime, unsigned int _nHeight,
+                                 bool poolHasNoInputsOf,
                                  bool _spendsCoinbase, unsigned int _sigOps, uint32_t _nBranchId):
-    tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
+    tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), nHeight(_nHeight),
     hadNoDependencies(poolHasNoInputsOf),
     spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), nBranchId(_nBranchId)
 {
     nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION);
-    nModSize = _tx.CalculateModifiedSize(nTxSize);
     nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
 
     nCountWithDescendants = 1;
     nSizeWithDescendants = nTxSize;
-    nFeesWithDescendants = nFee;
+    nModFeesWithDescendants = nFee;
 
     feeDelta = 0;
 }
@@ -46,17 +45,9 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
     *this = other;
 }
 
-double
-CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
-{
-    CAmount nValueIn = tx->GetValueOut()+nFee;
-    double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize;
-    double dResult = dPriority + deltaPriority;
-    return dResult;
-}
-
 void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
 {
+    nModFeesWithDescendants += newFeeDelta - feeDelta;
     feeDelta = newFeeDelta;
 }
 
@@ -114,7 +105,7 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
     for (txiter cit : setAllDescendants) {
         if (!setExclude.count(cit->GetTx().GetHash())) {
             modifySize += cit->GetTxSize();
-            modifyFee += cit->GetFee();
+            modifyFee += cit->GetModifiedFee();
             modifyCount++;
             cachedDescendants[updateIt].insert(cit);
         }
@@ -244,7 +235,7 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
     }
     const int64_t updateCount = (add ? 1 : -1);
     const int64_t updateSize = updateCount * it->GetTxSize();
-    const CAmount updateFee = updateCount * it->GetFee();
+    const CAmount updateFee = updateCount * it->GetModifiedFee();
     for (txiter ancestorIt : setAncestors) {
         mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
     }
@@ -304,7 +295,7 @@ void CTxMemPoolEntry::SetDirty()
 {
     nCountWithDescendants = 0;
     nSizeWithDescendants = nTxSize;
-    nFeesWithDescendants = nFee;
+    nModFeesWithDescendants = GetModifiedFee();
 }
 
 void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
@@ -312,8 +303,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
     if (!IsDirty()) {
         nSizeWithDescendants += modifySize;
         assert(int64_t(nSizeWithDescendants) > 0);
-        nFeesWithDescendants += modifyFee;
-        assert(nFeesWithDescendants >= 0);
+        nModFeesWithDescendants += modifyFee;
         nCountWithDescendants += modifyCount;
         assert(int64_t(nCountWithDescendants) > 0);
     }
@@ -376,6 +366,17 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
     indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
     mapLinks.insert(make_pair(newit, TxLinks()));
 
+    // Update transaction for any feeDelta created by PrioritiseTransaction
+    // TODO: refactor so that the fee delta is calculated before inserting
+    // into mapTx.
+    std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
+    if (pos != mapDeltas.end()) {
+        const CAmount &delta = pos->second;
+        if (delta) {
+            mapTx.modify(newit, update_fee_delta(delta));
+        }
+    }
+
     // Update cachedInnerUsage to include contained transaction's usage.
     // (When we update the entry for in-mempool parents, memory usage will be
     // further updated.)
@@ -417,15 +418,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
         mapOrchardNullifiers[orchardNullifier] = &tx;
     }
 
-    // Update transaction's score for any feeDelta created by PrioritiseTransaction
-    std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
-    if (pos != mapDeltas.end()) {
-        const std::pair<double, CAmount> &deltas = pos->second;
-        if (deltas.second) {
-            mapTx.modify(newit, update_fee_delta(deltas.second));
-        }
-    }
-
     nTransactionsUpdated++;
     totalTxSize += entry.GetTxSize();
     minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
@@ -908,27 +900,24 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
         CTxMemPool::setEntries setChildrenCheck;
         std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
         int64_t childSizes = 0;
-        CAmount childFees = 0;
+        CAmount childModFee = 0;
         for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) {
             txiter childit = mapTx.find(iter->second.ptx->GetHash());
             assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
             if (setChildrenCheck.insert(childit).second) {
                 childSizes += childit->GetTxSize();
-                childFees += childit->GetFee();
+                childModFee += childit->GetModifiedFee();
             }
         }
         assert(setChildrenCheck == GetMemPoolChildren(it));
-        // Also check to make sure size/fees is greater than sum with immediate children.
+        // Also check to make sure size is greater than sum with immediate children.
         // just a sanity check, not definitive that this calc is correct...
-        // also check that the size is less than the size of the entire mempool.
         if (!it->IsDirty()) {
             assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
-            assert(it->GetFeesWithDescendants() >= childFees + it->GetFee());
         } else {
             assert(it->GetSizeWithDescendants() == it->GetTxSize());
-            assert(it->GetFeesWithDescendants() == it->GetFee());
+            assert(it->GetModFeesWithDescendants() == it->GetModifiedFee());
         }
-        assert(it->GetFeesWithDescendants() >= 0);
 
         if (fDependsWait)
             waitingOnDependants.push_back(&(*it));
@@ -1096,19 +1085,14 @@ CFeeRate CTxMemPool::estimateFee(int nBlocks) const
     LOCK(cs);
     return minerPolicyEstimator->estimateFee(nBlocks);
 }
-double CTxMemPool::estimatePriority(int nBlocks) const
-{
-    LOCK(cs);
-    return minerPolicyEstimator->estimatePriority(nBlocks);
-}
 
 bool
 CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
 {
     try {
         LOCK(cs);
-        fileout << 109900; // version required to read: 0.10.99 or later
-        fileout << CLIENT_VERSION; // version that wrote the file
+        fileout << FEE_ESTIMATES_WITHOUT_PRIORITY_VERSION; // version required to read
+        fileout << std::max(FEE_ESTIMATES_WITHOUT_PRIORITY_VERSION, CLIENT_VERSION); // version that wrote the file
         minerPolicyEstimator->Write(fileout);
     }
     catch (const std::exception&) {
@@ -1124,11 +1108,10 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
     try {
         int nVersionRequired, nVersionThatWrote;
         filein >> nVersionRequired >> nVersionThatWrote;
-        if (nVersionRequired > CLIENT_VERSION)
+        if (nVersionRequired > std::max(FEE_ESTIMATES_WITHOUT_PRIORITY_VERSION, CLIENT_VERSION))
             return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
-
         LOCK(cs);
-        minerPolicyEstimator->Read(filein);
+        minerPolicyEstimator->Read(filein, nVersionThatWrote);
     }
     catch (const std::exception&) {
         LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
@@ -1137,30 +1120,36 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
     return true;
 }
 
-void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta)
+void CTxMemPool::PrioritiseTransaction(const uint256 hash, const std::string strHash, const CAmount& nFeeDelta)
 {
     {
         LOCK(cs);
-        std::pair<double, CAmount> &deltas = mapDeltas[hash];
-        deltas.first += dPriorityDelta;
-        deltas.second += nFeeDelta;
+        CAmount &delta = mapDeltas[hash];
+        delta += nFeeDelta;
         txiter it = mapTx.find(hash);
         if (it != mapTx.end()) {
-            mapTx.modify(it, update_fee_delta(deltas.second));
+            mapTx.modify(it, update_fee_delta(delta));
+            // Now update all ancestors' modified fees with descendants
+            setEntries setAncestors;
+            uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+            std::string dummy;
+            CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+            BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+                mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));
+            }
         }
     }
-    LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
+    LogPrintf("PrioritiseTransaction: %s feerate += %s\n", strHash, FormatMoney(nFeeDelta));
 }
 
-void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const
+void CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const
 {
     LOCK(cs);
-    std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+    std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
     if (pos == mapDeltas.end())
         return;
-    const std::pair<double, CAmount> &deltas = pos->second;
-    dPriorityDelta += deltas.first;
-    nFeeDelta += deltas.second;
+    const CAmount &delta = pos->second;
+    nFeeDelta += delta;
 }
 
 void CTxMemPool::ClearPrioritisation(const uint256 hash)
diff --git a/src/txmempool.h b/src/txmempool.h
index ecbed2834f8..6e43461d49c 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -28,21 +28,8 @@
 
 class CAutoFile;
 
-inline double AllowFreeThreshold()
-{
-    // 144 is the number of Bitcoin blocks per day. This has not been updated for Zcash,
-    // as it would make it harder to get shielded transactions into blocks by lowering the
-    // threshold at which we switch from priority-based selection of transactions into
-    // blocks to fee-based selection.
-    return COIN * 144 / 250;
-}
-
-inline bool AllowFree(double dPriority)
-{
-    // Large (in bytes) low-priority (new, small-coin) transactions
-    // need a fee.
-    return dPriority > AllowFreeThreshold();
-}
+/** Version from which we write `fee_estimates.dat` without priority information: 5.5.0-beta1 or later */
+static const int FEE_ESTIMATES_WITHOUT_PRIORITY_VERSION = 5050000;
 
 /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
 static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
@@ -56,12 +43,12 @@ class CTxMemPool;
  * ("descendant" transactions).
  *
  * When a new entry is added to the mempool, we update the descendant state
- * (nCountWithDescendants, nSizeWithDescendants, and nFeesWithDescendants) for
+ * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
  * all ancestors of the newly added transaction.
  *
  * If updating the descendant state is skipped, we can mark the entry as
- * "dirty", and set nSizeWithDescendants/nFeesWithDescendants to equal nTxSize/
- * nTxFee. (This can potentially happen during a reorg, where we limit the
+ * "dirty", and set nSizeWithDescendants/nModFeesWithDescendants to equal nTxSize/
+ * nFee+feeDelta. (This can potentially happen during a reorg, where we limit the
  * amount of work we're willing to do to avoid consuming too much CPU.)
  *
  */
@@ -72,10 +59,8 @@ class CTxMemPoolEntry
     std::shared_ptr<const CTransaction> tx;
     CAmount nFee;              //!< Cached to avoid expensive parent-transaction lookups
     size_t nTxSize;            //!< ... and avoid recomputing tx size
-    size_t nModSize;           //!< ... and modified size for priority
     size_t nUsageSize;         //!< ... and total memory usage
     int64_t nTime;             //!< Local time when entering the mempool
-    double dPriority;          //!< Priority when entering the mempool
     unsigned int nHeight;      //!< Chain height when entering the mempool
     bool hadNoDependencies;    //!< Not dependent on any other txs when it entered the mempool
     bool spendsCoinbase;       //!< keep track of transactions that spend a coinbase
@@ -86,22 +71,21 @@ class CTxMemPoolEntry
     // Information about descendants of this transaction that are in the
     // mempool; if we remove this transaction we must remove all of these
     // descendants as well.  if nCountWithDescendants is 0, treat this entry as
-    // dirty, and nSizeWithDescendants and nFeesWithDescendants will not be
+    // dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be
     // correct.
     uint64_t nCountWithDescendants;  //! number of descendant transactions
     uint64_t nSizeWithDescendants;   //! ... and size
-    CAmount nFeesWithDescendants;    //! ... and total fees (all including us)
+    CAmount nModFeesWithDescendants; //! ... and total fees (all including us)
 
 public:
     CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
-                    int64_t _nTime, double _dPriority, unsigned int _nHeight,
+                    int64_t _nTime, unsigned int _nHeight,
                     bool poolHasNoInputsOf, bool spendsCoinbase,
                     unsigned int nSigOps, uint32_t nBranchId);
     CTxMemPoolEntry(const CTxMemPoolEntry& other);
 
     const CTransaction& GetTx() const { return *this->tx; }
     std::shared_ptr<const CTransaction> GetSharedTx() const { return this->tx; }
-    double GetPriority(unsigned int currentHeight) const;
     const CAmount& GetFee() const { return nFee; }
     size_t GetTxSize() const { return nTxSize; }
     int64_t GetTime() const { return nTime; }
@@ -113,7 +97,8 @@ class CTxMemPoolEntry
 
     // Adjusts the descendant state, if this entry is not dirty.
     void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
-    // Updates the fee delta used for mining priority score
+    // Updates the fee delta used for mining priority score, and the
+    // modified fees with descendants.
     void UpdateFeeDelta(int64_t feeDelta);
 
     /** We can set the entry to be dirty if doing the full calculation of in-
@@ -125,7 +110,7 @@ class CTxMemPoolEntry
 
     uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
     uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
-    CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; }
+    CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
 
     bool GetSpendsCoinbase() const { return spendsCoinbase; }
     uint32_t GetValidatedBranchId() const { return nBranchId; }
@@ -173,27 +158,27 @@ struct mempoolentry_txid
     }
 };
 
-/** \class CompareTxMemPoolEntryByFee
+/** \class CompareTxMemPoolEntryByDescendantScore
  *
- *  Sort an entry by max(feerate of entry's tx, feerate with all descendants).
+ *  Sort an entry by max(score/size of entry's tx, score/size with all descendants).
  */
-class CompareTxMemPoolEntryByFee
+class CompareTxMemPoolEntryByDescendantScore
 {
 public:
     bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b) const
     {
-        bool fUseADescendants = UseDescendantFeeRate(a);
-        bool fUseBDescendants = UseDescendantFeeRate(b);
+        bool fUseADescendants = UseDescendantScore(a);
+        bool fUseBDescendants = UseDescendantScore(b);
 
-        double aFees = fUseADescendants ? a.GetFeesWithDescendants() : a.GetFee();
+        double aModFee = fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee();
         double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize();
 
-        double bFees = fUseBDescendants ? b.GetFeesWithDescendants() : b.GetFee();
+        double bModFee = fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee();
         double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize();
 
         // Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
-        double f1 = aFees * bSize;
-        double f2 = aSize * bFees;
+        double f1 = aModFee * bSize;
+        double f2 = aSize * bModFee;
 
         if (f1 == f2) {
             return a.GetTime() >= b.GetTime();
@@ -201,11 +186,11 @@ class CompareTxMemPoolEntryByFee
         return f1 < f2;
     }
 
-    // Calculate which feerate to use for an entry (avoiding division).
-    bool UseDescendantFeeRate(const CTxMemPoolEntry &a) const
+    // Calculate which score to use for an entry (avoiding division).
+    bool UseDescendantScore(const CTxMemPoolEntry &a) const
     {
-        double f1 = (double)a.GetFee() * a.GetSizeWithDescendants();
-        double f2 = (double)a.GetFeesWithDescendants() * a.GetTxSize();
+        double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();
+        double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
         return f2 > f1;
     }
 };
@@ -382,9 +367,9 @@ class CTxMemPool
             boost::multi_index::ordered_non_unique<
                 boost::multi_index::tag<descendant_score>,
                 boost::multi_index::identity<CTxMemPoolEntry>,
-                CompareTxMemPoolEntryByFee
+                CompareTxMemPoolEntryByDescendantScore
             >,
-            // sorted by score (for mining prioritization)
+            // sorted by score (for mining prioritisation)
             boost::multi_index::ordered_unique<
                 boost::multi_index::tag<mining_score>,
                 boost::multi_index::identity<CTxMemPoolEntry>,
@@ -465,7 +450,7 @@ class CTxMemPool
 
 public:
     std::map<COutPoint, CInPoint> mapNextTx;
-    std::map<uint256, std::pair<double, CAmount> > mapDeltas;
+    std::map<uint256, CAmount> mapDeltas;
 
     /** Create a new CTxMemPool.
      *  minReasonableRelayFee should be a feerate which is, roughly, somewhere
@@ -524,8 +509,8 @@ class CTxMemPool
     bool HasNoInputsOf(const CTransaction& tx) const;
 
     /** Affect CreateNewBlock prioritisation of transactions */
-    void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta);
-    void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const;
+    void PrioritiseTransaction(const uint256 hash, const std::string strHash, const CAmount& nFeeDelta);
+    void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
     void ClearPrioritisation(const uint256 hash);
 
 public:
@@ -588,9 +573,6 @@ class CTxMemPool
     /** Estimate fee rate needed to get into the next nBlocks */
     CFeeRate estimateFee(int nBlocks) const;
 
-    /** Estimate priority needed to get into the next nBlocks */
-    double estimatePriority(int nBlocks) const;
-
     /** Write/Read estimates to disk */
     bool WriteFeeEstimates(CAutoFile& fileout) const;
     bool ReadFeeEstimates(CAutoFile& filein);
@@ -669,17 +651,4 @@ class CCoinsViewMemPool : public CCoinsViewBacked
     bool HaveCoins(const uint256 &txid) const;
 };
 
-// We want to sort transactions by coin age priority
-typedef std::pair<double, CTxMemPool::txiter> TxCoinAgePriority;
-
-struct TxCoinAgePriorityCompare
-{
-    bool operator()(const TxCoinAgePriority& a, const TxCoinAgePriority& b)
-    {
-        if (a.first == b.first)
-            return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); //Reverse order to make sort less than
-        return a.first < b.first;
-    }
-};
-
 #endif // BITCOIN_TXMEMPOOL_H
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 825bf2b97e7..8da116f3454 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2408,9 +2408,9 @@ UniValue settxfee(const UniValue& params, bool fHelp)
     if (fHelp || params.size() < 1 || params.size() > 1)
         throw runtime_error(
             "settxfee amount\n"
-            "\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
+            "\nSet the preferred transaction fee rate per 1000 bytes. This is only used by legacy transaction creation APIs (sendtoaddress, sendmany, and fundrawtransaction). Overwrites the paytxfee parameter.\n"
             "\nArguments:\n"
-            "1. amount         (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
+            "1. amount         (numeric, required) The transaction fee rate in " + CURRENCY_UNIT + " per 1000 bytes rounded to the nearest 0.00000001\n"
             "\nResult\n"
             "true|false        (boolean) Returns true if successful\n"
             "\nExamples:\n"
@@ -2454,7 +2454,7 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
             "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
             "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
             "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
-            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
+            "  \"paytxfee\": x.xxxx,         (numeric) the preferred transaction fee rate used for transactions created by legacy APIs, set in " + CURRENCY_UNIT + " per 1000 bytes\n"
             "  \"mnemonic_seedfp\": \"uint256\", (string) the BLAKE2b-256 hash of the HD seed derived from the wallet's emergency recovery phrase\n"
             "  \"legacy_seedfp\": \"uint256\",   (string, optional) if this wallet was created prior to release 4.5.2, this will contain the BLAKE2b-256\n"
             "                                    hash of the legacy HD seed that was used to derive Sapling addresses prior to the 4.5.2 upgrade to mnemonic\n"
@@ -4260,7 +4260,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
             "      \"actionPrev\" : n,               (numeric, orchard) the index of the action within the orchard bundle\n"
             "      \"address\" : \"zcashaddress\",     (string) The Zcash address involved in the transaction\n"
             "      \"value\" : x.xxx                 (numeric) The amount in " + CURRENCY_UNIT + "\n"
-            "      \"valueZat\" : xxxx               (numeric) The amount in zatoshis\n"
+            "      \"valueZat\" : xxxx               (numeric) The amount in " + MINOR_CURRENCY_UNIT + "\n"
             "    }\n"
             "    ,...\n"
             "  ],\n"
@@ -4276,7 +4276,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
             "      \"outgoing\" : true|false         (boolean) True if the output is not for an address in the wallet\n"
             "      \"walletInternal\" : true|false   (boolean) True if this is a change output.\n"
             "      \"value\" : x.xxx                 (numeric) The amount in " + CURRENCY_UNIT + "\n"
-            "      \"valueZat\" : xxxx               (numeric) The amount in zatoshis\n"
+            "      \"valueZat\" : xxxx               (numeric) The amount in " + MINOR_CURRENCY_UNIT + "\n"
             "      \"memo\" : \"hexmemo\",             (string) hexadecimal string representation of the memo field\n"
             "      \"memoStr\" : \"memo\",             (string) Only returned if memo contains valid UTF-8 text.\n"
             "    }\n"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 451de78896a..1304e9335e8 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -49,7 +49,6 @@ CWallet* pwalletMain = NULL;
 CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
 unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
 bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
-bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
 bool fPayAtLeastCustomFee = true;
 unsigned int nAnchorConfirmations = DEFAULT_ANCHOR_CONFIRMATIONS;
 unsigned int nOrchardActionLimit = DEFAULT_ORCHARD_ACTION_LIMIT;
@@ -57,8 +56,9 @@ unsigned int nOrchardActionLimit = DEFAULT_ORCHARD_ACTION_LIMIT;
 const char * DEFAULT_WALLET_DAT = "wallet.dat";
 
 /**
- * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
- * Override with -mintxfee
+ * -mintxfee: the fallback fee rate (in ZEC per 1000 bytes) used by legacy APIs
+ * when -paytxfee has not been set and there is insufficient mempool data to
+ * estimate a fee according to the -txconfirmtarget option.
  */
 CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
 
@@ -5542,7 +5542,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
                 CAmount nTotalValue = nValue;
                 if (nSubtractFeeFromAmount == 0)
                     nTotalValue += nFeeRet;
-                double dPriority = 0;
+
                 // vouts to the payees
                 for (const CRecipient& recipient : vecSend)
                 {
@@ -5559,7 +5559,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
                         }
                     }
 
-                    if (txout.IsDust(::minRelayTxFee))
+                    if (txout.IsDust())
                     {
                         if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
                         {
@@ -5591,18 +5591,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
                     }
                     return false;
                 }
-                for (std::pair<const CWalletTx*, unsigned int> pcoin : setCoins)
-                {
-                    CAmount nCredit = pcoin.first->vout[pcoin.second].nValue;
-                    //The coin age after the next block (depth+1) is used instead of the current,
-                    //reflecting an assumption the user would accept a bit more delay for
-                    //a chance at a free transaction.
-                    //But mempool inputs might still be in the mempool, so their age stays 0
-                    int age = pcoin.first->GetDepthInMainChain(std::nullopt);
-                    if (age != 0)
-                        age += 1;
-                    dPriority += (double)nCredit * age;
-                }
 
                 CAmount nChange = nValueIn - nValue;
                 if (nSubtractFeeFromAmount == 0)
@@ -5643,16 +5631,16 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
                     // We do not move dust-change to fees, because the sender would end up paying more than requested.
                     // This would be against the purpose of the all-inclusive feature.
                     // So instead we raise the change and deduct from the recipient.
-                    if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(::minRelayTxFee))
+                    if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust())
                     {
-                        CAmount nDust = newTxOut.GetDustThreshold(::minRelayTxFee) - newTxOut.nValue;
+                        CAmount nDust = newTxOut.GetDustThreshold() - newTxOut.nValue;
                         newTxOut.nValue += nDust; // raise change until no more dust
                         for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
                         {
                             if (vecSend[i].fSubtractFeeFromAmount)
                             {
                                 txNew.vout[i].nValue -= nDust;
-                                if (txNew.vout[i].IsDust(::minRelayTxFee))
+                                if (txNew.vout[i].IsDust())
                                 {
                                     strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
                                     return false;
@@ -5664,7 +5652,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
 
                     // Never create dust outputs; if we would, just
                     // add the dust to the fee.
-                    if (newTxOut.IsDust(::minRelayTxFee))
+                    if (newTxOut.IsDust())
                     {
                         nFeeRet += nChange;
                         reservekey.ReturnKey();
@@ -5738,22 +5726,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
                     return false;
                 }
 
-                dPriority = wtxNew.ComputePriority(dPriority, nBytes);
-
-                // Can we complete this as a free transaction?
-                if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
-                {
-                    // Not enough fee: enough priority?
-                    double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget);
-                    // Not enough mempool history to estimate: use hard-coded AllowFree.
-                    if (dPriorityNeeded <= 0 && AllowFree(dPriority))
-                        break;
-
-                    // Small enough, and priority high enough, to send for free
-                    if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
-                        break;
-                }
-
                 CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool);
 
                 // If we made it here and we aren't even able to meet the relay fee on the next pass, give up
@@ -5837,7 +5809,9 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
 {
     // payTxFee is user-set "I want to pay this much"
     CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes);
-    // user selected total at least (default=true)
+    // TODO: fPayAtLeastCustomFee is always true so we could simplify this by saying
+    // `payTxFee.GetFee(std::max(1000, nTxBytes))` above, if we do not remove this code
+    // completely.
     if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK())
         nFeeNeeded = payTxFee.GetFeePerK();
     // User didn't set: use -txconfirmtarget to estimate...
@@ -6532,16 +6506,21 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
     strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
     strUsage += HelpMessageOpt("-migration", _("Enable the Sprout to Sapling migration"));
     strUsage += HelpMessageOpt("-migrationdestaddress=<zaddr>", _("Set the Sapling migration address"));
-    strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
+    strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("The fallback fee rate (in %s per 1000 bytes) used by legacy APIs (sendtoaddress, sendmany, and fundrawtransaction) when -paytxfee "
+                                                              "has not been set and there is insufficient mempool data to estimate a fee according to the -txconfirmtarget option (default: %s)"),
                                                             CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
     strUsage += HelpMessageOpt("-orchardactionlimit=<n>", strprintf(_("Set the maximum number of Orchard actions permitted in a transaction (default %u)"), DEFAULT_ORCHARD_ACTION_LIMIT));
-    strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
-                                                            CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
+    strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("The preferred fee rate (in %s per 1000 bytes) used for transactions created by legacy APIs (sendtoaddress, sendmany, and fundrawtransaction). "
+                                                              "If the transaction is less than 1000 bytes then the fee rate is applied as though it were 1000 bytes. See the descriptions of -txconfirmtarget "
+                                                              "and -mintxfee options for how the fee is calculated when this option is not set."),
+                                                            CURRENCY_UNIT));
     strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
     strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup (implies -rescan)"));
-    strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
     strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
-    strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
+    strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If -paytxfee is not set, include enough fee that transactions created by legacy APIs (sendtoaddress, sendmany, and fundrawtransaction) "
+                                                                   "begin confirmation on average within n blocks. This is only used if there is sufficient mempool data to estimate the fee; if not, the "
+                                                                   "fallback fee set by -mintxfee is used. (default: %u)"),
+                                                                 DEFAULT_TX_CONFIRM_TARGET));
     strUsage += HelpMessageOpt("-txexpirydelta", strprintf(_("Set the number of blocks after which a transaction that has not been mined will become invalid (min: %u, default: %u (pre-Blossom) or %u (post-Blossom))"), TX_EXPIRING_SOON_THRESHOLD + 1, DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA, DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA));
     strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
     strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file absolute path or a path relative to the data directory") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
@@ -6758,11 +6737,11 @@ bool CWallet::ParameterInteraction(const CChainParams& params)
         if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
             return UIError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"]));
         if (nFeePerK > HIGH_TX_FEE_PER_KB)
-            UIWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
+            UIWarning(_("-paytxfee is set to a very high fee rate! This is the fee rate you will pay if you send a transaction."));
         payTxFee = CFeeRate(nFeePerK, 1000);
         if (payTxFee < ::minRelayTxFee)
         {
-            return UIError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+            return UIError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least the minimum relay fee rate %s)"),
                                        mapArgs["-paytxfee"], ::minRelayTxFee.ToString()));
         }
     }
@@ -6772,11 +6751,11 @@ bool CWallet::ParameterInteraction(const CChainParams& params)
         if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
             return UIError(AmountErrMsg("maxtxfee", mapArgs["-maxtxfee"]));
         if (nMaxFee > HIGH_MAX_TX_FEE)
-            UIWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
+            UIWarning(_("-maxtxfee is set to a very high fee rate! Fee rates this large could be paid on a single transaction."));
         maxTxFee = nMaxFee;
         if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
         {
-            return UIError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+            return UIError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minimum relay fee rate of %s to prevent stuck transactions)"),
                                        mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
         }
     }
@@ -6790,7 +6769,10 @@ bool CWallet::ParameterInteraction(const CChainParams& params)
         expiryDeltaArg = expiryDelta;
     }
     bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
-    fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
+
+    if (GetBoolArg("-sendfreetransactions", false)) {
+        return UIError(_("The argument -sendfreetransactions is no longer supported."));
+    }
 
     KeyIO keyIO(params);
     // Check Sapling migration address if set and is a valid Sapling address
@@ -7780,6 +7762,7 @@ bool SpendableInputs::LimitToAmount(
     const CAmount dustThreshold,
     const std::set<OutputPool>& recipientPools)
 {
+    // dustThreshold cannot be zero because it is no longer configured via `-minrelaytxfee`.
     assert(amountRequired >= 0 && dustThreshold > 0);
     // Calling this method twice is a programming error.
     assert(!limited);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 6b21a1727cb..705c1e7014f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -54,7 +54,6 @@ extern CWallet* pwalletMain;
 extern CFeeRate payTxFee;
 extern unsigned int nTxConfirmTarget;
 extern bool bSpendZeroConfChange;
-extern bool fSendFreeTransactions;
 extern bool fPayAtLeastCustomFee;
 extern unsigned int nAnchorConfirmations;
 // The maximum number of Orchard actions permitted within a single transaction.
@@ -70,12 +69,8 @@ static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
 static const CAmount MIN_CHANGE = CENT;
 //! Default for -spendzeroconfchange
 static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
-//! Default for -sendfreetransactions
-static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
 //! -txconfirmtarget default
 static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
-//! Largest (in bytes) free transaction we're willing to create
-static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
 static const bool DEFAULT_WALLETBROADCAST = true;
 //! Size of witness cache
 //  Should be large enough that we can expect not to reorg beyond our cache
@@ -1952,12 +1947,12 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
     static CFeeRate minTxFee;
     /**
      * Estimate the minimum fee considering user set parameters
-     * and the required fee
+     * and the required fee.
      */
     static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
     /**
      * Return the minimum required fee taking into account the
-     * floating relay fee and user set minimum transaction fee
+     * floating relay fee rate and user set minimum transaction fee rate.
      */
     static CAmount GetRequiredFee(unsigned int nTxBytes);
 
diff --git a/src/wallet/wallet_tx_builder.cpp b/src/wallet/wallet_tx_builder.cpp
index 1576d1ba2b9..6bead7085d1 100644
--- a/src/wallet/wallet_tx_builder.cpp
+++ b/src/wallet/wallet_tx_builder.cpp
@@ -191,7 +191,7 @@ CAmount WalletTxBuilder::DefaultDustThreshold() const {
     CKey secret{CKey::TestOnlyRandomKey(true)};
     CScript scriptPubKey = GetScriptForDestination(secret.GetPubKey().GetID());
     CTxOut txout(CAmount(1), scriptPubKey);
-    return txout.GetDustThreshold(minRelayFee);
+    return txout.GetDustThreshold();
 }
 
 SpendableInputs WalletTxBuilder::FindAllSpendableInputs(


Test patch:
diff --git a/qa/rpc-tests/addressindex.py b/qa/rpc-tests/addressindex.py
index 3e55c4b1119..6d5251e63df 100755
--- a/qa/rpc-tests/addressindex.py
+++ b/qa/rpc-tests/addressindex.py
@@ -50,6 +50,7 @@ def __init__(self):
 
     def setup_network(self):
         base_args = [
+            '-minrelaytxfee=0',
             '-debug',
             '-txindex',
             '-experimentalfeatures',
diff --git a/qa/rpc-tests/finalorchardroot.py b/qa/rpc-tests/finalorchardroot.py
index 4c004bc58b6..f40cf3758cf 100755
--- a/qa/rpc-tests/finalorchardroot.py
+++ b/qa/rpc-tests/finalorchardroot.py
@@ -33,6 +33,7 @@ def __init__(self):
 
     def setup_network(self, split=False):
         self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-txindex', # Avoid JSONRPC error: No information available about transaction
             '-reindex', # Required due to enabling -txindex
             nuparams(NU5_BRANCH_ID, 200),
diff --git a/qa/rpc-tests/finalsaplingroot.py b/qa/rpc-tests/finalsaplingroot.py
index 6d07f75f37b..59909f3ef99 100755
--- a/qa/rpc-tests/finalsaplingroot.py
+++ b/qa/rpc-tests/finalsaplingroot.py
@@ -33,6 +33,7 @@ def __init__(self):
 
     def setup_network(self, split=False):
         self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-txindex', # Avoid JSONRPC error: No information available about transaction
             '-reindex', # Required due to enabling -txindex
             nuparams(NU5_BRANCH_ID, 210),
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 94debab796d..5f3a53250c7 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -425,7 +425,7 @@ def run_test(self):
         mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])
 
 
-        # send 1.2 BTC to msig addr
+        # send 1.2 ZEC to multisig address
         txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
         self.sync_all()
         self.nodes[1].generate(1)
diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py
index 8ec448f5066..369bc4d9c29 100755
--- a/qa/rpc-tests/invalidtxrequest.py
+++ b/qa/rpc-tests/invalidtxrequest.py
@@ -17,6 +17,9 @@
 
 # Use the ComparisonTestFramework with 1 node: only use --testbinary.
 class InvalidTxRequestTest(ComparisonTestFramework):
+    def __init__(self):
+        super().__init__()
+        self.additional_args = ['-minrelaytxfee=0']
 
     ''' Can either run this test as 1 node with expected answers, or two and compare them. 
         Change the "outcome" variable from each TestInstance object to only do the comparison. '''
diff --git a/qa/rpc-tests/mempool_nu_activation.py b/qa/rpc-tests/mempool_nu_activation.py
index 6ae41003f67..43c8691a3f5 100755
--- a/qa/rpc-tests/mempool_nu_activation.py
+++ b/qa/rpc-tests/mempool_nu_activation.py
@@ -30,9 +30,10 @@ def __init__(self):
 
     def setup_network(self):
         args = [
-            "-checkmempool",
-            "-debug=mempool",
-            "-blockmaxsize=4000",
+            '-minrelaytxfee=0',
+            '-checkmempool',
+            '-debug=mempool',
+            '-blockmaxsize=4000',
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=legacy_privacy',
             '-allowdeprecated=z_getnewaddress',
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 5b549a58542..7e4cc01fe9f 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -16,18 +16,20 @@
     sync_blocks,
     sync_mempools,
 )
+from test_framework.mininode import COIN
 
 def satoshi_round(amount):
     return  Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
 
 class MempoolPackagesTest(BitcoinTestFramework):
+    maxorphantx = 120
 
     def setup_network(self):
         base_args = [
-            "-maxorphantx=1000",
-            "-relaypriority=0",
-            "-debug",
-            "-allowdeprecated=getnewaddress",
+            '-minrelaytxfee=0',
+            '-maxorphantx=%d' % (self.maxorphantx,),
+            '-debug',
+            '-allowdeprecated=getnewaddress',
         ]
         self.nodes = []
         self.nodes.append(start_node(0, self.options.tmpdir, base_args))
@@ -74,22 +76,45 @@ def run_test(self):
         descendant_count = 1
         descendant_fees = 0
         descendant_size = 0
-        SATOSHIS = 100000000
 
         for x in reversed(chain):
             assert_equal(mempool[x]['descendantcount'], descendant_count)
             descendant_fees += mempool[x]['fee']
-            assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees)
+            assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee'])
+            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN)
             descendant_size += mempool[x]['size']
             assert_equal(mempool[x]['descendantsize'], descendant_size)
             descendant_count += 1
 
+        # Check that descendant modified fees includes fee deltas from
+        # prioritisetransaction
+        self.nodes[0].prioritisetransaction(chain[-1], 0, 1000)
+        mempool = self.nodes[0].getrawmempool(True)
+
+        descendant_fees = 0
+        for x in reversed(chain):
+            descendant_fees += mempool[x]['fee']
+            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000)
+
         # Adding one more transaction on to the chain should fail.
         try:
             self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)
         except JSONRPCException:
             print("too-long-ancestor-chain successfully rejected")
 
+        # Check that prioritising a tx before it's added to the mempool works
+        self.nodes[0].generate(1)
+        self.nodes[0].prioritisetransaction(chain[-1], None, 2000)
+        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
+        mempool = self.nodes[0].getrawmempool(True)
+
+        descendant_fees = 0
+        for x in reversed(chain):
+            descendant_fees += mempool[x]['fee']
+            if (x == chain[-1]):
+                assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']+satoshi_round(0.00002))
+            assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 2000)
+
         # TODO: check that node1's mempool is as expected
 
         # TODO: test ancestor size limits
@@ -106,18 +131,18 @@ def run_test(self):
         for i in range(10):
             transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})
 
-        for i in range(1000):
+        for i in range(self.maxorphantx):
             utxo = transaction_package.pop(0)
             try:
                 (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
                 for j in range(10):
                     transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
-                if i == 998:
+                if i == self.maxorphantx-2:
                     mempool = self.nodes[0].getrawmempool(True)
-                    assert_equal(mempool[parent_transaction]['descendantcount'], 1000)
+                    assert_equal(mempool[parent_transaction]['descendantcount'], self.maxorphantx)
             except JSONRPCException as e:
                 print(e.error['message'])
-                assert_equal(i, 999)
+                assert_equal(i, self.maxorphantx-1)
                 print("tx that would create too large descendant package successfully rejected")
 
         # TODO: check that node1's mempool is as expected
@@ -127,7 +152,8 @@ def run_test(self):
         # Test reorg handling
         # First, the basics:
         self.nodes[0].generate(1)
-        sync_blocks(self.nodes)
+        print("syncing blocks")
+        sync_blocks(self.nodes, timeout=480)
         self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash())
         self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash())
 
diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py
index b9af8b19cd1..06e9d1f5b54 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/qa/rpc-tests/mempool_reorg.py
@@ -24,9 +24,10 @@ def __init__(self):
 
     def setup_network(self):
         args = [
-            "-checkmempool",
-            "-debug=mempool",
-            "-allowdeprecated=getnewaddress",
+            '-minrelaytxfee=0',
+            '-checkmempool',
+            '-debug=mempool',
+            '-allowdeprecated=getnewaddress',
         ]
         self.nodes = []
         self.nodes.append(start_node(0, self.options.tmpdir, args))
diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py
index c7e63a0163a..36012974ec1 100755
--- a/qa/rpc-tests/mempool_resurrect_test.py
+++ b/qa/rpc-tests/mempool_resurrect_test.py
@@ -24,7 +24,12 @@ def __init__(self):
 
     def setup_network(self):
         # Just need one node for this test
-        args = ["-checkmempool", "-debug=mempool", "-allowdeprecated=getnewaddress"]
+        args = [
+            '-minrelaytxfee=0',
+            '-checkmempool',
+            '-debug=mempool',
+            '-allowdeprecated=getnewaddress',
+        ]
         self.nodes = []
         self.nodes.append(start_node(0, self.options.tmpdir, args))
         self.is_network_split = False
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
index eeec2d5618f..43da9f90590 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -30,9 +30,10 @@ def __init__(self):
     def setup_network(self):
         # Just need one node for this test
         args = [
-            "-checkmempool",
-            "-debug=mempool",
-            "-allowdeprecated=getnewaddress",
+            '-minrelaytxfee=0',
+            '-checkmempool',
+            '-debug=mempool',
+            '-allowdeprecated=getnewaddress',
         ]
         self.nodes = []
         self.nodes.append(start_node(0, self.options.tmpdir, args))
diff --git a/qa/rpc-tests/mempool_tx_expiry.py b/qa/rpc-tests/mempool_tx_expiry.py
index a5d77ef9933..16c128a9848 100755
--- a/qa/rpc-tests/mempool_tx_expiry.py
+++ b/qa/rpc-tests/mempool_tx_expiry.py
@@ -22,14 +22,14 @@
 class MempoolTxExpiryTest(BitcoinTestFramework):
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir,
-            [[
-                "-txexpirydelta=%d" % TX_EXPIRY_DELTA,
-                "-debug=mempool",
-                "-allowdeprecated=getnewaddress",
-                "-allowdeprecated=z_getnewaddress",
-                "-allowdeprecated=z_gettotalbalance",
-            ]] * self.num_nodes)
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
+            '-txexpirydelta=%d' % TX_EXPIRY_DELTA,
+            '-debug=mempool',
+            '-allowdeprecated=getnewaddress',
+            '-allowdeprecated=z_getnewaddress',
+            '-allowdeprecated=z_gettotalbalance',
+        ]] * self.num_nodes)
 
     # Test before, at, and after expiry block
     # chain is at block height 199 when run_test executes
diff --git a/qa/rpc-tests/mergetoaddress_helper.py b/qa/rpc-tests/mergetoaddress_helper.py
index cbaee02b51a..7cc677d66fc 100755
--- a/qa/rpc-tests/mergetoaddress_helper.py
+++ b/qa/rpc-tests/mergetoaddress_helper.py
@@ -43,6 +43,7 @@ def setup_chain(self, test):
 
     def setup_network(self, test, additional_args=[]):
         args = [
+            '-minrelaytxfee=0',
             '-debug=zrpcunsafe',
             '-limitancestorcount=%d' % self.utxos_to_generate,
             '-allowdeprecated=getnewaddress',
diff --git a/qa/rpc-tests/mergetoaddress_mixednotes.py b/qa/rpc-tests/mergetoaddress_mixednotes.py
index 0217bb047a0..e31a8503c01 100755
--- a/qa/rpc-tests/mergetoaddress_mixednotes.py
+++ b/qa/rpc-tests/mergetoaddress_mixednotes.py
@@ -18,6 +18,7 @@ def __init__(self):
     def setup_nodes(self):
         self.num_nodes = 4
         return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-anchorconfirmations=1',
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=z_getnewaddress',
diff --git a/qa/rpc-tests/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py
index f08f7458017..9778b7d589d 100755
--- a/qa/rpc-tests/merkle_blocks.py
+++ b/qa/rpc-tests/merkle_blocks.py
@@ -24,8 +24,9 @@ def __init__(self):
 
     def setup_network(self):
         base_args = [
-            "-debug",
-            "-allowdeprecated=getnewaddress",
+            '-minrelaytxfee=0',
+            '-debug',
+            '-allowdeprecated=getnewaddress',
         ]
         self.nodes = []
         # Nodes 0/1 are "wallet" nodes
diff --git a/qa/rpc-tests/mining_shielded_coinbase.py b/qa/rpc-tests/mining_shielded_coinbase.py
index 203c78ba1b9..118ec4f9fe6 100755
--- a/qa/rpc-tests/mining_shielded_coinbase.py
+++ b/qa/rpc-tests/mining_shielded_coinbase.py
@@ -30,15 +30,16 @@ def __init__(self):
 
     def start_node_with(self, index, extra_args=[]):
         args = [
+            '-minrelaytxfee=0',
             nuparams(BLOSSOM_BRANCH_ID, 1),
             nuparams(HEARTWOOD_BRANCH_ID, 10),
             nuparams(CANOPY_BRANCH_ID, 20),
             nuparams(NU5_BRANCH_ID, 20),
-            "-nurejectoldversions=false",
-            "-allowdeprecated=getnewaddress",
-            "-allowdeprecated=z_getnewaddress",
-            "-allowdeprecated=z_getbalance",
-            "-allowdeprecated=z_gettotalbalance",
+            '-nurejectoldversions=false',
+            '-allowdeprecated=getnewaddress',
+            '-allowdeprecated=z_getnewaddress',
+            '-allowdeprecated=z_getbalance',
+            '-allowdeprecated=z_gettotalbalance',
         ]
         return start_node(index, self.options.tmpdir, args + extra_args)
 
diff --git a/qa/rpc-tests/orchard_reorg.py b/qa/rpc-tests/orchard_reorg.py
index aad4a4a5744..420118393ea 100755
--- a/qa/rpc-tests/orchard_reorg.py
+++ b/qa/rpc-tests/orchard_reorg.py
@@ -32,6 +32,7 @@ def __init__(self):
 
     def setup_nodes(self):
         return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(BLOSSOM_BRANCH_ID, 1),
             nuparams(HEARTWOOD_BRANCH_ID, 5),
             nuparams(CANOPY_BRANCH_ID, 5),
diff --git a/qa/rpc-tests/p2p_txexpiringsoon.py b/qa/rpc-tests/p2p_txexpiringsoon.py
index 2e53f9b4342..c0c127e5d51 100755
--- a/qa/rpc-tests/p2p_txexpiringsoon.py
+++ b/qa/rpc-tests/p2p_txexpiringsoon.py
@@ -21,6 +21,7 @@ def __init__(self):
 
     def setup_network(self):
         self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=getnewaddress',
         ]] * self.num_nodes)
         connect_nodes_bi(self.nodes, 0, 1)
diff --git a/qa/rpc-tests/prioritisetransaction.py b/qa/rpc-tests/prioritisetransaction.py
index 72634b3efd7..42dc8f406f0 100755
--- a/qa/rpc-tests/prioritisetransaction.py
+++ b/qa/rpc-tests/prioritisetransaction.py
@@ -27,10 +27,8 @@ def setup_network(self, split=False):
         self.nodes = []
         # Start nodes with tiny block size of 11kb
         args = [
-            "-blockprioritysize=7000",
             "-blockmaxsize=11000",
             "-maxorphantx=1000",
-            "-relaypriority=true",
             "-printpriority=1",
             "-limitancestorcount=900",
             "-allowdeprecated=getnewaddress",
@@ -42,8 +40,6 @@ def setup_network(self, split=False):
         self.sync_all()
 
     def run_test (self):
-        # tx priority is calculated: priority = sum(input_value_in_base_units * input_age)/size_in_bytes
-
         print("Mining 11kb blocks...")
         self.nodes[0].generate(501)
 
@@ -60,8 +56,8 @@ def run_test (self):
         # could take up to 128s. So use a higher timeout on the mempool sync.
         sync_mempools(self.nodes, timeout=200)
 
-        # Create tx of lower value to be prioritized on node 0
-        # Older transactions get mined first, so this lower value, newer tx is unlikely to be mined without prioritisation
+        # Create tx to be prioritised on node 0
+        # This tx will not be mined without prioritisation.
         priority_tx_0 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
 
         # Check that priority_tx_0 is not in block_template() prior to prioritisation
@@ -71,12 +67,17 @@ def run_test (self):
             if tx['hash'] == priority_tx_0:
                 in_block_template = True
                 break
-        assert_equal(in_block_template, False)
 
-        priority_success = self.nodes[0].prioritisetransaction(priority_tx_0, 1000, int(3 * base_fee * COIN))
+        # TODO: this doesn't work reliably now, but as part of #6403 it can be made
+        # to work reliably by using a transaction that has unpaid actions over the
+        # block_unpaid_action_limit before prioritisation.
+        print("in_block_template =", in_block_template)
+        #assert_equal(in_block_template, False)
+
+        priority_success = self.nodes[0].prioritisetransaction(priority_tx_0, 0, int(3 * base_fee * COIN))
         assert(priority_success)
 
-        # Check that prioritized transaction is not in getblocktemplate()
+        # Check that prioritised transaction is not in getblocktemplate()
         # (not updated because no new txns)
         in_block_template = False
         block_template = self.nodes[0].getblocktemplate()
@@ -84,22 +85,15 @@ def run_test (self):
             if tx['hash'] == priority_tx_0:
                 in_block_template = True
                 break
-        assert_equal(in_block_template, False)
+
+        # See TODO above.
+        print("in_block_template =", in_block_template)
+        #assert_equal(in_block_template, False)
 
         # Sending a new transaction will make getblocktemplate refresh within 10s
         self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1)
 
-        # Check that prioritized transaction is not in getblocktemplate()
-        # (too soon)
-        in_block_template = False
-        block_template = self.nodes[0].getblocktemplate()
-        for tx in block_template['transactions']:
-            if tx['hash'] == priority_tx_0:
-                in_block_template = True
-                break
-        assert_equal(in_block_template, False)
-
-        # Check that prioritized transaction is in getblocktemplate()
+        # Check that prioritised transaction is in getblocktemplate()
         # getblocktemplate() will refresh after 1 min, or after 10 sec if new transaction is added to mempool
         # Mempool is probed every 10 seconds. We'll give getblocktemplate() a maximum of 30 seconds to refresh
         block_template = self.nodes[0].getblocktemplate()
@@ -117,9 +111,9 @@ def run_test (self):
 
         assert(in_block_template)
 
-        # Node 1 doesn't get the next block, so this *shouldn't* be mined despite being prioritized on node 1
+        # Node 1 doesn't get the next block, so this *shouldn't* be mined despite being prioritised on node 1
         priority_tx_1 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)
-        self.nodes[1].prioritisetransaction(priority_tx_1, 1000, int(3 * base_fee * COIN))
+        self.nodes[1].prioritisetransaction(priority_tx_1, 0, int(3 * base_fee * COIN))
 
         # Mine block on node 0
         blk_hash = self.nodes[0].generate(1)
@@ -133,7 +127,8 @@ def run_test (self):
 
         # Check that priority_tx_1 was not mined
         assert_equal(priority_tx_1 in mempool, True)
-        assert_equal(priority_tx_1 in block['tx'], False)
+        # TODO: again this is potentially unreliable.
+        #assert_equal(priority_tx_1 in block['tx'], False)
 
         # Mine a block on node 1 and sync
         blk_hash_1 = self.nodes[1].generate(1)
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index eb459e4284d..f4994f4aef2 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -66,7 +66,7 @@ def setup_network(self):
         self.address[0] = self.nodes[0].getnewaddress()
         self.address[1] = self.nodes[1].getnewaddress()
 
-        # Determine default relay fee
+        # Determine default relay fee rate
         self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
 
         connect_nodes(self.nodes[0], 1)
diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py
index 4686a5b1a58..d97eaea2543 100755
--- a/qa/rpc-tests/rawtransactions.py
+++ b/qa/rpc-tests/rawtransactions.py
@@ -115,7 +115,7 @@ def run_test(self):
         #use balance deltas instead of absolute values
         bal = self.nodes[2].getbalance()
 
-        # send 1.2 BTC to msig adr
+        # send 1.2 ZEC to multisig address
         txId       = self.nodes[0].sendtoaddress(mSigObj, 1.2);
         self.sync_all()
         self.nodes[0].generate(1)
diff --git a/qa/rpc-tests/remove_sprout_shielding.py b/qa/rpc-tests/remove_sprout_shielding.py
index 4b807ddae8e..4d9504cb974 100755
--- a/qa/rpc-tests/remove_sprout_shielding.py
+++ b/qa/rpc-tests/remove_sprout_shielding.py
@@ -21,6 +21,7 @@
 import logging
 
 HAS_CANOPY = [
+    '-minrelaytxfee=0',
     '-nurejectoldversions=false',
     '-anchorconfirmations=1',
     nuparams(BLOSSOM_BRANCH_ID, 205),
diff --git a/qa/rpc-tests/shorter_block_times.py b/qa/rpc-tests/shorter_block_times.py
index 103e581773d..f96dc3a53d9 100755
--- a/qa/rpc-tests/shorter_block_times.py
+++ b/qa/rpc-tests/shorter_block_times.py
@@ -23,6 +23,7 @@ def __init__(self):
 
     def setup_nodes(self):
         return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(BLOSSOM_BRANCH_ID, 106),
             '-allowdeprecated=z_getnewaddress',
             '-allowdeprecated=z_gettotalbalance',
diff --git a/qa/rpc-tests/show_help.py b/qa/rpc-tests/show_help.py
index 47f27c1ce24..f58ab0969b1 100755
--- a/qa/rpc-tests/show_help.py
+++ b/qa/rpc-tests/show_help.py
@@ -258,15 +258,22 @@
        Set the Sapling migration address
 
   -mintxfee=<amt>
-       Fees (in ZEC/kB) smaller than this are considered zero fee for
-       transaction creation (default: 0.00001)
+       The fallback fee rate (in ZEC per 1000 bytes) used by legacy APIs
+       (sendtoaddress, sendmany, and fundrawtransaction) when -paytxfee has not
+       been set and there is insufficient mempool data to estimate a fee
+       according to the -txconfirmtarget option (default: 0.00001)
 
   -orchardactionlimit=<n>
        Set the maximum number of Orchard actions permitted in a transaction
        (default 50)
 
   -paytxfee=<amt>
-       Fee (in ZEC/kB) to add to transactions you send (default: 0.00)
+       The preferred fee rate (in ZEC per 1000 bytes) used for transactions
+       created by legacy APIs (sendtoaddress, sendmany, and
+       fundrawtransaction). If the transaction is less than 1000 bytes then the
+       fee rate is applied as though it were 1000 bytes. See the descriptions
+       of -txconfirmtarget and -mintxfee options for how the fee is calculated
+       when this option is not set.
 
   -rescan
        Rescan the block chain for missing wallet transactions on startup
@@ -275,15 +282,15 @@
        Attempt to recover private keys from a corrupt wallet on startup
        (implies -rescan)
 
-  -sendfreetransactions
-       Send transactions as zero-fee transactions if possible (default: 0)
-
   -spendzeroconfchange
        Spend unconfirmed change when sending transactions (default: 1)
 
   -txconfirmtarget=<n>
-       If paytxfee is not set, include enough fee so transactions begin
-       confirmation on average within n blocks (default: 2)
+       If -paytxfee is not set, include enough fee that transactions created by
+       legacy APIs (sendtoaddress, sendmany, and fundrawtransaction) begin
+       confirmation on average within n blocks. This is only used if there is
+       sufficient mempool data to estimate the fee; if not, the fallback fee
+       set by -mintxfee is used. (default: 2)
 
   -txexpirydelta
        Set the number of blocks after which a transaction that has not been
@@ -378,8 +385,9 @@
        Prepend debug output with timestamp (default: 1)
 
   -minrelaytxfee=<amt>
-       Fees (in ZEC/kB) smaller than this are considered zero fee for relaying,
-       mining and transaction creation (default: 0.000001)
+       Transactions must have at least this fee rate (in ZEC per 1000 bytes)
+       for relaying, mining and transaction creation (default: 0.000001). This
+       is not the only fee constraint.
 
   -maxtxfee=<amt>
        Maximum total fees (in ZEC) to use in a single wallet transaction or raw
@@ -411,10 +419,6 @@
   -blockmaxsize=<n>
        Set maximum block size in bytes (default: 2000000)
 
-  -blockprioritysize=<n>
-       Set maximum size of high-priority/low-fee transactions in bytes
-       (default: 1000000)
-
 Mining options:
 
   -gen
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index cb403982928..f2d00c4dd8a 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/qa/rpc-tests/smartfees.py
@@ -78,12 +78,13 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
     return (completetx, fee)
 
 def split_inputs(from_node, txins, txouts, initial_split = False):
-    '''
-    We need to generate a lot of very small inputs so we can generate a ton of transactions
-    and they will have low priority.
+    """
+    We need to generate a lot of inputs so we can generate a ton of transactions.
     This function takes an input from txins, and creates and sends a transaction
     which splits the value into 2 outputs which are appended to txouts.
-    '''
+    Previously this was designed to be small inputs so they wouldn't have
+    a high coin age when the notion of priority still existed.
+    """
     prevtxout = txins.pop()
     inputs = []
     outputs = {}
@@ -150,16 +151,16 @@ def __init__(self):
     def setup_network(self):
         '''
         We'll setup the network to have 3 nodes that all mine with different parameters.
-        But first we need to use one node to create a lot of small low priority outputs
+        But first we need to use one node to create a lot of outputs
         which we will use to generate our transactions.
         '''
         self.nodes = []
         # Use node0 to mine blocks for input splitting
         self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
-                                                              "-relaypriority=0", "-whitelist=127.0.0.1"]))
+                                                              "-whitelist=127.0.0.1"]))
 
         print("This test is time consuming, please be patient")
-        print("Splitting inputs to small size so we can generate low priority tx's")
+        print("Splitting inputs so we can generate tx's")
         self.txouts = []
         self.txouts2 = []
         # Split a coinbase into two transaction puzzle outputs
@@ -188,18 +189,16 @@ def setup_network(self):
 
         # Now we can connect the other nodes, didn't want to connect them earlier
         # so the estimates would not be affected by the splitting transactions
-        # Node1 mines small blocks but that are bigger than the expected transaction rate,
-        # and allows free transactions.
+        # Node1 mines small blocks but that are bigger than the expected transaction rate.
         # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
         # (17k is room enough for 110 or so transactions)
         self.nodes.append(start_node(1, self.options.tmpdir,
-                                     ["-blockprioritysize=1500", "-blockmaxsize=18000",
-                                      "-maxorphantx=1000", "-relaypriority=0", "-debug=estimatefee"]))
+                                     ["-blockmaxsize=18000", "-maxorphantx=1000", "-debug=estimatefee"]))
         connect_nodes(self.nodes[1], 0)
 
         # Node2 is a stingy miner, that
         # produces too small blocks (room for only 70 or so transactions)
-        node2args = ["-blockprioritysize=0", "-blockmaxsize=12000", "-maxorphantx=1000", "-relaypriority=0"]
+        node2args = ["-blockmaxsize=12000", "-maxorphantx=1000"]
 
         self.nodes.append(start_node(2, self.options.tmpdir, node2args))
         connect_nodes(self.nodes[0], 2)
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index 43182526027..216069a46a1 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -190,6 +190,7 @@ def __init__(self):
         super().__init__()
         self.num_nodes = 1
         self.cache_behavior = 'clean'
+        self.additional_args = []
 
     def add_options(self, parser):
         parser.add_option("--testbinary", dest="testbinary",
@@ -202,7 +203,7 @@ def add_options(self, parser):
     def setup_network(self):
         self.nodes = start_nodes(
             self.num_nodes, self.options.tmpdir,
-            extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes,
+            extra_args=[['-debug', '-whitelist=127.0.0.1'] + self.additional_args] * self.num_nodes,
             binary=[self.options.testbinary] +
             [self.options.refbinary]*(self.num_nodes-1))
 
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 143ff902704..e741af8dbe8 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -101,10 +101,10 @@ def rpc_port(n):
     return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
 
 def check_json_precision():
-    """Make sure json library being used does not lose precision converting BTC values"""
+    """Make sure json library being used does not lose precision converting ZEC values"""
     n = Decimal("20000000.00000003")
-    satoshis = int(json.loads(json.dumps(float(n)))*1.0e8)
-    if satoshis != 2000000000000003:
+    zatoshis = int(json.loads(json.dumps(float(n)))*1.0e8)
+    if zatoshis != 2000000000000003:
         raise RuntimeError("JSON encode/decode loses precision")
 
 def bytes_to_hex_str(byte_str):
@@ -552,47 +552,6 @@ def make_change(from_node, amount_in, amount_out, fee):
         outputs[from_node.getnewaddress()] = change
     return outputs
 
-def send_zeropri_transaction(from_node, to_node, amount, fee):
-    """
-    Create&broadcast a zero-priority transaction.
-    Returns (txid, hex-encoded-txdata)
-    Ensures transaction is zero-priority by first creating a send-to-self,
-    then using its output
-    """
-
-    # Create a send-to-self with confirmed inputs:
-    self_address = from_node.getnewaddress()
-    (total_in, inputs) = gather_inputs(from_node, amount+fee*2)
-    outputs = make_change(from_node, total_in, amount+fee, fee)
-    outputs[self_address] = float(amount+fee)
-
-    self_rawtx = from_node.createrawtransaction(inputs, outputs)
-    self_signresult = from_node.signrawtransaction(self_rawtx)
-    self_txid = from_node.sendrawtransaction(self_signresult["hex"], True)
-
-    vout = find_output(from_node, self_txid, amount+fee)
-    # Now immediately spend the output to create a 1-input, 1-output
-    # zero-priority transaction:
-    inputs = [ { "txid" : self_txid, "vout" : vout } ]
-    outputs = { to_node.getnewaddress() : float(amount) }
-
-    rawtx = from_node.createrawtransaction(inputs, outputs)
-    signresult = from_node.signrawtransaction(rawtx)
-    txid = from_node.sendrawtransaction(signresult["hex"], True)
-
-    return (txid, signresult["hex"])
-
-def random_zeropri_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
-    """
-    Create a random zero-priority transaction.
-    Returns (txid, hex-encoded-transaction-data, fee)
-    """
-    from_node = random.choice(nodes)
-    to_node = random.choice(nodes)
-    fee = min_fee + fee_increment*random.randint(0,fee_variants)
-    (txid, txhex) = send_zeropri_transaction(from_node, to_node, amount, fee)
-    return (txid, txhex, fee)
-
 def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
     """
     Create a random transaction.
diff --git a/qa/rpc-tests/turnstile.py b/qa/rpc-tests/turnstile.py
index 47441a22119..56384d73a4b 100755
--- a/qa/rpc-tests/turnstile.py
+++ b/qa/rpc-tests/turnstile.py
@@ -41,6 +41,7 @@
 from decimal import Decimal
 
 BASE_ARGS = [
+    '-minrelaytxfee=0',
     '-allowdeprecated=z_getnewaddress',
     '-allowdeprecated=z_getbalance',
 ]
diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py
index 3f24b03a70e..3e55edb4a90 100755
--- a/qa/rpc-tests/txn_doublespend.py
+++ b/qa/rpc-tests/txn_doublespend.py
@@ -26,6 +26,7 @@ def add_options(self, parser):
 
     def setup_nodes(self):
         return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=getnewaddress',
         ]] * self.num_nodes)
 
@@ -44,7 +45,7 @@ def run_test(self):
         # Coins are sent to node1_address
         node1_address = self.nodes[1].getnewaddress("")
 
-        # First: use raw transaction API to send (starting_balance - (mining_reward - 2)) BTC to node1_address,
+        # First: use raw transaction API to send (starting_balance - (mining_reward - 2)) ZEC to node1_address,
         # but don't broadcast:
         (total_in, inputs) = gather_inputs(self.nodes[0], (starting_balance - (mining_reward - 2)))
         change_address = self.nodes[0].getnewaddress("")
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 97dc5083870..3d47fe630f6 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -20,6 +20,7 @@ def __init__(self):
 
     def setup_network(self, split=False):
         self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=z_getbalance',
         ]] * 3)
diff --git a/qa/rpc-tests/wallet_accounts.py b/qa/rpc-tests/wallet_accounts.py
index 140f1050f39..bf5f657e4b3 100755
--- a/qa/rpc-tests/wallet_accounts.py
+++ b/qa/rpc-tests/wallet_accounts.py
@@ -22,7 +22,8 @@
 # Test wallet accounts behaviour
 class WalletAccountsTest(BitcoinTestFramework):
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 210),
             '-allowdeprecated=z_getnewaddress',
             '-allowdeprecated=z_getbalance',
diff --git a/qa/rpc-tests/wallet_changeaddresses.py b/qa/rpc-tests/wallet_changeaddresses.py
index 61b66b45a2e..4f8e12ae8ab 100755
--- a/qa/rpc-tests/wallet_changeaddresses.py
+++ b/qa/rpc-tests/wallet_changeaddresses.py
@@ -25,6 +25,7 @@ def setup_chain(self):
 
     def setup_network(self):
         args = [
+            '-minrelaytxfee=0',
             nuparams(SAPLING_BRANCH_ID, 1),
             '-txindex',              # Avoid JSONRPC error: No information available about transaction
             '-allowdeprecated=getnewaddress',
diff --git a/qa/rpc-tests/wallet_changeindicator.py b/qa/rpc-tests/wallet_changeindicator.py
index 3e70ef1aec3..bf289ac8601 100755
--- a/qa/rpc-tests/wallet_changeindicator.py
+++ b/qa/rpc-tests/wallet_changeindicator.py
@@ -23,6 +23,7 @@ def generate_and_sync(self):
 
     def setup_nodes(self):
         return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=z_getnewaddress',
         ]] * self.num_nodes)
diff --git a/qa/rpc-tests/wallet_doublespend.py b/qa/rpc-tests/wallet_doublespend.py
index 4654b58ed52..868f706affa 100755
--- a/qa/rpc-tests/wallet_doublespend.py
+++ b/qa/rpc-tests/wallet_doublespend.py
@@ -25,7 +25,8 @@ def __init__(self):
         self.num_nodes = 4
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 201),
         ]] * self.num_nodes)
 
diff --git a/qa/rpc-tests/wallet_isfromme.py b/qa/rpc-tests/wallet_isfromme.py
index 70d09062d28..c38c95be02a 100755
--- a/qa/rpc-tests/wallet_isfromme.py
+++ b/qa/rpc-tests/wallet_isfromme.py
@@ -26,6 +26,7 @@ def setup_chain(self):
 
     def setup_network(self, split=False):
         self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(OVERWINTER_BRANCH_ID, 1),
             nuparams(SAPLING_BRANCH_ID, 1),
             nuparams(BLOSSOM_BRANCH_ID, 1),
diff --git a/qa/rpc-tests/wallet_listnotes.py b/qa/rpc-tests/wallet_listnotes.py
index cbc7898f645..065005bd996 100755
--- a/qa/rpc-tests/wallet_listnotes.py
+++ b/qa/rpc-tests/wallet_listnotes.py
@@ -24,7 +24,8 @@ def __init__(self):
         self.cache_behavior = 'sprout'
 
     def setup_nodes(self):
-        return start_nodes(4, self.options.tmpdir, [[
+        return start_nodes(4, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 215),
             '-allowdeprecated=z_getnewaddress',
             '-allowdeprecated=z_getbalance',
diff --git a/qa/rpc-tests/wallet_listreceived.py b/qa/rpc-tests/wallet_listreceived.py
index 22fcbb63e21..c39786b0ab5 100755
--- a/qa/rpc-tests/wallet_listreceived.py
+++ b/qa/rpc-tests/wallet_listreceived.py
@@ -32,14 +32,13 @@ def __init__(self):
         self.cache_behavior = 'clean'
 
     def setup_network(self):
-        self.nodes = start_nodes(
-            self.num_nodes, self.options.tmpdir,
-            extra_args=[[
-                nuparams(NU5_BRANCH_ID, 225),
-                '-allowdeprecated=getnewaddress',
-                '-allowdeprecated=z_getnewaddress',
-            ]] * self.num_nodes
-            )
+        self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
+            nuparams(NU5_BRANCH_ID, 225),
+            '-allowdeprecated=getnewaddress',
+            '-allowdeprecated=z_getnewaddress',
+        ]] * self.num_nodes)
+
         connect_nodes_bi(self.nodes, 0, 1)
         connect_nodes_bi(self.nodes, 1, 2)
         connect_nodes_bi(self.nodes, 0, 2)
diff --git a/qa/rpc-tests/wallet_listunspent.py b/qa/rpc-tests/wallet_listunspent.py
index 924c49df5d3..c0c2255f9d3 100755
--- a/qa/rpc-tests/wallet_listunspent.py
+++ b/qa/rpc-tests/wallet_listunspent.py
@@ -20,7 +20,8 @@ def unspent_total(unspent):
 
 class WalletListUnspent(BitcoinTestFramework):
     def setup_nodes(self):
-        return start_nodes(4, self.options.tmpdir, [[
+        return start_nodes(4, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 201),
             '-allowdeprecated=getnewaddress',
         ]] * 4)
diff --git a/qa/rpc-tests/wallet_orchard.py b/qa/rpc-tests/wallet_orchard.py
index 8122b268c3f..01c27fcd3fb 100755
--- a/qa/rpc-tests/wallet_orchard.py
+++ b/qa/rpc-tests/wallet_orchard.py
@@ -22,7 +22,8 @@ def __init__(self):
         self.num_nodes = 4
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 210),
         ]] * self.num_nodes)
 
diff --git a/qa/rpc-tests/wallet_orchard_change.py b/qa/rpc-tests/wallet_orchard_change.py
index bded746143d..fb4487b48ab 100755
--- a/qa/rpc-tests/wallet_orchard_change.py
+++ b/qa/rpc-tests/wallet_orchard_change.py
@@ -22,7 +22,8 @@ def __init__(self):
         self.num_nodes = 4
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 205),
             '-regtestwalletsetbestchaineveryblock',
         ]] * self.num_nodes)
diff --git a/qa/rpc-tests/wallet_orchard_init.py b/qa/rpc-tests/wallet_orchard_init.py
index b5db9f4e10d..75d7746f8c0 100755
--- a/qa/rpc-tests/wallet_orchard_init.py
+++ b/qa/rpc-tests/wallet_orchard_init.py
@@ -27,7 +27,8 @@ def __init__(self):
         self.num_nodes = 4
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 205),
             '-regtestwalletsetbestchaineveryblock'
         ]] * self.num_nodes)
diff --git a/qa/rpc-tests/wallet_orchard_persistence.py b/qa/rpc-tests/wallet_orchard_persistence.py
index f27a9444289..99470dccb60 100755
--- a/qa/rpc-tests/wallet_orchard_persistence.py
+++ b/qa/rpc-tests/wallet_orchard_persistence.py
@@ -24,7 +24,8 @@ def __init__(self):
         self.num_nodes = 4
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 201),
         ]] * self.num_nodes)
 
diff --git a/qa/rpc-tests/wallet_orchard_reindex.py b/qa/rpc-tests/wallet_orchard_reindex.py
index c1a3a9686eb..a9a60b223c4 100755
--- a/qa/rpc-tests/wallet_orchard_reindex.py
+++ b/qa/rpc-tests/wallet_orchard_reindex.py
@@ -21,6 +21,7 @@
 import time
 
 BASE_ARGS = [
+    '-minrelaytxfee=0',
     nuparams(NU5_BRANCH_ID, 210),
     '-regtestwalletsetbestchaineveryblock',
 ]
diff --git a/qa/rpc-tests/wallet_persistence.py b/qa/rpc-tests/wallet_persistence.py
index f0b9f8be875..74085e6b069 100755
--- a/qa/rpc-tests/wallet_persistence.py
+++ b/qa/rpc-tests/wallet_persistence.py
@@ -22,6 +22,7 @@ def setup_chain(self):
 
     def setup_network(self, split=False):
         self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=z_getnewaddress',
             '-allowdeprecated=z_getbalance',
             '-allowdeprecated=z_gettotalbalance',
diff --git a/qa/rpc-tests/wallet_sapling.py b/qa/rpc-tests/wallet_sapling.py
index aa772d7932b..f95569c7393 100755
--- a/qa/rpc-tests/wallet_sapling.py
+++ b/qa/rpc-tests/wallet_sapling.py
@@ -19,6 +19,7 @@ class WalletSaplingTest(BitcoinTestFramework):
 
     def setup_nodes(self):
         return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=z_getnewaddress',
             '-allowdeprecated=z_getbalance',
@@ -54,10 +55,6 @@ def run_test(self):
 
         self.sync_all()
 
-        # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000)
-        mempool = self.nodes[0].getrawmempool(True)
-        assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16'))
-
         # Shield another coinbase UTXO
         myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
         mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
@@ -80,11 +77,6 @@ def run_test(self):
         mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
 
         self.sync_all()
-
-        # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000)
-        mempool = self.nodes[0].getrawmempool(True)
-        assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16'))
-
         self.nodes[2].generate(1)
         self.sync_all()
 
@@ -104,11 +96,6 @@ def run_test(self):
         mytxid = wait_and_assert_operationid_status(self.nodes[1], myopid)
 
         self.sync_all()
-
-        # Verify priority of tx is MAX_PRIORITY, defined as 1E+16 (10000000000000000)
-        mempool = self.nodes[1].getrawmempool(True)
-        assert(Decimal(mempool[mytxid]['startingpriority']) == Decimal('1E+16'))
-
         self.nodes[2].generate(1)
         self.sync_all()
 
diff --git a/qa/rpc-tests/wallet_sendmany_any_taddr.py b/qa/rpc-tests/wallet_sendmany_any_taddr.py
index d81ee6c598b..64df0b66249 100755
--- a/qa/rpc-tests/wallet_sendmany_any_taddr.py
+++ b/qa/rpc-tests/wallet_sendmany_any_taddr.py
@@ -19,13 +19,13 @@
 # Test ANY_TADDR special string in z_sendmany
 class WalletSendManyAnyTaddr(BitcoinTestFramework):
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir,
-            [[
-                "-txexpirydelta=%d" % TX_EXPIRY_DELTA,
-                "-allowdeprecated=getnewaddress",
-                "-allowdeprecated=z_getnewaddress",
-                "-allowdeprecated=z_getbalance",
-            ]] * self.num_nodes)
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
+            '-txexpirydelta=%d' % TX_EXPIRY_DELTA,
+            '-allowdeprecated=getnewaddress',
+            '-allowdeprecated=z_getnewaddress',
+            '-allowdeprecated=z_getbalance',
+        ]] * self.num_nodes)
 
     def run_test(self):
         # Sanity-check the test harness
diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py
index b9a87470ccc..61aedd8411e 100755
--- a/qa/rpc-tests/wallet_shieldcoinbase.py
+++ b/qa/rpc-tests/wallet_shieldcoinbase.py
@@ -19,6 +19,7 @@ def setup_chain(self):
 
     def setup_network(self, split=False):
         args = [
+            '-minrelaytxfee=0',
             '-regtestprotectcoinbase',
             '-debug=zrpcunsafe',
             nuparams(NU5_BRANCH_ID, self.nu5_activation),
diff --git a/qa/rpc-tests/wallet_shieldingcoinbase.py b/qa/rpc-tests/wallet_shieldingcoinbase.py
index ab9f1fadba0..390238b46f1 100755
--- a/qa/rpc-tests/wallet_shieldingcoinbase.py
+++ b/qa/rpc-tests/wallet_shieldingcoinbase.py
@@ -36,6 +36,7 @@ def setup_chain(self):
     # Start nodes with -regtestshieldcoinbase to set fCoinbaseMustBeShielded to true.
     def setup_network(self, split=False):
         self.nodes = start_nodes(4, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-regtestshieldcoinbase',
             '-debug=zrpcunsafe',
             '-allowdeprecated=getnewaddress',
@@ -210,12 +211,8 @@ def run_test (self):
         myopid = self.nodes[0].z_sendmany(myzaddr, recipients, 1, DEFAULT_FEE, 'AllowRevealedRecipients')
         mytxid = wait_and_assert_operationid_status(self.nodes[0], myopid)
         assert(mytxid is not None)
-        self.sync_all()
-
-        # check that priority of the tx sending from a zaddr is not 0
-        mempool = self.nodes[0].getrawmempool(True)
-        assert(Decimal(mempool[mytxid]['startingpriority']) >= Decimal('1000000000000'))
 
+        self.sync_all()
         self.nodes[1].generate(1)
         self.sync_all()
 
diff --git a/qa/rpc-tests/wallet_treestate.py b/qa/rpc-tests/wallet_treestate.py
index 4fa1a245ccd..29f65b4922c 100755
--- a/qa/rpc-tests/wallet_treestate.py
+++ b/qa/rpc-tests/wallet_treestate.py
@@ -21,6 +21,7 @@ def setup_chain(self):
     # Start nodes with -regtestshieldcoinbase to set fCoinbaseMustBeShielded to true.
     def setup_network(self, split=False):
         self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-regtestshieldcoinbase',
             '-debug=zrpc',
             '-allowdeprecated=z_getnewaddress',
diff --git a/qa/rpc-tests/wallet_unified_change.py b/qa/rpc-tests/wallet_unified_change.py
index 1384d642d49..5c618c3e33a 100755
--- a/qa/rpc-tests/wallet_unified_change.py
+++ b/qa/rpc-tests/wallet_unified_change.py
@@ -22,7 +22,8 @@ def __init__(self):
         self.num_nodes = 4
 
     def setup_nodes(self):
-        return start_nodes(self.num_nodes, self.options.tmpdir, [[
+        return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 201),
         ]] * self.num_nodes)
 
diff --git a/qa/rpc-tests/wallet_z_sendmany.py b/qa/rpc-tests/wallet_z_sendmany.py
index 7dc57757cab..42efdb79dc7 100755
--- a/qa/rpc-tests/wallet_z_sendmany.py
+++ b/qa/rpc-tests/wallet_z_sendmany.py
@@ -27,7 +27,8 @@ def __init__(self):
         self.cache_behavior = 'sprout'
 
     def setup_network(self, split=False):
-        self.nodes = start_nodes(3, self.options.tmpdir, [[
+        self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             nuparams(NU5_BRANCH_ID, 238),
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=z_getnewaddress',
diff --git a/qa/rpc-tests/zkey_import_export.py b/qa/rpc-tests/zkey_import_export.py
index 3525c336dd8..b29fbac90ed 100755
--- a/qa/rpc-tests/zkey_import_export.py
+++ b/qa/rpc-tests/zkey_import_export.py
@@ -24,6 +24,7 @@ def setup_chain(self):
 
     def setup_network(self, split=False):
         self.nodes = start_nodes(5, self.options.tmpdir, extra_args=[[
+            '-minrelaytxfee=0',
             '-allowdeprecated=getnewaddress',
             '-allowdeprecated=z_getnewaddress',
             '-allowdeprecated=z_getbalance',
diff --git a/src/gtest/test_mempool.cpp b/src/gtest/test_mempool.cpp
index f83bd4aa93a..2fe80c7f79e 100644
--- a/src/gtest/test_mempool.cpp
+++ b/src/gtest/test_mempool.cpp
@@ -113,14 +113,11 @@ TEST(Mempool, PriorityStatsDoNotCrash) {
     CAmount nFees = 0;
     int64_t nTime = 0x58e5fed9;
     unsigned int nHeight = 92045;
-    double dPriority = view.GetPriority(tx, nHeight);
 
-    CTxMemPoolEntry entry(tx, nFees, nTime, dPriority, nHeight, true, false, 0, SPROUT_BRANCH_ID);
+    CTxMemPoolEntry entry(tx, nFees, nTime, nHeight, true, false, 0, SPROUT_BRANCH_ID);
 
     // Check it does not crash (ie. the death test fails)
     EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(testPool.addUnchecked(tx.GetHash(), entry), ""), "");
-
-    EXPECT_EQ(dPriority, MAX_PRIORITY);
 }
 
 // Valid overwinter v3 format tx gets rejected because overwinter hasn't activated yet.
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 20ae5bea7b1..66ab933ad9b 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -127,28 +127,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
     tx1.vout.resize(1);
     tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     tx1.vout[0].nValue = 10 * COIN;
-    pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
+    pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
 
     /* highest fee */
     CMutableTransaction tx2 = CMutableTransaction();
     tx2.vout.resize(1);
     tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     tx2.vout[0].nValue = 2 * COIN;
-    pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
+    pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
 
     /* lowest fee */
     CMutableTransaction tx3 = CMutableTransaction();
     tx3.vout.resize(1);
     tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     tx3.vout[0].nValue = 5 * COIN;
-    pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
+    pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
 
     /* 2nd highest fee */
     CMutableTransaction tx4 = CMutableTransaction();
     tx4.vout.resize(1);
     tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     tx4.vout[0].nValue = 6 * COIN;
-    pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
+    pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
 
     /* equal fee rate to tx1, but newer */
     CMutableTransaction tx5 = CMutableTransaction();
@@ -156,7 +156,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
     tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     tx5.vout[0].nValue = 11 * COIN;
     entry.nTime = 1;
-    entry.dPriority = 10.0;
     pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
     BOOST_CHECK_EQUAL(pool.size(), 5);
 
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index fab302b63d7..f3ca8cea42f 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -161,7 +161,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
     uint256 hash;
     TestMemPoolEntryHelper entry;
     entry.nFee = 11;
-    entry.dPriority = 111.0;
     entry.nHeight = 11;
 
     LOCK(cs_main);
@@ -350,11 +349,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
 
     // orphan in mempool, template creation fails
     hash = tx.GetHash();
-    mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
+    mempool.addUnchecked(hash, entry.Fee(HIGHFEE).Time(GetTime()).FromTx(tx));
     BOOST_CHECK_EXCEPTION(BlockAssembler(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, err_is("bad-txns-inputs-missingorspent"));
     mempool.clear();
 
-    // child with higher priority than parent
+    // child with higher feerate than parent
     tx.vin[0].scriptSig = CScript() << OP_1;
     tx.vin[0].prevout.hash = txFirst[1]->GetHash();
     tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 8b833c24ed2..add0215a367 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -19,26 +19,18 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     CTxMemPool mpool(CFeeRate(1000));
     TestMemPoolEntryHelper entry;
     CAmount basefee(2000);
-    double basepri = 1e6;
     CAmount deltaFee(100);
-    double deltaPri=5e5;
-    std::vector<CAmount> feeV[2];
-    std::vector<double> priV[2];
+    std::vector<CAmount> feeV;
 
-    // Populate vectors of increasing fees or priorities
+    // Populate vectors of increasing fees
     for (int j = 0; j < 10; j++) {
-        //V[0] is for fee transactions
-        feeV[0].push_back(basefee * (j+1));
-        priV[0].push_back(0);
-        //V[1] is for priority transactions
-        feeV[1].push_back(CAmount(0));
-        priV[1].push_back(basepri * pow(10, j+1));
+        feeV.push_back(basefee * (j+1));
     }
 
     // Store the hashes of transactions that have been
-    // added to the mempool by their associate fee/pri
+    // added to the mempool by their associate fee
     // txHashes[j] is populated with transactions either of
-    // fee = basefee * (j+1)  OR  pri = 10^6 * 10^(j+1)
+    // fee = basefee * (j+1)
     std::vector<uint256> txHashes[10];
 
     // Create a transaction template
@@ -61,19 +53,19 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     // At a decay .998 and 4 fee transactions per block
     // This makes the tx count about 1.33 per bucket, above the 1 threshold
     while (blocknum < 200) {
-        for (int j = 0; j < 10; j++) { // For each fee/pri multiple
-            for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+        for (int j = 0; j < 10; j++) { // For each fee
+            for (int k = 0; k < 4; k++) { // add 4 fee txs
                 tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
                 uint256 hash = tx.GetHash();
-                mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool));
+                mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx, &mpool));
                 txHashes[j].push_back(hash);
             }
         }
-        //Create blocks where higher fee/pri txs are included more often
+        //Create blocks where higher fee txs are included more often
         for (int h = 0; h <= blocknum%10; h++) {
-            // 10/10 blocks add highest fee/pri transactions
+            // 10/10 blocks add highest fee transactions
             // 9/10 blocks add 2nd highest and so on until ...
-            // 1/10 blocks add lowest fee/pri transactions
+            // 1/10 blocks add lowest fee transactions
             while (txHashes[9-h].size()) {
                 std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[9-h].back());
                 if (ptx)
@@ -94,7 +86,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     }
 
     std::vector<CAmount> origFeeEst;
-    std::vector<double> origPriEst;
     // Highest feerate is 10*baseRate and gets in all blocks,
     // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
     // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
@@ -103,15 +94,11 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     // so estimateFee(2) should return 8*baseRate etc...
     for (int i = 1; i < 10;i++) {
         origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
-        origPriEst.push_back(mpool.estimatePriority(i));
         if (i > 1) { // Fee estimates should be monotonically decreasing
             BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
-            BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]);
         }
         BOOST_CHECK(origFeeEst[i-1] < (10-i)*baseRate.GetFeePerK() + deltaFee);
         BOOST_CHECK(origFeeEst[i-1] > (10-i)*baseRate.GetFeePerK() - deltaFee);
-        BOOST_CHECK(origPriEst[i-1] < pow(10,10-i) * basepri + deltaPri);
-        BOOST_CHECK(origPriEst[i-1] > pow(10,10-i) * basepri - deltaPri);
     }
 
     // Mine 50 more blocks with no transactions happening, estimates shouldn't change
@@ -122,19 +109,17 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     for (int i = 1; i < 10;i++) {
         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
-        BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri);
-        BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
     }
 
 
     // Mine 15 more blocks with lots of transactions happening and not getting mined
     // Estimates should go up
     while (blocknum < 265) {
-        for (int j = 0; j < 10; j++) { // For each fee/pri multiple
-            for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+        for (int j = 0; j < 10; j++) { // For each fee multiple
+            for (int k = 0; k < 4; k++) { // add 4 fee txs
                 tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
                 uint256 hash = tx.GetHash();
-                mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool));
+                mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx, &mpool));
                 txHashes[j].push_back(hash);
             }
         }
@@ -143,7 +128,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
 
     for (int i = 1; i < 10;i++) {
         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
-        BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
     }
 
     // Mine all those transactions
@@ -160,20 +144,20 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     block.clear();
     for (int i = 1; i < 10;i++) {
         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
-        BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
     }
 
     // Mine 100 more blocks where everything is mined every block
     // Estimates should be below original estimates (not possible for last estimate)
     while (blocknum < 365) {
-        for (int j = 0; j < 10; j++) { // For each fee/pri multiple
-            for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+        for (int j = 0; j < 10; j++) { // For each fee multiple
+            for (int k = 0; k < 4; k++) { // add 4 fee txs
                 tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
                 uint256 hash = tx.GetHash();
-                mpool.addUnchecked(hash, entry.Fee(feeV[k/4][j]).Time(GetTime()).Priority(priV[k/4][j]).Height(blocknum).FromTx(tx, &mpool));
+                mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx, &mpool));
                 std::shared_ptr<const CTransaction> ptx = mpool.get(hash);
                 if (ptx)
                     block.push_back(*ptx);
+
             }
         }
         mpool.removeForBlock(block, ++blocknum, dummyConflicted);
@@ -181,7 +165,6 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
     }
     for (int i = 1; i < 9; i++) {
         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
-        BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri);
     }
 }
 
@@ -191,7 +174,7 @@ BOOST_AUTO_TEST_CASE(TxConfirmStats_FindBucketIndex)
     std::vector<double> buckets {0.0, 3.5, 42.0};
     TxConfirmStats txcs;
 
-    txcs.Initialize(buckets, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "Test");
+    txcs.Initialize(buckets, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY);
 
     BOOST_CHECK_EQUAL(txcs.FindBucketIndex(-1.0), 0);
     BOOST_CHECK_EQUAL(txcs.FindBucketIndex(0.0), 0);
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 9befebe9675..9e220058e48 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
     // Invalid, trailing garbage
     BOOST_CHECK(!ParseNonRFCJSONValue("1.0sds").has_value());
     BOOST_CHECK(!ParseNonRFCJSONValue("1.0]").has_value());
-    // BTC addresses should fail parsing
+    // Bitcoin addresses should fail parsing
     BOOST_CHECK(!ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W").has_value());
     BOOST_CHECK(!ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL").has_value());
 }
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 715a9ec1bc4..3b76e0bd3fc 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -231,7 +231,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPo
     CTransaction txn(tx);
     bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies;
 
-    return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
+    return CTxMemPoolEntry(txn, nFee, nTime, nHeight,
                            hasNoDependencies, spendsCoinbase, sigOpCount, nBranchId);
 }
 
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 4c1c060dfcc..9b3c1da6c71 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -86,7 +86,6 @@ struct TestMemPoolEntryHelper
     // Default values
     CAmount nFee;
     int64_t nTime;
-    double dPriority;
     unsigned int nHeight;
     bool hadNoDependencies;
     bool spendsCoinbase;
@@ -94,7 +93,7 @@ struct TestMemPoolEntryHelper
     uint32_t nBranchId;
 
     TestMemPoolEntryHelper() :
-        nFee(0), nTime(0), dPriority(0.0), nHeight(1),
+        nFee(0), nTime(0), nHeight(1),
         hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1),
         nBranchId(SPROUT_BRANCH_ID) { }
 
@@ -103,7 +102,6 @@ struct TestMemPoolEntryHelper
     // Change the default value
     TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
     TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; }
-    TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
     TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
     TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; }
     TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index e1c46898473..ea9ac0cafa0 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -690,8 +690,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
     string reason;
     BOOST_CHECK(IsStandardTx(t, reason, chainparams));
 
-    // Check dust with default relay fee:
-    CAmount nDustThreshold = 182 * minRelayTxFee.GetFeePerK()/1000 * 3;
+    // Check dust threshold:
+    CFeeRate oneThirdDustThresholdRate{ONE_THIRD_DUST_THRESHOLD_RATE};
+    CAmount nDustThreshold = (34 + 148) * oneThirdDustThresholdRate.GetFeePerK()/1000 * 3;
     BOOST_CHECK_EQUAL(nDustThreshold, 54);
     // dust:
     t.vout[0].nValue = nDustThreshold - 1;
@@ -700,17 +701,6 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
     t.vout[0].nValue = nDustThreshold;
     BOOST_CHECK(IsStandardTx(t, reason, chainparams));
 
-    // Check dust with odd relay fee to verify rounding:
-    // nDustThreshold = 182 * 1234 / 1000 * 3
-    minRelayTxFee = CFeeRate(1234);
-    // dust:
-    t.vout[0].nValue = 672 - 1;
-    BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
-    // not dust:
-    t.vout[0].nValue = 672;
-    BOOST_CHECK(IsStandardTx(t, reason, chainparams));
-    minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
-
     t.vout[0].scriptPubKey = CScript() << OP_1;
     BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
 
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 23008e505bb..9b98126c798 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -175,11 +175,11 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
         add_coin( 3*COIN);
         add_coin( 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
         BOOST_CHECK( CWallet::SelectCoinsMinConf(95 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
-        BOOST_CHECK_EQUAL(nValueRet, 1 * COIN);  // we should get 1 BTC in 1 coin
+        BOOST_CHECK_EQUAL(nValueRet, 1 * COIN);  // we should get 1 ZEC in 1 coin
         BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
 
         BOOST_CHECK( CWallet::SelectCoinsMinConf(195 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
-        BOOST_CHECK_EQUAL(nValueRet, 2 * COIN);  // we should get 2 BTC in 1 coin
+        BOOST_CHECK_EQUAL(nValueRet, 2 * COIN);  // we should get 2 ZEC in 1 coin
         BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
 
         // empty the wallet and start again, now with fractions of a cent, to test small change avoidance