Skip to content

Commit

Permalink
revert fee handling to conform with the old client. Resolves the stuc…
Browse files Browse the repository at this point in the history
…k transactions issue that could occur with dust outputs
  • Loading branch information
l0rdicon committed Oct 19, 2020
1 parent ed81c55 commit 558130a
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 34 deletions.
32 changes: 19 additions & 13 deletions src/amount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "amount.h"

#include "consensus/consensus.h"
#include "tinyformat.h"

#include "primitives/transaction.h"
#include <boost/foreach.hpp>

const std::string CURRENCY_UNIT = "CLAM";

CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
Expand All @@ -20,22 +23,25 @@ CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
nSatoshisPerK = 0;
}

CAmount CFeeRate::GetFee(size_t nBytes_, bool fRoundUp) const
CAmount CFeeRate::GetFee(size_t nBytes_, unsigned int nBlockSize, bool fRoundUp) const
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
int64_t nSize = int64_t(nBytes_);
CAmount nBaseFee = 10000;

CAmount nFee = fRoundUp ? (1 + nSize / 1000) * nSatoshisPerK : nSize * nSatoshisPerK / 1000;

if (nFee == 0 && nSize != 0) {
if (nSatoshisPerK > 0)
nFee = CAmount(1);
if (nSatoshisPerK < 0)
nFee = CAmount(-1);
unsigned int nNewBlockSize = nBlockSize + nBytes_;
int64_t nSize = int64_t(nBytes_);
CAmount nMinFee = (1 + (int64_t)nBytes_ / 1000) * nBaseFee;

//CAmount nFee = fRoundUp ? (1 + nSize / 1000) * nSatoshisPerK : nSize * nSatoshisPerK / 1000;
// Raise the price as the block approaches full
if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_BASE_SIZE_GEN / 2) {
if (nNewBlockSize >= MAX_BLOCK_BASE_SIZE_GEN)
return MAX_MONEY;
nMinFee *= MAX_BLOCK_BASE_SIZE_GEN / (MAX_BLOCK_BASE_SIZE_GEN - nNewBlockSize);
}
if (fRoundUp && nFee < 10000)
nFee = CAmount(10000);
return nFee;
if (!MoneyRange(nMinFee))
nMinFee = MAX_MONEY;
return nMinFee;
}

std::string CFeeRate::ToString() const
Expand Down
4 changes: 2 additions & 2 deletions src/amount.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ class CFeeRate
/**
* Return the fee in satoshis for the given size in bytes.
*/
CAmount GetFee(size_t nBytes, bool fRoundUp = true) const;
CAmount GetFee(size_t nBytes, unsigned int nBlockSize = 1, bool fRoundUp = true) const;
/**
* Return the fee in satoshis for a size of 1000 bytes
*/
CAmount GetFeePerK() const { return GetFee(1000); }
CAmount GetFeePerK() const { return CAmount(10000); }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
Expand Down
3 changes: 2 additions & 1 deletion src/consensus/consensus.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;

/** The maximum size for mined blocks */
static const unsigned int MAX_BLOCK_BASE_SIZE_GEN = MAX_BLOCK_BASE_SIZE / 2;

/** Flags for nSequence and nLockTime locks */
enum {
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "setnetworkactive", 0, "state" },
{ "getmempoolancestors", 1, "verbose" },
{ "getmempooldescendants", 1, "verbose" },
{ "bumpfee", 1, "options" },
//{ "bumpfee", 1, "options" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
Expand Down
27 changes: 22 additions & 5 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,19 +772,30 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
strprintf("%d", nSigOpsCost));

CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize, 1);
if (mempoolRejectFee < DEFAULT_TRANSACTION_FEE) {
BOOST_FOREACH (const CTxOut& txout, tx.vout)
if (txout.nValue < CENT)
mempoolRejectFee = DEFAULT_TRANSACTION_FEE;
}
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
LogPrintf("AcceptToMemoryPoolWorker : not enough fees (%d < %d)\n", nFees, mempoolRejectFee);
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize, 1) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block.
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 && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
int64_t nMinFee = ::minRelayTxFee.GetFee(nSize, 1);
if (nMinFee < DEFAULT_TRANSACTION_FEE) {
BOOST_FOREACH (const CTxOut& txout, tx.vout)
if (txout.nValue < CENT)
nMinFee = DEFAULT_TRANSACTION_FEE;
}
if (fLimitFree && nModifiedFees < nMinFee)
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
Expand Down Expand Up @@ -953,14 +964,20 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
int64_t nMinFee = ::incrementalRelayFee.GetFee(nSize, 1);
if (nMinFee < DEFAULT_TRANSACTION_FEE) {
BOOST_FOREACH (const CTxOut& txout, tx.vout)
if (txout.nValue < CENT)
nMinFee = DEFAULT_TRANSACTION_FEE;
}
if (nDeltaFees < nMinFee)
{
return state.DoS(0, false,
REJECT_INSUFFICIENTFEE, "insufficient fee", false,
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
FormatMoney(::incrementalRelayFee.GetFee(nSize))));
FormatMoney(nMinFee)));
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3158,6 +3158,7 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx)
return GetVirtualTransactionSize(txNew);
}

/*
UniValue bumpfee(const JSONRPCRequest& request)
{
if (!EnsureWalletIsAvailable(request.fHelp)) {
Expand Down Expand Up @@ -3449,6 +3450,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
return result;
}
*/

UniValue getrewardto(const JSONRPCRequest& request)
{
Expand Down Expand Up @@ -3678,7 +3680,7 @@ static const CRPCCommand commands[] =
{ "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
{ "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
{ "wallet", "backupwallet", &backupwallet, true, {"destination"} },
{ "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
//{ "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
{ "wallet", "createclamour", &createclamour, true, {"clamourProposal", "url"} },
{ "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
{ "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
Expand Down
50 changes: 39 additions & 11 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2689,6 +2689,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);


{
set<pair<const CWalletTx*,unsigned int> > setCoins;
vector<pair<const CWalletTx*,unsigned int>> vCoins;
Expand All @@ -2698,7 +2699,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
std::vector<COutput> vAvailableCoins;
AvailableCoins(vAvailableCoins, true, coinControl);

nFeeRet = 0;
nFeeRet = nTransactionFee;
// Start with no fee and loop until there is enough fee
while (true)
{
Expand Down Expand Up @@ -2767,7 +2768,13 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
dPriority += (double)nCredit * age;
}

const CAmount nChange = nValueIn - nValueToSelect;
CAmount nChange = nValueIn - nValueToSelect;
if (nFeeRet < DEFAULT_TRANSACTION_FEE && nChange > 0 && nChange < CENT)
{
int64_t nMoveToFee = min(nChange, DEFAULT_TRANSACTION_FEE - nFeeRet);
nChange -= CAmount(nMoveToFee);
nFeeRet += nMoveToFee;
}
if (nChange > 0)
{
// Fill a vout to ourself
Expand Down Expand Up @@ -2832,6 +2839,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(dustRelayFee))
Expand Down Expand Up @@ -2873,6 +2881,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}
}


// Fill vin
//
// Note how the sequence number is set to non-maxint so that
Expand Down Expand Up @@ -2905,7 +2914,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
}

// Allow to override the default confirmation target over the CoinControl instance
int currentConfirmationTarget = nTxConfirmTarget;
/* int currentConfirmationTarget = nTxConfirmTarget;
if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget;
Expand Down Expand Up @@ -2954,11 +2963,26 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
nFeeRet += additionalFeeNeeded;
break; // Done, able to increase fee from change
}
}*/
CAmount nBaseFee = DEFAULT_TRANSACTION_FEE;
int64_t nMinFee = minTxFee.GetFee(1, nBytes);
int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
if (nMinFee < nBaseFee) {
BOOST_FOREACH (const CTxOut& txout, txNew.vout)
if (txout.nValue < CENT)
nMinFee = nBaseFee;
}

if (nFeeRet < max(nPayFee, nMinFee))
{
LogPrintf("[FEE] so we increased fee to %s and loop again\n", FormatMoney(nFeeRet));
nFeeRet = max(nPayFee, nMinFee);
continue;
}

// Include more fee and try again.
nFeeRet = nFeeNeeded;
continue;
//nFeeRet = nMinFee;
break;
}
}

Expand Down Expand Up @@ -3342,6 +3366,10 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int
return error("CreateCoinStake : failed to sign coinstake");
}

unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_BLOCK_BASE_SIZE_GEN/5)
return error("CreateCoinStake : exceeded coinstake size limit");

// Successfully generated coinstake
tx = CTransaction(txNew);
return true;
Expand Down Expand Up @@ -3481,39 +3509,39 @@ bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwa

CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
{
return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
return std::max(1, 1); //minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
}


CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
{
// payTxFee is the user-set global for desired feerate
return GetMinimumFee(nTxBytes, nConfirmTarget, pool, payTxFee.GetFee(nTxBytes));
return CAmount(10000); //etMinimumFee(nTxBytes, nConfirmTarget, pool, payTxFee.GetFee(nTxBytes));
}

CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool, CAmount targetFee)
{
CAmount nFeeNeeded = targetFee;
// User didn't set: use -txconfirmtarget to estimate...
if (nFeeNeeded == 0) {
/*if (nFeeNeeded == 0) {
int estimateFoundTarget = nConfirmTarget;
nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes);
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if (nFeeNeeded == 0)
nFeeNeeded = fallbackFee.GetFee(nTxBytes);
}
}*/
// prevent user from paying a fee below minRelayTxFee or minTxFee
nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes));
// But always obey the maximum
if (nFeeNeeded > maxTxFee)
nFeeNeeded = maxTxFee;
if(nFeeNeeded < 10000)
if (nFeeNeeded < 10000)
nFeeNeeded = CAmount(10000);
return nFeeNeeded;
}




DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
if (!fFileBacked)
Expand Down
3 changes: 3 additions & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "wallet/rpcwallet.h"
#include "wallet/coincontrol.h"
#include "consensus/params.h"
#include "consensus/consensus.h"
#include <algorithm>
#include <atomic>
#include <map>
Expand Down Expand Up @@ -48,6 +49,8 @@ extern bool fSendFreeTransactions;
extern bool fWalletRbf;
extern bool fWalletUnlockStakingOnly;

/** The maximum size for transactions we're willing to relay/mine **/
static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_BASE_SIZE_GEN / 5;

static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
//! -paytxfee default
Expand Down

0 comments on commit 558130a

Please sign in to comment.