[fees] introduce configurable hard dust limit
Co-authored-by: Ross Nicoll <rnicoll@rnicoll.name>
This commit is contained in:
parent
a88d53be2e
commit
4c46af0483
|
@ -153,6 +153,7 @@ testScripts = [
|
|||
'signmessages.py',
|
||||
# 'nulldummy.py',
|
||||
'import-rescan.py',
|
||||
'harddustlimit.py',
|
||||
# While fee bumping should work in Doge, these tests depend on free transactions, which we don't support.
|
||||
# Disable until we can do a full rewrite of the tests (possibly upstream), or revise fee schedule, or something
|
||||
'bumpfee.py',
|
||||
|
|
82
qa/rpc-tests/harddustlimit.py
Normal file
82
qa/rpc-tests/harddustlimit.py
Normal file
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2021 The Dogecoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Hard dust limit QA test.
|
||||
|
||||
# Tests nodes with differing -dustlimits
|
||||
"""
|
||||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import *
|
||||
from decimal import Decimal
|
||||
|
||||
class HardDustLimitTest(BitcoinTestFramework):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 3
|
||||
|
||||
def setup_network(self, split=False):
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-dustlimit=0.1", "-debug"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-dustlimit=1", "-debug"]))
|
||||
self.nodes.append(start_node(2, self.options.tmpdir, ["-dustlimit=0.01", "-debug"]))
|
||||
|
||||
connect_nodes_bi(self.nodes,0,1)
|
||||
connect_nodes_bi(self.nodes,1,2)
|
||||
connect_nodes_bi(self.nodes,0,2)
|
||||
|
||||
self.is_network_split=False
|
||||
self.sync_all()
|
||||
|
||||
def run_test(self):
|
||||
|
||||
self.fee = Decimal("1")
|
||||
self.seed = 1000
|
||||
self.coinselector = {'minimumAmount': self.fee * 10, 'maximumAmount': self.seed}
|
||||
|
||||
# set up addresses
|
||||
n0a1 = self.nodes[0].getnewaddress()
|
||||
n0a2 = self.nodes[0].getnewaddress()
|
||||
n0a3 = self.nodes[0].getnewaddress()
|
||||
n1a1 = self.nodes[1].getnewaddress()
|
||||
n2a1 = self.nodes[2].getnewaddress()
|
||||
n2a2 = self.nodes[2].getnewaddress()
|
||||
n2a3 = self.nodes[2].getnewaddress()
|
||||
n2a4 = self.nodes[2].getnewaddress()
|
||||
|
||||
# mine some blocks and prepare some coins
|
||||
self.nodes[2].generate(1)
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(101)
|
||||
self.sync_all()
|
||||
self.nodes[0].sendtoaddress(n0a1, self.seed)
|
||||
self.nodes[0].sendtoaddress(n2a1, self.seed)
|
||||
self.sync_all()
|
||||
self.nodes[0].generate(1)
|
||||
self.sync_all()
|
||||
|
||||
# create dusty transactions
|
||||
self.send_dusty_tx(self.nodes[2], n2a2, n0a2, Decimal("0.9"))
|
||||
self.send_dusty_tx(self.nodes[2], n2a3, n0a3, Decimal("0.09"))
|
||||
self.send_dusty_tx(self.nodes[0], n2a4, n1a1, Decimal("1"))
|
||||
|
||||
# wait 10 seconds to sync mempools
|
||||
time.sleep(10)
|
||||
|
||||
assert_equal(self.nodes[2].getmempoolinfo()['size'], 3)
|
||||
assert_equal(self.nodes[1].getmempoolinfo()['size'], 1)
|
||||
assert_equal(self.nodes[0].getmempoolinfo()['size'], 2)
|
||||
|
||||
def send_dusty_tx(self, n, addr1, addr2, dust):
|
||||
avail = n.listunspent(0, 1000, [], True, self.coinselector)
|
||||
inputs = [ {'txid': avail[0]['txid'], 'vout': avail[0]['vout']}]
|
||||
outputs = { addr1 : avail[0]['amount'] - self.fee - dust , addr2: dust }
|
||||
rawtx = n.createrawtransaction(inputs, outputs)
|
||||
rawtx = n.signrawtransaction(rawtx)
|
||||
n.sendrawtransaction(rawtx['hex'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
HardDustLimitTest().main()
|
|
@ -475,6 +475,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||
strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
|
||||
strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
|
||||
}
|
||||
strUsage += HelpMessageOpt("-dustlimit=<amt>", strprintf(_("Amount under which a transaction output is considered dust, in %s (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_DUST_LIMIT)));
|
||||
strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
|
||||
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
|
||||
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
|
||||
|
@ -1043,6 +1044,14 @@ bool AppInitParameterInteraction()
|
|||
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
|
||||
nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp);
|
||||
|
||||
if (IsArgSet("-dustlimit"))
|
||||
{
|
||||
CAmount n = nDustLimit;
|
||||
if (!ParseMoney(GetArg("-dustlimit", ""), n))
|
||||
return InitError(AmountErrMsg("dustlimit", GetArg("-dustlimit", "")));
|
||||
nDustLimit = n;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
if (!CWallet::ParameterInteraction())
|
||||
return false;
|
||||
|
|
|
@ -209,6 +209,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|||
CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
|
||||
CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
|
||||
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
|
||||
unsigned int nDustLimit = DEFAULT_DUST_LIMIT;
|
||||
|
||||
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
|
||||
{
|
||||
|
|
|
@ -46,6 +46,13 @@ static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
|
|||
* only increase the dust limit after prior releases were already not creating
|
||||
* outputs below the new threshold */
|
||||
static const unsigned int DUST_RELAY_TX_FEE = 1000;
|
||||
/**
|
||||
* Dogecoin: Default dust limit that is evaluated when considering whether a
|
||||
* transaction output is required to pay additional fee for relay and inclusion
|
||||
* in blocks. Overridden by -dustlimit
|
||||
*/
|
||||
static const unsigned int DEFAULT_DUST_LIMIT = 100000000;
|
||||
|
||||
/**
|
||||
* Standard script verification flags that standard transactions will comply
|
||||
* with. However scripts violating these flags may still be present in valid
|
||||
|
@ -96,6 +103,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
|||
extern CFeeRate incrementalRelayFee;
|
||||
extern CFeeRate dustRelayFee;
|
||||
extern unsigned int nBytesPerSigOp;
|
||||
extern unsigned int nDustLimit;
|
||||
|
||||
/** Compute the virtual transaction size (weight reinterpreted as bytes). */
|
||||
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost);
|
||||
|
|
|
@ -15,6 +15,8 @@ static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
|
|||
|
||||
static const int WITNESS_SCALE_FACTOR = 4;
|
||||
|
||||
extern unsigned int nDustLimit;
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
{
|
||||
|
@ -195,7 +197,7 @@ public:
|
|||
*/
|
||||
|
||||
// Dogecoin: Anything below 1 DOGE is always dust
|
||||
return COIN;
|
||||
return nDustLimit;
|
||||
}
|
||||
|
||||
bool IsDust(const CFeeRate &minRelayTxFeeRate) const
|
||||
|
|
|
@ -36,6 +36,8 @@ std::vector<std::unique_ptr<CWalletTx>> wtxn;
|
|||
|
||||
typedef set<pair<const CWalletTx*,unsigned int> > CoinSet;
|
||||
|
||||
extern unsigned int nDustLimit;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
|
||||
|
||||
static const CWallet wallet;
|
||||
|
@ -524,6 +526,18 @@ BOOST_AUTO_TEST_CASE(GetMinimumFee_dust_test)
|
|||
BOOST_CHECK_EQUAL(CWallet::GetMinimumFee(tx, 963, 0, pool), 2 * nMinTxFee);
|
||||
BOOST_CHECK_EQUAL(CWallet::GetMinimumFee(tx, 1000, 0, pool), 2 * nMinTxFee);
|
||||
BOOST_CHECK_EQUAL(CWallet::GetMinimumFee(tx, 1999, 0, pool), 3 * nMinTxFee);
|
||||
|
||||
// change the hard dust limit
|
||||
|
||||
nDustLimit = COIN / 10;
|
||||
|
||||
// Confirm dust penalty fees are not added
|
||||
|
||||
BOOST_CHECK_EQUAL(CWallet::GetMinimumFee(tx, 963, 0, pool), 1 * nMinTxFee);
|
||||
BOOST_CHECK_EQUAL(CWallet::GetMinimumFee(tx, 1000, 0, pool), 1 * nMinTxFee);
|
||||
BOOST_CHECK_EQUAL(CWallet::GetMinimumFee(tx, 1999, 0, pool), 2 * nMinTxFee);
|
||||
|
||||
nDustLimit = COIN;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in a new issue