diff -uNr a/bitcoin/manifest b/bitcoin/manifest --- a/bitcoin/manifest 3d238d061aa136b7e513428f29f58699ea0fcefa01e30d1680afa84e31a4151dd730e59283d6db81bda6a8d06bc6a76169f9b584c3a7fbbb6e719f1f8b77937b +++ b/bitcoin/manifest f6d48da661101d4ab85441db4a19090939c4859618074ea1e16171700d76b7482f363cdd1cbb1570a494910dcd40456ae936c6c168f89469fdf50f562cb75f8a @@ -38,3 +38,4 @@ 696655 bitcoin_help_tuneups jfw Don't hide help for wallet commands based on current encryption state; accept -help for consistency; rewrite inane help for -highs/-lows options; add help for -disablesafemode; make it and -testsafemode use explicit variables for consistency and centricity of options; clarify warning message shown in safe mode and change the political interpretation it offers; fix inept formatting in the parts otherwise touched. 696655 bitcoin_permissive_mode jfw Add -permissive option to disable the potentially isolating effects of the malleus_mikehearnificarum; remove -caneat option, always allowing 'eatblock' which has no need for such childproofing. 707665 bitcoin_boost_prune_built_libs jfw Reduce precompiled Boost libraries to the four actually in use. +709104 bitcoin_tx_fee_cleanup jfw Add nMinRelayTxFee global accessed with new -minrelaytxfee option, minrelaytxfee field in getinfo, and setminrelaytxfee RPC command. Use this to replace the fixed MIN_RELAY_TX_FEE. Simplify mempool acceptance rules so this threshold always applies (no special-case free transactions or rubber-banding threshold by current block size). Adjust block generation logic accordingly, though it still sorts on a strange age-value priority rather than fee. Simplify wallet to always send using its configured fee (-paytxfee) and change its default to match the default minrelaytxfee, removing the fixed MIN_TX_FEE. Make nTransactionFee access thread-safe and expand the help text for its inconsistently named RPC setter. Fees are now figured properly without premature rounding, as floor((size*rate)/1024) rather than (floor(size/1000)+1)*rate. *NOTE:* This change may substantially impact wallet transaction fees and node memory usage patterns but puts more control over these in the hands of the operator. diff -uNr a/bitcoin/src/bitcoinrpc.cpp b/bitcoin/src/bitcoinrpc.cpp --- a/bitcoin/src/bitcoinrpc.cpp 298fb81c68959629fe77be43b445905a4708b468cb6d780c560efddf09eb99985ac0f5159bf92ed8a9a4bb5f179d895d3fafc2ed37575f251bd0bd4f4ea9fe2e +++ b/bitcoin/src/bitcoinrpc.cpp cf90b3587fee9524551fe517aff743c52062de1e377f468d58f6185f2b6cf66894f62bff386d3c43864775240923d19e12042f295c5ab82f3a8587ba7fb495df @@ -10,8 +10,6 @@ #include "util.h" #undef printf #include -// These two comment lines are to preserve line numbering and thus identical disassembly in a pruning of unused boost includes (the line number dependence there comes from ENTER_CRITICAL_SECTION). -// They can be freely removed at a later stage. #include #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" @@ -308,7 +306,8 @@ obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); - obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + obj.push_back(Pair("paytxfee", ValueFromAmount(GetTransactionFee()))); + obj.push_back(Pair("minrelaytxfee", ValueFromAmount(GetMinRelayTxFee()))); if (pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); @@ -477,14 +476,31 @@ if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( "settxfee \n" - " is a real and is rounded to the nearest 0.00000001"); + " is a real and is rounded to the nearest 0.00000001\n" + "Set the fee to pay when creating transactions, in BTC per binary kB (same as using the -paytxfee option)."); // Amount int64 nAmount = 0; if (params[0].get_real() != 0.0) nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts - nTransactionFee = nAmount; + SetTransactionFee(nAmount); + return true; +} + +Value setminrelaytxfee(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "setminrelaytxfee \n" + " is a real and is rounded to the nearest 0.00000001\n" + "Set the minimum fee for accepting transactions into pool, in BTC per binary kB (same as using the -minrelaytxfee option)."); + + int64 nAmount = 0; + if (params[0].get_real() != 0.0) + nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts + + SetMinRelayTxFee(nAmount); return true; } @@ -1968,6 +1984,7 @@ make_pair("getwork", &getwork), make_pair("listaccounts", &listaccounts), make_pair("settxfee", &settxfee), + make_pair("setminrelaytxfee", &setminrelaytxfee), make_pair("getmemorypool", &getmemorypool), make_pair("listsinceblock", &listsinceblock), make_pair("dumpblock", &dumpblock), @@ -2490,6 +2507,7 @@ if (strMethod == "setgenerate" && n > 1) ConvertTo(params[1]); if (strMethod == "sendtoaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "settxfee" && n > 0) ConvertTo(params[0]); + if (strMethod == "setminrelaytxfee" && n > 0) ConvertTo(params[0]); if (strMethod == "getreceivedbyaddress" && n > 1) ConvertTo(params[1]); if (strMethod == "getreceivedbyaccount" && n > 1) ConvertTo(params[1]); if (strMethod == "listreceivedbyaddress" && n > 0) ConvertTo(params[0]); diff -uNr a/bitcoin/src/db.cpp b/bitcoin/src/db.cpp --- a/bitcoin/src/db.cpp 8d156ea97f8a65cedfb916c7eb8a2ff621f1cf0131efe51cd6bf1d5a8d3d6d0dd24fe05372fb91ed35db27858a737d3e4e741bb0e0e5536893390bebce6ea6dd +++ b/bitcoin/src/db.cpp 387ae498b8e968a7a3d7640e0b34f677b8cf60279928ba33d8054e26cf23f8d5e798cc857a81cc23433de5669808e4ce621e0b37649c06d86fbc29da2630539d @@ -915,7 +915,12 @@ // Options if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins; - if (strKey == "nTransactionFee") ssValue >> nTransactionFee; + if (strKey == "nTransactionFee") + { + int64 nFee = 0; + ssValue >> nFee; + SetTransactionFee(nFee); + } if (strKey == "fLimitProcessors") ssValue >> fLimitProcessors; if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors; if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray; @@ -939,7 +944,7 @@ printf("nFileVersion = %d\n", nFileVersion); printf("fGenerateBitcoins = %d\n", fGenerateBitcoins); - printf("nTransactionFee = %"PRI64d"\n", nTransactionFee); + printf("nTransactionFee = %"PRI64d"\n", GetTransactionFee()); printf("fMinimizeToTray = %d\n", fMinimizeToTray); printf("fMinimizeOnClose = %d\n", fMinimizeOnClose); printf("fUseProxy = %d\n", fUseProxy); diff -uNr a/bitcoin/src/init.cpp b/bitcoin/src/init.cpp --- a/bitcoin/src/init.cpp e0f55c8b6462c4efd445f7455d2527e7c44c7a9e6db3d2ce3ebcc07a9548a255d385e06aa9780bf7c7dad6e04efa5db61ed643cf84e77176badd92c9a0b6f47f +++ b/bitcoin/src/init.cpp 60e5cc7e8afa70278b7c37eb9ec1d53e161e79b7809f908aef4bda8d448b455176f3902460e79ccad2f99aa80b1fd34002adc1dda51f2acca6c29a5e7a8b1fda @@ -172,7 +172,8 @@ " -permissive Don't ban peers for sending unrecognized message types.\n" + " -maxreceivebuffer=\t " + _("Maximum per-connection receive buffer, *1000 bytes (default: 10000)\n") + " -maxsendbuffer=\t " + _("Maximum per-connection send buffer, *1000 bytes (default: 10000)\n") + - " -paytxfee= \t " + _("Fee per kB to add to transactions you send\n") + + " -paytxfee= Fee to add to transactions you send, in BTC per binary kB\n" + + " -minrelaytxfee= Minimum fee for accepting transactions into pool, in BTC per binary kB\n" + " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + " -debug \t\t " + _("Output extra debugging information\n") + " -verifyall Forbid the skipping of ECDSA signature verification between checkpoints\n" + @@ -234,6 +235,17 @@ fPrintToDebugger = GetBoolArg("-printtodebugger"); fLogTimestamps = GetBoolArg("-logtimestamps"); + if (mapArgs.count("-minrelaytxfee")) + { + int64 nMinFee = 0; + if (!ParseMoney(mapArgs["-minrelaytxfee"], nMinFee)) + { + fprintf(stderr, "Invalid amount for -minrelaytxfee=\n"); + return false; + } + SetMinRelayTxFee(nMinFee); + } + for (int i = 1; i < argc; i++) if (!IsSwitchChar(argv[i][0])) fCommandLine = true; @@ -466,13 +478,15 @@ if (mapArgs.count("-paytxfee")) { + int64 nTransactionFee = 0; if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee)) { - wxMessageBox(_("Invalid amount for -paytxfee="), "Bitcoin"); + fprintf(stderr, "Invalid amount for -paytxfee=\n"); return false; } if (nTransactionFee > 0.25 * COIN) - wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION); + fprintf(stderr, "Warning: -paytxfee is set very high. This is the fee you will pay per kB if you send a transaction.\n"); + SetTransactionFee(nTransactionFee); } // diff -uNr a/bitcoin/src/main.cpp b/bitcoin/src/main.cpp --- a/bitcoin/src/main.cpp 11f90e29ae8e63bdbc32ea162791eb29439f61221bbbe69a09068929c9554e0dad22a3cb454d5890e28f1c617d847be6ec9555cb6d09d9c5916760347308c129 +++ b/bitcoin/src/main.cpp c2f38d7e3e2772ee004f8b212eb71c872f09e7e9aa8f7e3c84b11e1c5f0860310a95c3ae0d0ea24b56f6e728c38b3421bdd404e6c6547440d4520b17f2b2a57d @@ -51,12 +51,48 @@ // Settings int fGenerateBitcoins = false; -int64 nTransactionFee = 0; int fLimitProcessors = false; int nLimitProcessors = 1; int fMinimizeToTray = true; int fMinimizeOnClose = true; +static int64 nTransactionFee = 10000; +static int64 nMinRelayTxFee = 10000; +static CCriticalSection cs_settings; +int64 GetTransactionFee() +{ + SCOPED_LOCK(cs_settings); + return nTransactionFee; +} + +void SetTransactionFee(int64 nFee) +{ + SCOPED_LOCK(cs_settings); + nTransactionFee = nFee; +} + +int64 GetMinRelayTxFee() +{ + SCOPED_LOCK(cs_settings); + return nMinRelayTxFee; +} + +void SetMinRelayTxFee(int64 nFee) +{ + SCOPED_LOCK(cs_settings); + nMinRelayTxFee = nFee; +} + +int64 ScaleTxFee(int64 nFeePerKB, unsigned int nBytes) +{ + if (nFeePerKB < 0) nFeePerKB = 0; // should probably never happen + if (nBytes > MAX_BLOCK_SIZE) nBytes = MAX_BLOCK_SIZE; // should probably never happen + int64 nFee = (nFeePerKB > INT64_MAX / (int64) MAX_BLOCK_SIZE) + ? INT64_MAX // multiplication overflow, should never happen for "reasonable" fee + : nFeePerKB * (int64) nBytes; + nFee /= 1024; + return (nFee > MAX_MONEY) ? MAX_MONEY : nFee; +} bool GetMempoolTx(const uint256 &hash, CTransaction &tx) { @@ -386,34 +422,9 @@ return error("AcceptToMemoryPool() : ConnectInputs failed %s", hash.ToString().c_str()); } - // Don't accept it if it can't get into a block - if (nFees < GetMinFee(1000, true, true)) + // Don't accept it if its fee is below the current threshold + if (nFees < GetMinFee()) return error("AcceptToMemoryPool() : not enough fees"); - - // Continuously rate-limit free transactions - // This mitigates 'penny-flooding' -- sending thousands of free transactions just to - // be annoying or make other's transactions take longer to confirm. - if (nFees < MIN_RELAY_TX_FEE) - { - static CCriticalSection cs; - static double dFreeCount; - static int64 nLastTime; - int64 nNow = GetTime(); - - CRITICAL_BLOCK(cs) - { - // 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", 15)*10*1000 && !IsFromMe(*this)) - return error("AcceptToMemoryPool() : free transaction rejected by rate limiter"); - if (fDebug) - printf("Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); - dFreeCount += nSize; - } - } } // Store transaction in memory @@ -2622,6 +2633,7 @@ } // Priority is sum(valuein * age) / txsize + // XXX This should probably be (fee / txsize), but may need to refactor to get the fee dPriority /= ::GetSerializeSize(tx, SER_NETWORK); if (porphan) @@ -2657,9 +2669,9 @@ if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; - // Transaction fee required depends on block size - bool fAllowFree = (nBlockSize + nTxSize < 4000 || CTransaction::AllowFree(dPriority)); - int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree); + // Transaction fee required depends on size and current configuration + // XXX Mostly redundant since tx was already accepted to mempool based on its fee. But perhaps the threshold has changed, and for now we need to maintain at least some way to prevent better-paying transactions from being drowned out. + int64 nMinFee = tx.GetMinFee(); // Connecting shouldn't fail due to dependency on other memory pool transactions // because we're already processing them in order of dependency diff -uNr a/bitcoin/src/main.h b/bitcoin/src/main.h --- a/bitcoin/src/main.h 6788cbec57850c7ba97f945ea48fbf77e9de12361a067f5a5bcf0149bbdba3e9f9c3e9e676c617ac5f23836cac8249035ae02ade091d0da3b212f98dd5eb7db8 +++ b/bitcoin/src/main.h 3cd26bb2979bc7ba58683345760c51e3f7ed974df52d84ed6855ed6e294c18776da4d5f5aa2461cb2bece6e3d9388a035cd485812b29900b406d0472904ea384 @@ -32,8 +32,6 @@ static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; static const int64 COIN = 100000000; static const int64 CENT = 1000000; -static const int64 MIN_TX_FEE = 50000; -static const int64 MIN_RELAY_TX_FEE = 10000; static const int64 MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } static const int COINBASE_MATURITY = 100; @@ -63,13 +61,18 @@ // Settings extern int fGenerateBitcoins; -extern int64 nTransactionFee; extern int fLimitProcessors; extern int nLimitProcessors; extern int fMinimizeToTray; extern int fMinimizeOnClose; +int64 GetTransactionFee(); +void SetTransactionFee(int64 nFee); +int64 GetMinRelayTxFee(); +void SetMinRelayTxFee(int64 nFee); +// Fees are now defined in BTC per binary kilobyte without premature rounding. +int64 ScaleTxFee(int64 nFeePerKB, unsigned int nBytes); @@ -519,56 +522,10 @@ return nValueOut; } - static bool AllowFree(double dPriority) + int64 GetMinFee() const { - // Large (in bytes) low-priority (new, small-coin) transactions - // need a fee. - return dPriority > COIN * 144 / 250; - } - - int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, bool fForRelay=false) const - { - // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE - int64 nBaseFee = fForRelay ? MIN_RELAY_TX_FEE : MIN_TX_FEE; - unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK); - unsigned int nNewBlockSize = nBlockSize + nBytes; - int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; - - if (fAllowFree) - { - if (nBlockSize == 1) - { - // Transactions under 10K are free - // (about 4500bc if made of 50bc inputs) - if (nBytes < 10000) - nMinFee = 0; - } - else - { - // Free transaction area - if (nNewBlockSize < 27000) - nMinFee = 0; - } - } - - // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01 - if (nMinFee < nBaseFee) - BOOST_FOREACH(const CTxOut& txout, vout) - if (txout.nValue < CENT) - nMinFee = nBaseFee; - - // Raise the price as the block approaches full - if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) - { - if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN) - return MAX_MONEY; - nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize); - } - - if (!MoneyRange(nMinFee)) - nMinFee = MAX_MONEY; - return nMinFee; + return ScaleTxFee(GetMinRelayTxFee(), nBytes); } diff -uNr a/bitcoin/src/util.h b/bitcoin/src/util.h --- a/bitcoin/src/util.h 8201beeab0ac958f021df12bb30a4fcdbdc42151e6516bd7083a6b6c4ff95acad430157196d447a4a5344559ac5f82d96c981b87b9937326e24a2ad0094c9bdd +++ b/bitcoin/src/util.h 25e0005b1ac501d4058966ec78823ff48427dc8dcb39f6414cba439782da31c5de505bf931ea41fee35bd3327caf0a90af74bb4a5a83617ab0d93caea61c5357 @@ -220,6 +220,9 @@ #define CRITICAL_BLOCK(cs) \ if (CCriticalBlock criticalblock = CCriticalBlock(cs, #cs, __FILE__, __LINE__)) +// Or we could not misdirect the compiler not to mention reader through if-statement and operator-bool() hacks. +#define SCOPED_LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) + #define ENTER_CRITICAL_SECTION(cs) \ (cs).Enter(#cs, __FILE__, __LINE__) diff -uNr a/bitcoin/src/wallet.cpp b/bitcoin/src/wallet.cpp --- a/bitcoin/src/wallet.cpp ec7774805c2999f289f26c3dc0aa669977ea36b9112c4040d4470760583854821262b5073c74f51dfd6c9b3725660f706c1e7990ce43b94b91d7cff61f047012 +++ b/bitcoin/src/wallet.cpp a7688a9eadf8cea2d5d65c432ae068bedbaf9ab865310c6d846dc3635732dd5ba217d2bf9c02131f241ed80681f15615bd579404e39750358c22ba8e866bd51a @@ -921,6 +921,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { + int64 nTransactionFee = GetTransactionFee(); int64 nValue = 0; BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) { @@ -939,7 +940,7 @@ // txdb must be opened before the mapWallet lock CTxDB txdb("r"); { - nFeeRet = nTransactionFee; + nFeeRet = 0; loop { wtxNew.vin.clear(); @@ -947,7 +948,6 @@ wtxNew.fFromMe = true; int64 nTotalValue = nValue + nFeeRet; - double dPriority = 0; // vouts to the payees BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) wtxNew.vout.push_back(CTxOut(s.second, s.first)); @@ -957,22 +957,8 @@ int64 nValueIn = 0; if (!SelectCoins(nTotalValue, setCoins, nValueIn)) return false; - BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) - { - int64 nCredit = pcoin.first->vout[pcoin.second].nValue; - dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); - } int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE - // or until nChange becomes zero - if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT) - { - int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet); - nChange -= nMoveToFee; - nFeeRet += nMoveToFee; - } - if (nChange > 0) { // Note: We use a new key here to keep it from being obvious which side is the change. @@ -1014,15 +1000,12 @@ unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK); if (nBytes >= MAX_BLOCK_SIZE_GEN/5) return false; - dPriority /= nBytes; - // Check that enough fee is included - int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); - bool fAllowFree = CTransaction::AllowFree(dPriority); - int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree); - if (nFeeRet < max(nPayFee, nMinFee)) + // Check that enough fee is included for the current size; repeat until satisfied or out of coins + int64 nPayFee = ScaleTxFee(nTransactionFee, nBytes); + if (nFeeRet < nPayFee) { - nFeeRet = max(nPayFee, nMinFee); + nFeeRet = nPayFee; continue; } @@ -1113,7 +1096,7 @@ { string strError; if (nValue + nFeeRequired > GetBalance()) - strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str()); + strError = strprintf("Error: insufficient funds to cover transaction fee of %s ", FormatMoney(nFeeRequired).c_str()); else strError = _("Error: Transaction creation failed "); printf("SendMoney() : %s", strError.c_str()); @@ -1137,7 +1120,7 @@ // Check amount if (nValue <= 0) return _("Invalid amount"); - if (nValue + nTransactionFee > GetBalance()) + if (nValue > GetBalance()) // There's little point in counting a fee here because the final fee isn't known until the serialized transaction length is measured. So this is basically a courtesy pre-check and we can still run into insufficient funds when we try to CreateTransaction. return _("Insufficient funds"); // Parse bitcoin address