diff options
-rw-r--r-- | configure.ac | 11 | ||||
-rwxr-xr-x | contrib/devtools/check-doc.py | 2 | ||||
-rw-r--r-- | depends/packages/fontconfig.mk | 6 | ||||
-rw-r--r-- | src/chainparams.cpp | 14 | ||||
-rw-r--r-- | src/dbwrapper.cpp | 6 | ||||
-rw-r--r-- | src/leveldb/db/memtable.cc | 2 | ||||
-rw-r--r-- | src/leveldb/db/version_set.cc | 2 | ||||
-rw-r--r-- | src/leveldb/port/atomic_pointer.h | 47 | ||||
-rw-r--r-- | src/leveldb/port/port_example.h | 4 | ||||
-rw-r--r-- | src/leveldb/port/port_posix.cc | 14 | ||||
-rw-r--r-- | src/leveldb/port/port_posix.h | 1 | ||||
-rw-r--r-- | src/leveldb/port/port_posix_sse.cc | 19 | ||||
-rw-r--r-- | src/leveldb/port/port_win.cc | 11 | ||||
-rw-r--r-- | src/leveldb/port/port_win.h | 1 | ||||
-rw-r--r-- | src/leveldb/util/crc32c.cc | 4 | ||||
-rw-r--r-- | src/leveldb/util/logging.cc | 2 | ||||
-rw-r--r-- | src/net.cpp | 31 | ||||
-rw-r--r-- | src/net.h | 19 | ||||
-rw-r--r-- | src/net_processing.cpp | 11 | ||||
-rw-r--r-- | src/qt/forms/sendcoinsdialog.ui | 2 | ||||
-rw-r--r-- | src/qt/intro.cpp | 4 | ||||
-rw-r--r-- | src/qt/locale/bitcoin_en.ts | 2 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 12 |
23 files changed, 135 insertions, 92 deletions
diff --git a/configure.ac b/configure.ac index aea5d7160c..ba523d3762 100644 --- a/configure.ac +++ b/configure.ac @@ -258,14 +258,13 @@ if test "x$CXXFLAGS_overridden" = "xno"; then AX_CHECK_COMPILE_FLAG([-Wunused-local-typedef],[CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wdeprecated-register],[CXXFLAGS="$CXXFLAGS -Wno-deprecated-register"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[CXXFLAGS="$CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]]) - - # Check for optional instruction set support. Enabling these does _not_ imply that all code will - # be compiled with them, rather that specific objects/libs may use them after checking for runtime - # compatibility. - AX_CHECK_COMPILE_FLAG([-msse4.2],[[SSE42_CXXFLAGS="-msse4.2"]],,[[$CXXFLAG_WERROR]]) - fi +# Check for optional instruction set support. Enabling these does _not_ imply that all code will +# be compiled with them, rather that specific objects/libs may use them after checking for runtime +# compatibility. +AX_CHECK_COMPILE_FLAG([-msse4.2],[[SSE42_CXXFLAGS="-msse4.2"]],,[[$CXXFLAG_WERROR]]) + TEMP_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $SSE42_CXXFLAGS" AC_MSG_CHECKING(for assembler crc32 support) diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py index 150f368513..3b7a8f9a61 100755 --- a/contrib/devtools/check-doc.py +++ b/contrib/devtools/check-doc.py @@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"') REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")') # list unsupported, deprecated and duplicate args as they need no documentation -SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio']) +SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-dbcrashratio', '-forcecompactdb']) def main(): used = check_output(CMD_GREP_ARGS, shell=True) diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk index fb97e0b9ec..12695db4b9 100644 --- a/depends/packages/fontconfig.mk +++ b/depends/packages/fontconfig.mk @@ -13,7 +13,13 @@ define $(package)_config_cmds $($(package)_autoconf) endef +# 2.12.1 uses CHAR_WIDTH which is reserved and clashes with some glibc versions, but newer versions of fontconfig +# have broken makefiles which needlessly attempt to re-generate headers with gperf. +# Instead, change all uses of CHAR_WIDTH, and disable the rule that forces header re-generation. +# This can be removed once the upstream build is fixed. define $(package)_build_cmds + sed -i 's/CHAR_WIDTH/CHARWIDTH/g' fontconfig/fontconfig.h src/fcobjshash.gperf src/fcobjs.h src/fcobjshash.h && \ + sed -i 's/fcobjshash.h: fcobjshash.gperf/fcobjshash.h:/' src/Makefile && \ $(MAKE) endef diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 02c8abb100..2021ec51db 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -162,11 +162,11 @@ public: }; chainTxData = ChainTxData{ - // Data as of block 00000000000000000166d612d5595e2b1cd88d71d695fc580af64d8da8658c23 (height 446482). - 1483472411, // * UNIX timestamp of last known number of transactions - 184495391, // * total number of transactions between genesis and that timestamp + // Data as of block 000000000000000000d97e53664d17967bd4ee50b23abb92e54a34eb222d15ae (height 478913). + 1501801925, // * UNIX timestamp of last known number of transactions + 243756039, // * total number of transactions between genesis and that timestamp // (the tx=... number in the SetBestChain debug.log lines) - 3.2 // * estimated number of transactions per second after that timestamp + 3.1 // * estimated number of transactions per second after that timestamp }; } }; @@ -250,9 +250,9 @@ public: }; chainTxData = ChainTxData{ - // Data as of block 00000000c2872f8f8a8935c8e3c5862be9038c97d4de2cf37ed496991166928a (height 1063660) - 1483546230, - 12834668, + // Data as of block 00000000000001c200b9790dc637d3bb141fe77d155b966ed775b17e109f7c6c (height 1156179) + 1501802953, + 14706531, 0.15 }; diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index ba9e21cc1f..3626e0177f 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -115,6 +115,12 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo dbwrapper_private::HandleError(status); LogPrintf("Opened LevelDB successfully\n"); + if (GetBoolArg("-forcecompactdb", false)) { + LogPrintf("Starting database compaction of %s\n", path.string()); + pdb->CompactRange(nullptr, nullptr); + LogPrintf("Finished database compaction of %s\n", path.string()); + } + // The base-case obfuscation key, which is a noop. obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES, '\000'); diff --git a/src/leveldb/db/memtable.cc b/src/leveldb/db/memtable.cc index bfec0a7e7a..287afdbdcb 100644 --- a/src/leveldb/db/memtable.cc +++ b/src/leveldb/db/memtable.cc @@ -101,7 +101,7 @@ void MemTable::Add(SequenceNumber s, ValueType type, p += 8; p = EncodeVarint32(p, val_size); memcpy(p, value.data(), val_size); - assert((p + val_size) - buf == encoded_len); + assert(p + val_size == buf + encoded_len); table_.Insert(buf); } diff --git a/src/leveldb/db/version_set.cc b/src/leveldb/db/version_set.cc index b1256f90e1..2cb6d80ed3 100644 --- a/src/leveldb/db/version_set.cc +++ b/src/leveldb/db/version_set.cc @@ -20,7 +20,7 @@ namespace leveldb { -static int TargetFileSize(const Options* options) { +static size_t TargetFileSize(const Options* options) { return options->max_file_size; } diff --git a/src/leveldb/port/atomic_pointer.h b/src/leveldb/port/atomic_pointer.h index 1c4c7aafc6..d79a02230d 100644 --- a/src/leveldb/port/atomic_pointer.h +++ b/src/leveldb/port/atomic_pointer.h @@ -46,6 +46,30 @@ namespace leveldb { namespace port { +// AtomicPointer based on <cstdatomic> if available +#if defined(LEVELDB_ATOMIC_PRESENT) +class AtomicPointer { + private: + std::atomic<void*> rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* v) : rep_(v) { } + inline void* Acquire_Load() const { + return rep_.load(std::memory_order_acquire); + } + inline void Release_Store(void* v) { + rep_.store(v, std::memory_order_release); + } + inline void* NoBarrier_Load() const { + return rep_.load(std::memory_order_relaxed); + } + inline void NoBarrier_Store(void* v) { + rep_.store(v, std::memory_order_relaxed); + } +}; + +#else + // Define MemoryBarrier() if available // Windows on x86 #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) @@ -142,28 +166,6 @@ class AtomicPointer { } }; -// AtomicPointer based on <cstdatomic> -#elif defined(LEVELDB_ATOMIC_PRESENT) -class AtomicPointer { - private: - std::atomic<void*> rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* v) : rep_(v) { } - inline void* Acquire_Load() const { - return rep_.load(std::memory_order_acquire); - } - inline void Release_Store(void* v) { - rep_.store(v, std::memory_order_release); - } - inline void* NoBarrier_Load() const { - return rep_.load(std::memory_order_relaxed); - } - inline void NoBarrier_Store(void* v) { - rep_.store(v, std::memory_order_relaxed); - } -}; - // Atomic pointer based on sparc memory barriers #elif defined(__sparcv9) && defined(__GNUC__) class AtomicPointer { @@ -229,6 +231,7 @@ class AtomicPointer { #error Please implement AtomicPointer for this platform. #endif +#endif #undef LEVELDB_HAVE_MEMORY_BARRIER #undef ARCH_CPU_X86_FAMILY diff --git a/src/leveldb/port/port_example.h b/src/leveldb/port/port_example.h index 97bd669a5e..5b1d027de5 100644 --- a/src/leveldb/port/port_example.h +++ b/src/leveldb/port/port_example.h @@ -129,6 +129,10 @@ extern bool Snappy_Uncompress(const char* input_data, size_t input_length, // The concatenation of all "data[0,n-1]" fragments is the heap profile. extern bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg); +// Determine whether a working accelerated crc32 implementation exists +// Returns true if AcceleratedCRC32C is safe to call +bool HasAcceleratedCRC32C(); + // Extend the CRC to include the first n bytes of buf. // // Returns zero if the CRC cannot be extended using acceleration, else returns diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc index 30e8007ae3..ec39e92195 100644 --- a/src/leveldb/port/port_posix.cc +++ b/src/leveldb/port/port_posix.cc @@ -8,6 +8,10 @@ #include <stdio.h> #include <string.h> +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) +#include <cpuid.h> +#endif + namespace leveldb { namespace port { @@ -49,5 +53,15 @@ void InitOnce(OnceType* once, void (*initializer)()) { PthreadCall("once", pthread_once(once, initializer)); } +bool HasAcceleratedCRC32C() { +#if (defined(__x86_64__) || defined(__i386__)) && defined(__GNUC__) + unsigned int eax, ebx, ecx, edx; + __get_cpuid(1, &eax, &ebx, &ecx, &edx); + return (ecx & (1 << 20)) != 0; +#else + return false; +#endif +} + } // namespace port } // namespace leveldb diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index 7e8213b22e..d85fa5d63f 100644 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -152,6 +152,7 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } +bool HasAcceleratedCRC32C(); uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); } // namespace port diff --git a/src/leveldb/port/port_posix_sse.cc b/src/leveldb/port/port_posix_sse.cc index 1e519ba0b6..2d49c21dd8 100644 --- a/src/leveldb/port/port_posix_sse.cc +++ b/src/leveldb/port/port_posix_sse.cc @@ -19,7 +19,6 @@ #include <intrin.h> #elif defined(__GNUC__) && defined(__SSE4_2__) #include <nmmintrin.h> -#include <cpuid.h> #endif #endif // defined(LEVELDB_PLATFORM_POSIX_SSE) @@ -48,20 +47,6 @@ static inline uint64_t LE_LOAD64(const uint8_t *p) { #endif // defined(_M_X64) || defined(__x86_64__) -static inline bool HaveSSE42() { -#if defined(_MSC_VER) - int cpu_info[4]; - __cpuid(cpu_info, 1); - return (cpu_info[2] & (1 << 20)) != 0; -#elif defined(__GNUC__) - unsigned int eax, ebx, ecx, edx; - __get_cpuid(1, &eax, &ebx, &ecx, &edx); - return (ecx & (1 << 20)) != 0; -#else - return false; -#endif -} - #endif // defined(LEVELDB_PLATFORM_POSIX_SSE) // For further improvements see Intel publication at: @@ -70,10 +55,6 @@ uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size) { #if !defined(LEVELDB_PLATFORM_POSIX_SSE) return 0; #else - static bool have = HaveSSE42(); - if (!have) { - return 0; - } const uint8_t *p = reinterpret_cast<const uint8_t *>(buf); const uint8_t *e = p + size; diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc index 1b0f060a19..1be9e8d5b0 100644 --- a/src/leveldb/port/port_win.cc +++ b/src/leveldb/port/port_win.cc @@ -32,6 +32,7 @@ #include <windows.h> #include <cassert> +#include <intrin.h> namespace leveldb { namespace port { @@ -143,5 +144,15 @@ void AtomicPointer::NoBarrier_Store(void* v) { rep_ = v; } +bool HasAcceleratedCRC32C() { +#if defined(__x86_64__) || defined(__i386__) + int cpu_info[4]; + __cpuid(cpu_info, 1); + return (cpu_info[2] & (1 << 20)) != 0; +#else + return false; +#endif +} + } } diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h index 5009004822..e8bf46ef27 100644 --- a/src/leveldb/port/port_win.h +++ b/src/leveldb/port/port_win.h @@ -168,6 +168,7 @@ inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) { return false; } +bool HasAcceleratedCRC32C(); uint32_t AcceleratedCRC32C(uint32_t crc, const char* buf, size_t size); } diff --git a/src/leveldb/util/crc32c.cc b/src/leveldb/util/crc32c.cc index edd61cfd6f..b3f40eeeed 100644 --- a/src/leveldb/util/crc32c.cc +++ b/src/leveldb/util/crc32c.cc @@ -288,6 +288,10 @@ static inline uint32_t LE_LOAD32(const uint8_t *p) { // Determine if the CPU running this program can accelerate the CRC32C // calculation. static bool CanAccelerateCRC32C() { + if (!port::HasAcceleratedCRC32C()) + return false; + + // Double-check that the accelerated implementation functions correctly. // port::AcceleretedCRC32C returns zero when unable to accelerate. static const char kTestCRCBuffer[] = "TestCRCBuffer"; static const char kBufSize = sizeof(kTestCRCBuffer) - 1; diff --git a/src/leveldb/util/logging.cc b/src/leveldb/util/logging.cc index ca6b324403..db6160c8f1 100644 --- a/src/leveldb/util/logging.cc +++ b/src/leveldb/util/logging.cc @@ -49,7 +49,7 @@ bool ConsumeDecimalNumber(Slice* in, uint64_t* val) { uint64_t v = 0; int digits = 0; while (!in->empty()) { - char c = (*in)[0]; + unsigned char c = (*in)[0]; if (c >= '0' && c <= '9') { ++digits; const int delta = (c - '0'); diff --git a/src/net.cpp b/src/net.cpp index d4a36a0306..ca9a173abe 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2210,12 +2210,10 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe nReceiveFloodSize = 0; semOutbound = NULL; semAddnode = NULL; - nMaxConnections = 0; - nMaxOutbound = 0; - nMaxAddnode = 0; - nBestHeight = 0; - clientInterface = NULL; flagInterruptMsgProc = false; + + Options connOptions; + Init(connOptions); } NodeId CConnman::GetNewNodeId() @@ -2254,30 +2252,15 @@ bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<C return fBound; } -bool CConnman::Start(CScheduler& scheduler, Options connOptions) +bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) { + Init(connOptions); + nTotalBytesRecv = 0; nTotalBytesSent = 0; nMaxOutboundTotalBytesSentInCycle = 0; nMaxOutboundCycleStartTime = 0; - nRelevantServices = connOptions.nRelevantServices; - nLocalServices = connOptions.nLocalServices; - nMaxConnections = connOptions.nMaxConnections; - nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); - nMaxAddnode = connOptions.nMaxAddnode; - nMaxFeeler = connOptions.nMaxFeeler; - - nSendBufferMaxSize = connOptions.nSendBufferMaxSize; - nReceiveFloodSize = connOptions.nReceiveFloodSize; - - nMaxOutboundLimit = connOptions.nMaxOutboundLimit; - nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; - - SetBestHeight(connOptions.nBestHeight); - - clientInterface = connOptions.uiInterface; - if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) { if (clientInterface) { clientInterface->ThreadSafeMessageBox( @@ -2287,8 +2270,6 @@ bool CConnman::Start(CScheduler& scheduler, Options connOptions) return false; } - vWhitelistedRange = connOptions.vWhitelistedRange; - for (const auto& strDest : connOptions.vSeedNodes) { AddOneShot(strDest); } @@ -146,9 +146,26 @@ public: std::vector<CSubNet> vWhitelistedRange; std::vector<CService> vBinds, vWhiteBinds; }; + + void Init(const Options& connOptions) { + nLocalServices = connOptions.nLocalServices; + nRelevantServices = connOptions.nRelevantServices; + nMaxConnections = connOptions.nMaxConnections; + nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections); + nMaxAddnode = connOptions.nMaxAddnode; + nMaxFeeler = connOptions.nMaxFeeler; + nBestHeight = connOptions.nBestHeight; + clientInterface = connOptions.uiInterface; + nSendBufferMaxSize = connOptions.nSendBufferMaxSize; + nReceiveFloodSize = connOptions.nReceiveFloodSize; + nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe; + nMaxOutboundLimit = connOptions.nMaxOutboundLimit; + vWhitelistedRange = connOptions.vWhitelistedRange; + } + CConnman(uint64_t seed0, uint64_t seed1); ~CConnman(); - bool Start(CScheduler& scheduler, Options options); + bool Start(CScheduler& scheduler, const Options& options); void Stop(); void Interrupt(); bool GetNetworkActive() const { return fNetworkActive; }; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a743f04dd1..6fabfcf0ad 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1260,6 +1260,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } + if (nServices & ((1 << 7) | (1 << 5))) { + if (GetTime() < 1533096000) { + // Immediately disconnect peers that use service bits 6 or 8 until August 1st, 2018 + // These bits have been used as a flag to indicate that a node is running incompatible + // consensus rules instead of changing the network magic, so we're stuck disconnecting + // based on these service bits, at least for a while. + pfrom->fDisconnect = true; + return false; + } + } + if (nVersion < MIN_PEER_PROTO_VERSION) { // disconnect from peers older than this proto version diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index e82a3c1533..1e2f2302b9 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -762,7 +762,7 @@ <item> <widget class="QLabel" name="fallbackFeeWarningLabel"> <property name="toolTip"> - <string>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain.</string> + <string>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</string> </property> <property name="font"> <font> diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 1e0d472b6a..231a715753 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -22,9 +22,9 @@ static const uint64_t GB_BYTES = 1000000000LL; /* Minimum free space (in GB) needed for data directory */ -static const uint64_t BLOCK_CHAIN_SIZE = 120; +static const uint64_t BLOCK_CHAIN_SIZE = 150; /* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */ -static const uint64_t CHAIN_STATE_SIZE = 2; +static const uint64_t CHAIN_STATE_SIZE = 3; /* Total required space (in GB) depending on user choice (prune, not prune) */ static uint64_t requiredSpace; diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 4cd1048d11..821be8987e 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -2674,7 +2674,7 @@ </message> <message> <location line="+24"/> - <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain.</source> + <source>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source> <translation type="unfinished"></translation> </message> <message> diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cf75cdd744..d236b1de3f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2789,10 +2789,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT // selected to meet nFeeNeeded result in a transaction that // requires less fee than the prior iteration. - // TODO: The case where nSubtractFeeFromAmount > 0 remains - // to be addressed because it requires returning the fee to - // the payees and not the change output. - // If we have no change and a big enough excess fee, then // try to construct transaction again only without picking // new inputs. We now know we only need the smaller fee @@ -2819,6 +2815,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT else if (!pick_new_inputs) { // This shouldn't happen, we should have had enough excess // fee to pay for the new output and still meet nFeeNeeded + // Or we should have just subtracted fee from recipients and + // nFeeNeeded should not have changed strFailReason = _("Transaction fee and change calculation failed"); return false; } @@ -2835,6 +2833,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT } } + // If subtracting fee from recipients, we now know what fee we + // need to subtract, we have no reason to reselect inputs + if (nSubtractFeeFromAmount > 0) { + pick_new_inputs = false; + } + // Include more fee and try again. nFeeRet = nFeeNeeded; continue; |