Skip to content

Commit 8ffe5aa

Browse files
JBetzMixa84
authored andcommitted
Interpret fee rates in reference fee unit (#21)
* Introduce CValue for distinguishing amounts from values * Remove random character * Define insertion operator for CValue * Move CValue to separate module * Remove consensus changes * Remove CValue usage for fee rates, restrict to mempool * More cleanup * Use CValue for descendant and ancestor fee updates * More mempool fixes * Remove unused include * Fix variable shadowing * More conversions * Factor in fee asset when validating package fees * More conversions * Convert dust relay fee from RFU * More cleanup * Cleanup * Don't factor in asset in when calculating dust threshold * Convert package fees * Return CValue from CalculateExchangeValue * Use CValue for reverse exchange rate conversion * Update method documentation * Rename currency conversion methods * Fix typo * Add justification for RFU to comments * Use accessor instead of public instance variable unpacking CValue * Use GetValue() in fee rate conversion * Only apply dust check to outputs denominated in same asset as fee * Interpret coin selection effective feerate in RFU * Change GetModifiedFee() method to use RFU for summing with ancestor and descendant transactions * Add functional test for "fee_rate" parameter in fundrawtransaction RPC and -mintxfee node configuration parameter * Normalize fees to RFU during fee estimation * Lint fixes * More linting fixes * More linting * Apply method renams to fee amount conversions * Add any asset fee rates test to test runner * More amount conversion fixes * Add compiler switch for currency constants * Add new configuration flag to documentation * Apply fixes to fee estimation functional test from ElementsProject/elements#1298 * Add tests for paytxfee parameter * Cleanup * Fix compiler flag * Add tests for blockmintxfee * Remove whitespace * Add comments clarifying what's being demonstrated * Remove nFeeValue, recompute as needed * Revert "Remove nFeeValue, recompute as needed" This reverts commit ab3a67b. * Move No Coin configuration documentation to separate line * Add constant for full name of currency atom * Fix constant reference * Fix typo
1 parent d3b073e commit 8ffe5aa

25 files changed

+384
-86
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ To speed up the build if not necessary, disable bench and tests in configure:
3636
```bash
3737
./configure --without-gui --without-natpmp --without-miniupnpc --disable-bench --disable-tests
3838
```
39+
To configure RPC documentation to denominate fee rates using RFU and rfa instead of BTC and sat:
40+
```bash
41+
./configure --enable-any-asset-fees
42+
```
3943

4044
Modes
4145
-----
@@ -106,4 +110,3 @@ https://github.com/ElementsProject/elementsproject.github.io
106110
Secure Reporting
107111
------------------
108112
See [our vulnerability reporting guide](SECURITY.md)
109-

configure.ac

+13
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,24 @@ AC_ARG_ENABLE([liquid],
266266
[liquid_build=yes],
267267
[liquid_build=no])
268268

269+
AC_ARG_ENABLE([any_asset_fees],
270+
[AS_HELP_STRING([--enable-any-asset-fees],
271+
[Enable build that uses constants for any asset fees feature])],
272+
[any_asset_fees=yes],
273+
[any_asset_fees=no])
274+
269275
if test "$use_asm" = "yes"; then
270276
AC_DEFINE([USE_ASM], [1], [Define this symbol to build in assembly routines])
271277
fi
272278

273279
if test "$liquid_build" = "yes"; then
274280
AC_DEFINE(LIQUID, 1, [Define this symbol for Liquid builds])
275281
fi
282+
283+
if test "$any_asset_fees" = "yes"; then
284+
AC_DEFINE(ANY_ASSET_FEES, 1, [Define this symbol to modify constants for any asset fees feature])
285+
fi
286+
276287
AC_ARG_ENABLE([zmq],
277288
[AS_HELP_STRING([--disable-zmq],
278289
[disable ZMQ notifications])],
@@ -1833,6 +1844,7 @@ AM_CONDITIONAL([WORDS_BIGENDIAN], [test "$ac_cv_c_bigendian" = "yes"])
18331844
AM_CONDITIONAL([USE_NATPMP], [test "$use_natpmp" = "yes"])
18341845
AM_CONDITIONAL([USE_UPNP], [test "$use_upnp" = "yes"])
18351846
AM_CONDITIONAL([LIQUID], [test "$liquid_build" = "yes"])
1847+
AM_CONDITIONAL([ANY_ASSET_FEES], [test "$any_asset_fees" = "yes"])
18361848

18371849
dnl for minisketch
18381850
AM_CONDITIONAL([ENABLE_CLMUL], [test "$enable_clmul" = "yes"])
@@ -1986,6 +1998,7 @@ echo " with upnp = $use_upnp"
19861998
echo " with natpmp = $use_natpmp"
19871999
echo " use asm = $use_asm"
19882000
echo " liquid_build = $liquid_build"
2001+
echo " any_asset_fees = $any_asset_fees"
19892002
echo " USDT tracing = $use_usdt"
19902003
echo " sanitizers = $use_sanitizers"
19912004
echo " debug enabled = $enable_debug"

src/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ BITCOIN_CORE_H = \
209209
policy/policy.h \
210210
policy/rbf.h \
211211
policy/settings.h \
212+
policy/value.h \
212213
pow.h \
213214
primitives/pak.h \
214215
protocol.h \

src/exchangerates.cpp

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,40 @@
11
#include <assetsdir.h>
22
#include <exchangerates.h>
33
#include <policy/policy.h>
4+
#include <policy/value.h>
45
#include <util/settings.h>
56
#include <util/system.h>
67
#include <univalue.h>
78

89
#include <fstream>
910

10-
CAmount ExchangeRateMap::CalculateExchangeValue(const CAmount& amount, const CAsset& asset) {
11+
CValue ExchangeRateMap::ConvertAmountToValue(const CAmount& amount, const CAsset& asset) {
12+
int64_t int64_max = std::numeric_limits<int64_t>::max();
1113
auto it = this->find(asset);
1214
if (it == this->end()) {
13-
return 0;
15+
return CValue(0);
1416
}
1517
auto scaled_value = it->second.m_scaled_value;
16-
__uint128_t value = ((__uint128_t)amount * (__uint128_t)scaled_value) / (__uint128_t)exchange_rate_scale;
18+
__uint128_t result = ((__uint128_t)amount * (__uint128_t)scaled_value) / (__uint128_t)exchange_rate_scale;
19+
if (result > int64_max) {
20+
return CValue(int64_max);
21+
} else {
22+
return CValue((int64_t) result);
23+
}
24+
}
25+
26+
CAmount ExchangeRateMap::ConvertValueToAmount(const CValue& value, const CAsset& asset) {
1727
int64_t int64_max = std::numeric_limits<int64_t>::max();
18-
if (value > int64_max) {
28+
auto it = this->find(asset);
29+
if (it == this->end()) {
30+
return int64_max;
31+
}
32+
auto scaled_value = it->second.m_scaled_value;
33+
__uint128_t result = ((__uint128_t)value.GetValue() * (__uint128_t)exchange_rate_scale) / (__uint128_t)scaled_value;
34+
if (result > int64_max) {
1935
return int64_max;
2036
} else {
21-
return (int64_t) value;
37+
return (int64_t) result;
2238
}
2339
}
2440

src/exchangerates.h

+16-6
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
#include <fs.h>
55
#include <policy/policy.h>
6+
#include <policy/value.h>
67
#include <univalue.h>
78

8-
constexpr const CAmount exchange_rate_scale = COIN;
9+
constexpr const CAmount exchange_rate_scale = COIN; // 100,000,000
910
const std::string exchange_rates_config_file = "exchangerates.json";
1011

1112
class CAssetExchangeRate
@@ -33,15 +34,24 @@ class ExchangeRateMap : public std::map<CAsset, CAssetExchangeRate>
3334
}
3435

3536
/**
36-
* Calculate the exchange value
37+
* Convert an amount denominated in some asset to the node's RFU (reference fee unit)
3738
*
38-
* @param[in] amount Corresponds to CTxMemPoolEntry.nFeeAmount
39+
* @param[in] amount Corresponds to CTxMemPoolEntry.nFee
3940
* @param[in] asset Corresponds to CTxMemPoolEntry.nFeeAsset
40-
* @return the value at current exchange rate. Corresponds to CTxMemPoolEntry.nFee
41+
* @return the value at current exchange rate. Corresponds to CTxMemPoolEntry.nFeeValue
4142
*/
42-
CAmount CalculateExchangeValue(const CAmount& amount, const CAsset& asset);
43+
CValue ConvertAmountToValue(const CAmount& amount, const CAsset& asset);
4344

44-
/**
45+
/**
46+
* Convert an amount denominated in the node's RFU (reference fee unit) into some asset
47+
*
48+
* @param[in] value Corresponds to CTxMemPoolEntry.nFeeValue
49+
* @param[in] asset Corresponds to CTxMemPoolEntry.nFeeAsset
50+
* @return the amount at current exchange rate. Corresponds to CTxMemPoolEntry.nFee
51+
*/
52+
CAmount ConvertValueToAmount(const CValue& value, const CAsset& asset);
53+
54+
/**
4555
* Load the exchange rate map from the default JSON config file in <datadir>/exchangerates.json.
4656
*
4757
* @param[in] errors Vector for storing error messages, if there are any.

src/node/miner.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -452,15 +452,15 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
452452
assert(!inBlock.count(iter));
453453

454454
uint64_t packageSize = iter->GetSizeWithAncestors();
455-
CAmount packageFees = iter->GetModFeesWithAncestors();
455+
CValue packageFees = iter->GetModFeesWithAncestors();
456456
int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
457457
if (fUsingModified) {
458458
packageSize = modit->nSizeWithAncestors;
459459
packageFees = modit->nModFeesWithAncestors;
460460
packageSigOpsCost = modit->nSigOpCostWithAncestors;
461461
}
462462

463-
if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
463+
if (packageFees.GetValue() < blockMinFeeRate.GetFee(packageSize)) {
464464
// Everything else we might consider has a lower fee rate
465465
return;
466466
}

src/node/miner.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ struct CTxMemPoolModifiedEntry {
4747

4848
int64_t GetModifiedFee() const { return iter->GetModifiedFee(); }
4949
uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; }
50-
CAmount GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
50+
CValue GetModFeesWithAncestors() const { return nModFeesWithAncestors; }
5151
size_t GetTxSize() const { return iter->GetTxSize(); }
5252
const CTransaction& GetTx() const { return iter->GetTx(); }
5353

5454
CTxMemPool::txiter iter;
5555
uint64_t nSizeWithAncestors;
56-
CAmount nModFeesWithAncestors;
56+
CValue nModFeesWithAncestors;
5757
int64_t nSigOpCostWithAncestors;
5858
};
5959

@@ -116,7 +116,7 @@ struct update_for_parent_inclusion
116116

117117
void operator() (CTxMemPoolModifiedEntry &e)
118118
{
119-
e.nModFeesWithAncestors -= iter->GetFee();
119+
e.nModFeesWithAncestors -= iter->GetFeeValue();
120120
e.nSizeWithAncestors -= iter->GetTxSize();
121121
e.nSigOpCostWithAncestors -= iter->GetSigOpCost();
122122
}

src/node/transaction.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
7676
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
7777
return HandleATMPError(result.m_state, err_string);
7878
} else if (g_con_any_asset_fees) {
79-
CAmount mBaseFeesValue = ExchangeRateMap::GetInstance().CalculateExchangeValue(result.m_base_fees.value(), tx->GetFeeAsset(::policyAsset));
80-
if (mBaseFeesValue > max_tx_fee) {
79+
CValue mBaseFeesValue = ExchangeRateMap::GetInstance().ConvertAmountToValue(result.m_base_fees.value(), tx->GetFeeAsset(::policyAsset));
80+
if (mBaseFeesValue.GetValue() > max_tx_fee) {
8181
return TransactionError::MAX_FEE_EXCEEDED;
8282
}
8383
} else if (result.m_base_fees.value() > max_tx_fee) {

src/policy/feerate.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

6+
#include <asset.h>
7+
#include <exchangerates.h>
68
#include <policy/feerate.h>
9+
#include <policy/value.h>
10+
#include <primitives/transaction.h>
711

812
#include <tinyformat.h>
913

@@ -36,6 +40,15 @@ CAmount CFeeRate::GetFee(uint32_t num_bytes) const
3640
return nFee;
3741
}
3842

43+
CAmount CFeeRate::GetFee(uint32_t num_bytes, const CAsset& asset) const
44+
{
45+
CValue nFee = CValue(this->GetFee(num_bytes));
46+
if (g_con_any_asset_fees) {
47+
nFee = ExchangeRateMap::GetInstance().ConvertValueToAmount(nFee, asset);
48+
}
49+
return nFee.GetValue();
50+
}
51+
3952
std::string CFeeRate::ToString(const FeeEstimateMode& fee_estimate_mode) const
4053
{
4154
switch (fee_estimate_mode) {

src/policy/feerate.h

+14
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@
66
#ifndef BITCOIN_POLICY_FEERATE_H
77
#define BITCOIN_POLICY_FEERATE_H
88

9+
#include <asset.h>
910
#include <consensus/amount.h>
1011
#include <serialize.h>
1112

1213
#include <string>
1314

15+
#ifdef ANY_ASSET_FEES
16+
const std::string CURRENCY_UNIT = "RFU"; // One formatted unit (reference fee unit)
17+
const std::string CURRENCY_ATOM = "rfa"; // One indivisible minimum value unit (reference fee atom)
18+
const std::string CURRENCY_ATOM_FULL = "reference fee atom";
19+
#else
1420
const std::string CURRENCY_UNIT = "BTC"; // One formatted unit
1521
const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit
22+
const std::string CURRENCY_ATOM_FULL = "satoshi";
23+
#endif
1624

1725
/* Used to determine type of fee estimation requested */
1826
enum class FeeEstimateMode {
@@ -56,6 +64,12 @@ class CFeeRate
5664
*/
5765
CAmount GetFee(uint32_t num_bytes) const;
5866

67+
/**
68+
* Return the fee in denominations of the fee asset for the given
69+
* vsize in vbytes.
70+
*/
71+
CAmount GetFee(uint32_t num_bytes, const CAsset& asset) const;
72+
5973
/**
6074
* Return the fee in satoshis for a vsize of 1000 vbytes
6175
*/

src/policy/fees.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
569569
trackedTxs++;
570570

571571
// Feerates are stored and reported as BTC-per-kb:
572-
CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
572+
CFeeRate feeRate(entry.GetFeeValue().GetValue(), entry.GetTxSize());
573573

574574
mapMemPoolTxs[hash].blockHeight = txHeight;
575575
unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());

src/policy/policy.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
5353
nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
5454
}
5555

56-
return dustRelayFeeIn.GetFee(nSize);
56+
return dustRelayFeeIn.GetFee(nSize, txout.nAsset.GetAsset());
5757
}
5858

5959
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
@@ -146,7 +146,7 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
146146
} else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
147147
reason = "bare-multisig";
148148
return false;
149-
} else if ((txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == policyAsset) && IsDust(txout, dust_relay_fee)) {
149+
} else if ((txout.nAsset.IsExplicit() && txout.nAsset.GetAsset() == tx.GetFeeAsset(::policyAsset)) && IsDust(txout, dust_relay_fee)) {
150150
reason = "dust";
151151
return false;
152152
}

src/policy/value.h

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) 2009-2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2021 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#ifndef BITCOIN_POLICY_VALUE_H
7+
#define BITCOIN_POLICY_VALUE_H
8+
9+
#include <cstdint>
10+
11+
/** ELEMENTS: Amount denominated in the node's RFU (reference fee unit). Used only
12+
* when con_any_asset_fees is enabled in order to distinguish from amounts in an
13+
* actual asset. RFU is needed to make amounts comparable when sorting transactions
14+
* in the mempool, as well as for fee estimation and subsequent validation of those
15+
* fees according to various limits (e.g., mintxfee, paytsxfee, blockmintxfee,
16+
* incrementalrelaytxfee, etc.).
17+
*/
18+
struct CValue
19+
{
20+
private:
21+
int64_t value;
22+
23+
public:
24+
CValue(): value(0) {}
25+
CValue(const int64_t value): value(value) {}
26+
27+
int64_t GetValue() const
28+
{
29+
return value;
30+
}
31+
32+
CValue operator -(const CValue& operand)
33+
{
34+
return CValue(value - operand.value);
35+
}
36+
37+
CValue operator -=(const CValue& operand)
38+
{
39+
value -= operand.value;
40+
return *this;
41+
}
42+
43+
CValue operator +(const CValue& operand)
44+
{
45+
return CValue(value + operand.value);
46+
}
47+
48+
CValue operator +=(const CValue& operand)
49+
{
50+
value += operand.value;
51+
return *this;
52+
}
53+
54+
bool operator ==(const CValue& operand)
55+
{
56+
return value == operand.value;
57+
}
58+
59+
bool operator !=(const CValue& operand)
60+
{
61+
return value != operand.value;
62+
}
63+
};
64+
65+
#endif // BITCOIN_POLICY_VALUE_H

0 commit comments

Comments
 (0)