aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build-aux/m4/bitcoin_qt.m42
-rw-r--r--configure.ac2
-rw-r--r--doc/README.md2
-rw-r--r--doc/build-unix.md44
-rw-r--r--doc/build-windows.md40
-rw-r--r--src/init.cpp28
-rw-r--r--src/leveldb/util/env_win.cc236
-rw-r--r--src/main.cpp2
-rw-r--r--src/main.h3
-rw-r--r--src/miner.h2
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/coincontroldialog.cpp10
-rw-r--r--src/qt/guiutil.cpp4
-rw-r--r--src/qt/guiutil.h4
-rw-r--r--src/qt/optionsdialog.cpp2
-rw-r--r--src/qt/rpcconsole.cpp12
-rw-r--r--src/qt/rpcconsole.h1
-rw-r--r--src/qt/sendcoinsdialog.cpp10
-rw-r--r--src/qt/sendcoinsentry.cpp2
-rw-r--r--src/qt/signverifymessagedialog.cpp4
-rw-r--r--src/rpcblockchain.cpp8
-rw-r--r--src/rpcmining.cpp4
-rw-r--r--src/wallet/db.cpp2
-rw-r--r--src/wallet/db.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp113
-rw-r--r--src/wallet/wallet.cpp25
-rw-r--r--src/wallet/wallet.h38
-rw-r--r--src/zmq/zmqnotificationinterface.cpp11
-rw-r--r--src/zmq/zmqnotificationinterface.h3
29 files changed, 296 insertions, 322 deletions
diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4
index 121e10bd37..4ea2e734e8 100644
--- a/build-aux/m4/bitcoin_qt.m4
+++ b/build-aux/m4/bitcoin_qt.m4
@@ -50,7 +50,7 @@ AC_DEFUN([BITCOIN_QT_INIT],[
dnl enable qt support
AC_ARG_WITH([gui],
[AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@],
- [build bitcoin-qt GUI (default=auto, qt4 tried first)])],
+ [build bitcoin-qt GUI (default=auto, qt5 tried first)])],
[
bitcoin_qt_want_version=$withval
if test x$bitcoin_qt_want_version = xyes; then
diff --git a/configure.ac b/configure.ac
index 1669ec03ce..d94dd0c3dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -538,7 +538,7 @@ fi
BITCOIN_QT_INIT
dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus
-BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt4])
+BITCOIN_QT_CONFIGURE([$use_pkgconfig], [qt5])
if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests = xnononono; then
use_boost=no
diff --git a/doc/README.md b/doc/README.md
index 08fd724355..0594d20dd4 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -43,6 +43,8 @@ The following are developer notes on how to build Bitcoin on your native platfor
- [OS X Build Notes](build-osx.md)
- [Unix Build Notes](build-unix.md)
+- [Windows Build Notes](build-windows.md)
+- [OpenBSD Build Notes](build-openbsd.md)
- [Gitian Building Guide](gitian-building.md)
Development
diff --git a/doc/build-unix.md b/doc/build-unix.md
index a9a0028c4a..2102bbc830 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -1,6 +1,6 @@
UNIX BUILD NOTES
====================
-Some notes on how to build Bitcoin in Unix.
+Some notes on how to build Bitcoin Core in Unix.
(for OpenBSD specific instructions, see [build-openbsd.md](build-openbsd.md))
@@ -61,49 +61,55 @@ Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
- sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev
+ sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev
-For Ubuntu 12.04 and later or Debian 7 and later libboost-all-dev has to be installed:
+On Ubuntu 15.10+ there are generic names for the individual boost development
+packages, so the following can be used to only install necessary parts of
+boost:
- sudo apt-get install libboost-all-dev
+ apt-get install libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libboost-base-dev
- db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin).
- You can add the repository using the following command:
+For Ubuntu before 15.10, or Debian 7 and later libboost-all-dev has to be installed:
+
+ sudo apt-get install libboost-all-dev
+
+BerkeleyDB is required for the wallet. db4.8 packages are available [here](https://launchpad.net/~bitcoin/+archive/bitcoin).
+You can add the repository and install using the following commands:
sudo add-apt-repository ppa:bitcoin/bitcoin
sudo apt-get update
+ sudo apt-get install libdb4.8-dev libdb4.8++-dev
- Ubuntu 12.04 and later have packages for libdb5.1-dev and libdb5.1++-dev,
- but using these will break binary wallet compatibility, and is not recommended.
+Ubuntu and Debian have their own libdb-dev and libdb++-dev packages, but these will install
+BerkeleyDB 5.1 or later, which break binary wallet compatibility with the distributed executables which
+are based on BerkeleyDB 4.8. If you do not care about wallet compatibility,
+pass `--with-incompatible-bdb` to configure.
-For other Debian & Ubuntu (with ppa):
-
- sudo apt-get install libdb4.8-dev libdb4.8++-dev
+See the section "Disable-wallet mode" to build Bitcoin Core without wallet.
Optional:
- sudo apt-get install libminiupnpc-dev (see --with-miniupnpc and --enable-upnp-default)
+ sudo apt-get install libminiupnpc-dev (see --with-miniupnpc and --enable-upnp-default)
ZMQ dependencies:
sudo apt-get install libzmq3-dev (provides ZMQ API 4.x)
-
Dependencies for the GUI: Ubuntu & Debian
-----------------------------------------
If you want to build Bitcoin-Qt, make sure that the required packages for Qt development
-are installed. Either Qt 4 or Qt 5 are necessary to build the GUI.
-If both Qt 4 and Qt 5 are installed, Qt 4 will be used. Pass `--with-gui=qt5` to configure to choose Qt5.
+are installed. Either Qt 5 or Qt 4 are necessary to build the GUI.
+If both Qt 4 and Qt 5 are installed, Qt 5 will be used. Pass `--with-gui=qt4` to configure to choose Qt4.
To build without GUI pass `--without-gui`.
-To build with Qt 4 you need the following:
+To build with Qt 5 (recommended) you need the following:
- sudo apt-get install libqt4-dev libprotobuf-dev protobuf-compiler
+ sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
-For Qt 5 you need the following:
+Alternatively, to build with Qt 4 you need the following:
- sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler
+ sudo apt-get install libqt4-dev libprotobuf-dev protobuf-compiler
libqrencode (optional) can be installed with:
diff --git a/doc/build-windows.md b/doc/build-windows.md
new file mode 100644
index 0000000000..2b9233d1e1
--- /dev/null
+++ b/doc/build-windows.md
@@ -0,0 +1,40 @@
+WINDOWS BUILD NOTES
+====================
+
+Some notes on how to build Bitcoin Core for Windows.
+
+Most developers use cross-compilation from Ubuntu to build executables for
+Windows. This is also used to build the release binaries.
+
+Building on Windows itself is possible (for example using msys / mingw-w64),
+but no one documented the steps to do this. If you are doing this, please contribute them.
+
+Cross-compilation
+-------------------
+
+These steps can be performed on, for example, an Ubuntu VM. The depends system
+will also work on other Linux distributions, however the commands for
+installing the toolchain will be different.
+
+First install the toolchains:
+
+ sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
+
+To build executables for Windows 32-bit:
+
+ cd depends
+ make HOST=i686-w64-mingw32 -j4
+ cd ..
+ ./configure --prefix=`pwd`/depends/i686-w64-mingw32
+ make
+
+To build executables for Windows 64-bit:
+
+ cd depends
+ make HOST=x86_64-w64-mingw32 -j4
+ cd ..
+ ./configure --prefix=`pwd`/depends/x86_64-w64-mingw32
+ make
+
+For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory.
+
diff --git a/src/init.cpp b/src/init.cpp
index 76adca7692..cc055900f5 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -222,7 +222,6 @@ void Shutdown()
#if ENABLE_ZMQ
if (pzmqNotificationInterface) {
UnregisterValidationInterface(pzmqNotificationInterface);
- pzmqNotificationInterface->Shutdown();
delete pzmqNotificationInterface;
pzmqNotificationInterface = NULL;
}
@@ -307,8 +306,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
- strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288));
- strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3));
+ strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), DEFAULT_CHECKBLOCKS));
+ strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), DEFAULT_CHECKLEVEL));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "bitcoin.conf"));
if (mode == HMM_BITCOIND)
{
@@ -377,7 +376,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
if (showDebug)
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
- CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
@@ -407,12 +406,16 @@ std::string HelpMessage(HelpMessageMode mode)
if (showDebug)
{
strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", 1));
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)", 100));
+#ifdef ENABLE_WALLET
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
+#endif
strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", 0));
strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", 0));
strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
+#ifdef ENABLE_WALLET
strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
+#endif
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT));
strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
@@ -425,7 +428,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
- strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
+ strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), DEFAULT_GENERATE_THREADS));
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1));
@@ -436,7 +439,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
}
- strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"),
+ strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)"),
CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
if (showDebug)
@@ -1176,7 +1179,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
if (pzmqNotificationInterface) {
- pzmqNotificationInterface->Initialize();
RegisterValidationInterface(pzmqNotificationInterface);
}
#endif
@@ -1289,9 +1291,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
uiInterface.InitMessage(_("Verifying blocks..."));
- if (fHavePruned && GetArg("-checkblocks", 288) > MIN_BLOCKS_TO_KEEP) {
+ if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
- MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288));
+ MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", DEFAULT_CHECKBLOCKS));
}
{
@@ -1305,8 +1307,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3),
- GetArg("-checkblocks", 288))) {
+ if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected");
break;
}
@@ -1573,7 +1575,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
scheduler.scheduleEvery(f, nPowTargetSpacing);
// Generate coins in the background
- GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params());
+ GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", DEFAULT_GENERATE_THREADS), Params());
// ********************************************************* Step 12: finished
diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc
index ef2ecae830..e11a96b791 100644
--- a/src/leveldb/util/env_win.cc
+++ b/src/leveldb/util/env_win.cc
@@ -103,39 +103,20 @@ private:
DISALLOW_COPY_AND_ASSIGN(Win32RandomAccessFile);
};
-class Win32MapFile : public WritableFile
+class Win32WritableFile : public WritableFile
{
public:
- Win32MapFile(const std::string& fname);
+ Win32WritableFile(const std::string& fname);
+ ~Win32WritableFile();
- ~Win32MapFile();
virtual Status Append(const Slice& data);
virtual Status Close();
virtual Status Flush();
virtual Status Sync();
BOOL isEnable();
private:
- std::string _filename;
- HANDLE _hFile;
- size_t _page_size;
- size_t _map_size; // How much extra memory to map at a time
- char* _base; // The mapped region
- HANDLE _base_handle;
- char* _limit; // Limit of the mapped region
- char* _dst; // Where to write next (in range [base_,limit_])
- char* _last_sync; // Where have we synced up to
- uint64_t _file_offset; // Offset of base_ in file
- //LARGE_INTEGER file_offset_;
- // Have we done an munmap of unsynced data?
- bool _pending_sync;
-
- // Roundup x to a multiple of y
- static size_t _Roundup(size_t x, size_t y);
- size_t _TruncateToPageBoundary(size_t s);
- bool _UnmapCurrentRegion();
- bool _MapNewRegion();
- DISALLOW_COPY_AND_ASSIGN(Win32MapFile);
- BOOL _Init(LPCWSTR Path);
+ std::string filename_;
+ ::HANDLE _hFile;
};
class Win32FileLock : public FileLock
@@ -442,202 +423,63 @@ void Win32RandomAccessFile::_CleanUp()
}
}
-size_t Win32MapFile::_Roundup( size_t x, size_t y )
+Win32WritableFile::Win32WritableFile(const std::string& fname)
+ : filename_(fname)
{
- return ((x + y - 1) / y) * y;
+ std::wstring path;
+ ToWidePath(fname, path);
+ DWORD Flag = PathFileExistsW(path.c_str()) ? OPEN_EXISTING : CREATE_ALWAYS;
+ _hFile = CreateFileW(path.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
+ NULL,
+ Flag,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ // CreateFileW returns INVALID_HANDLE_VALUE in case of error, always check isEnable() before use
}
-size_t Win32MapFile::_TruncateToPageBoundary( size_t s )
+Win32WritableFile::~Win32WritableFile()
{
- s -= (s & (_page_size - 1));
- assert((s % _page_size) == 0);
- return s;
+ if (_hFile != INVALID_HANDLE_VALUE)
+ Close();
}
-bool Win32MapFile::_UnmapCurrentRegion()
+Status Win32WritableFile::Append(const Slice& data)
{
- bool result = true;
- if (_base != NULL) {
- if (_last_sync < _limit) {
- // Defer syncing this data until next Sync() call, if any
- _pending_sync = true;
- }
- if (!UnmapViewOfFile(_base) || !CloseHandle(_base_handle))
- result = false;
- _file_offset += _limit - _base;
- _base = NULL;
- _base_handle = NULL;
- _limit = NULL;
- _last_sync = NULL;
- _dst = NULL;
- // Increase the amount we map the next time, but capped at 1MB
- if (_map_size < (1<<20)) {
- _map_size *= 2;
- }
+ DWORD r = 0;
+ if (!WriteFile(_hFile, data.data(), data.size(), &r, NULL) || r != data.size()) {
+ return Status::IOError("Win32WritableFile.Append::WriteFile: "+filename_, Win32::GetLastErrSz());
}
- return result;
-}
-
-bool Win32MapFile::_MapNewRegion()
-{
- assert(_base == NULL);
- //LONG newSizeHigh = (LONG)((file_offset_ + map_size_) >> 32);
- //LONG newSizeLow = (LONG)((file_offset_ + map_size_) & 0xFFFFFFFF);
- DWORD off_hi = (DWORD)(_file_offset >> 32);
- DWORD off_lo = (DWORD)(_file_offset & 0xFFFFFFFF);
- LARGE_INTEGER newSize;
- newSize.QuadPart = _file_offset + _map_size;
- SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN);
- SetEndOfFile(_hFile);
-
- _base_handle = CreateFileMappingA(
- _hFile,
- NULL,
- PAGE_READWRITE,
- 0,
- 0,
- 0);
- if (_base_handle != NULL) {
- _base = (char*) MapViewOfFile(_base_handle,
- FILE_MAP_ALL_ACCESS,
- off_hi,
- off_lo,
- _map_size);
- if (_base != NULL) {
- _limit = _base + _map_size;
- _dst = _base;
- _last_sync = _base;
- return true;
- }
- }
- return false;
+ return Status::OK();
}
-Win32MapFile::Win32MapFile( const std::string& fname) :
- _filename(fname),
- _hFile(NULL),
- _page_size(Win32::g_PageSize),
- _map_size(_Roundup(65536, Win32::g_PageSize)),
- _base(NULL),
- _base_handle(NULL),
- _limit(NULL),
- _dst(NULL),
- _last_sync(NULL),
- _file_offset(0),
- _pending_sync(false)
+Status Win32WritableFile::Close()
{
- std::wstring path;
- ToWidePath(fname, path);
- _Init(path.c_str());
- assert((Win32::g_PageSize & (Win32::g_PageSize - 1)) == 0);
-}
-
-Status Win32MapFile::Append( const Slice& data )
-{
- const char* src = data.data();
- size_t left = data.size();
- Status s;
- while (left > 0) {
- assert(_base <= _dst);
- assert(_dst <= _limit);
- size_t avail = _limit - _dst;
- if (avail == 0) {
- if (!_UnmapCurrentRegion() ||
- !_MapNewRegion()) {
- return Status::IOError("WinMmapFile.Append::UnmapCurrentRegion or MapNewRegion: ", Win32::GetLastErrSz());
- }
- }
- size_t n = (left <= avail) ? left : avail;
- memcpy(_dst, src, n);
- _dst += n;
- src += n;
- left -= n;
- }
- return s;
-}
-
-Status Win32MapFile::Close()
-{
- Status s;
- size_t unused = _limit - _dst;
- if (!_UnmapCurrentRegion()) {
- s = Status::IOError("WinMmapFile.Close::UnmapCurrentRegion: ",Win32::GetLastErrSz());
- } else if (unused > 0) {
- // Trim the extra space at the end of the file
- LARGE_INTEGER newSize;
- newSize.QuadPart = _file_offset - unused;
- if (!SetFilePointerEx(_hFile, newSize, NULL, FILE_BEGIN)) {
- s = Status::IOError("WinMmapFile.Close::SetFilePointer: ",Win32::GetLastErrSz());
- } else
- SetEndOfFile(_hFile);
- }
if (!CloseHandle(_hFile)) {
- if (s.ok()) {
- s = Status::IOError("WinMmapFile.Close::CloseHandle: ", Win32::GetLastErrSz());
- }
+ return Status::IOError("Win32WritableFile.Close::CloseHandle: "+filename_, Win32::GetLastErrSz());
}
_hFile = INVALID_HANDLE_VALUE;
- _base = NULL;
- _base_handle = NULL;
- _limit = NULL;
-
- return s;
-}
-
-Status Win32MapFile::Sync()
-{
- Status s;
- if (_pending_sync) {
- // Some unmapped data was not synced
- _pending_sync = false;
- if (!FlushFileBuffers(_hFile)) {
- s = Status::IOError("WinMmapFile.Sync::FlushFileBuffers: ",Win32::GetLastErrSz());
- }
- }
- if (_dst > _last_sync) {
- // Find the beginnings of the pages that contain the first and last
- // bytes to be synced.
- size_t p1 = _TruncateToPageBoundary(_last_sync - _base);
- size_t p2 = _TruncateToPageBoundary(_dst - _base - 1);
- _last_sync = _dst;
- if (!FlushViewOfFile(_base + p1, p2 - p1 + _page_size)) {
- s = Status::IOError("WinMmapFile.Sync::FlushViewOfFile: ",Win32::GetLastErrSz());
- }
- }
- return s;
+ return Status::OK();
}
-Status Win32MapFile::Flush()
+Status Win32WritableFile::Flush()
{
+ // Nothing to do here, there are no application-side buffers
return Status::OK();
}
-Win32MapFile::~Win32MapFile()
+Status Win32WritableFile::Sync()
{
- if (_hFile != INVALID_HANDLE_VALUE) {
- Win32MapFile::Close();
+ if (!FlushFileBuffers(_hFile)) {
+ return Status::IOError("Win32WritableFile.Sync::FlushFileBuffers "+filename_, Win32::GetLastErrSz());
}
+ return Status::OK();
}
-BOOL Win32MapFile::_Init( LPCWSTR Path )
-{
- DWORD Flag = PathFileExistsW(Path) ? OPEN_EXISTING : CREATE_ALWAYS;
- _hFile = CreateFileW(Path,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
- NULL,
- Flag,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if(!_hFile || _hFile == INVALID_HANDLE_VALUE)
- return FALSE;
- else
- return TRUE;
-}
-
-BOOL Win32MapFile::isEnable()
+BOOL Win32WritableFile::isEnable()
{
- return _hFile ? TRUE : FALSE;
+ return _hFile != INVALID_HANDLE_VALUE;
}
Win32FileLock::Win32FileLock( const std::string& fname ) :
@@ -981,7 +823,7 @@ Status Win32Env::NewLogger( const std::string& fname, Logger** result )
{
Status sRet;
std::string path = fname;
- Win32MapFile* pMapFile = new Win32MapFile(ModifyPath(path));
+ Win32WritableFile* pMapFile = new Win32WritableFile(ModifyPath(path));
if(!pMapFile->isEnable()){
delete pMapFile;
*result = NULL;
@@ -995,7 +837,7 @@ Status Win32Env::NewWritableFile( const std::string& fname, WritableFile** resul
{
Status sRet;
std::string path = fname;
- Win32MapFile* pFile = new Win32MapFile(ModifyPath(path));
+ Win32WritableFile* pFile = new Win32WritableFile(ModifyPath(path));
if(!pFile->isEnable()){
*result = NULL;
sRet = Status::IOError(fname,Win32::GetLastErrSz());
diff --git a/src/main.cpp b/src/main.cpp
index e038fe3663..0199832f76 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -74,7 +74,7 @@ size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
bool fAlerts = DEFAULT_ALERTS;
-/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
+/** Fees smaller than this (in satoshi) are considered zero fee (for relaying, mining and transaction creation) */
CFeeRate minRelayTxFee = CFeeRate(1000);
CTxMemPool mempool(::minRelayTxFee);
diff --git a/src/main.h b/src/main.h
index 65732d770f..273a450867 100644
--- a/src/main.h
+++ b/src/main.h
@@ -127,6 +127,9 @@ extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
+static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP;
+static const unsigned int DEFAULT_CHECKLEVEL = 3;
+
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
// At 1MB per block, 288 blocks = 288MB.
// Add 15% for Undo data = 331MB
diff --git a/src/miner.h b/src/miner.h
index 7e0e58d540..ad13204818 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -17,6 +17,8 @@ class CScript;
class CWallet;
namespace Consensus { struct Params; };
+static const int DEFAULT_GENERATE_THREADS = 1;
+
struct CBlockTemplate
{
CBlock block;
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index c5ac07cfc2..a488d298c4 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -218,7 +218,7 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
QFont font;
if(index.column() == Address)
{
- font = GUIUtil::bitcoinAddressFont();
+ font = GUIUtil::fixedPitchFont();
}
return font;
}
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 51008ad2de..81b2597c3b 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -567,7 +567,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nChange -= nPayFee;
// Never create dust outputs; if we would, just add the dust to the fee.
- if (nChange > 0 && nChange < CENT)
+ if (nChange > 0 && nChange < MIN_CHANGE)
{
CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
if (txout.IsDust(::minRelayTxFee))
@@ -636,21 +636,21 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// tool tips
QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK())) + "<br /><br />";
+ toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
toolTip1 += tr("Can vary +/- 1 byte per input.");
QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::minTxFee.GetFeePerK()));
+ toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546)));
// how many satoshis the estimated fee can vary per byte we guess wrong
double dFeeVary;
if (payTxFee.GetFeePerK() > 0)
- dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), payTxFee.GetFeePerK()) / 1000;
+ dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), payTxFee.GetFeePerK()) / 1000;
else
- dFeeVary = (double)std::max(CWallet::minTxFee.GetFeePerK(), mempool.estimateFee(nTxConfirmTarget).GetFeePerK()) / 1000;
+ dFeeVary = (double)std::max(CWallet::GetRequiredFee(1000), mempool.estimateFee(nTxConfirmTarget).GetFeePerK()) / 1000;
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
l3->setToolTip(toolTip4);
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 8917f77f22..1c0056a7bd 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -88,7 +88,7 @@ QString dateTimeStr(qint64 nTime)
return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
}
-QFont bitcoinAddressFont()
+QFont fixedPitchFont()
{
QFont font("Monospace");
#if QT_VERSION >= 0x040800
@@ -103,7 +103,7 @@ void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
{
parent->setFocusProxy(widget);
- widget->setFont(bitcoinAddressFont());
+ widget->setFont(fixedPitchFont());
#if QT_VERSION >= 0x040700
// We don't want translators to use own addresses in translations
// and this is the only place, where this address is supplied.
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 0ac3db6327..ec678c4af2 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -37,8 +37,8 @@ namespace GUIUtil
QString dateTimeStr(const QDateTime &datetime);
QString dateTimeStr(qint64 nTime);
- // Render Bitcoin addresses in monospace font
- QFont bitcoinAddressFont();
+ // Return a monospace font
+ QFont fixedPitchFont();
// Set up widgets for address and amounts
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent);
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index f57c1203f6..d0191fa6d8 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -18,7 +18,7 @@
#include "txdb.h" // for -dbcache defaults
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h" // for CWallet::minTxFee
+#include "wallet/wallet.h" // for CWallet::GetRequiredFee()
#endif
#include <boost/thread.hpp>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index f387a3ec8c..8401701821 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -462,13 +462,19 @@ void RPCConsole::clear()
}
// Set default style sheet
+ QFontInfo fixedFontInfo(GUIUtil::fixedPitchFont());
+ // Try to make fixed font adequately large on different OS
+ QString ptSize = QString("%1pt").arg(QFontInfo(QFont()).pointSize() * 8.5 / 9);
ui->messagesWidget->document()->setDefaultStyleSheet(
+ QString(
"table { }"
"td.time { color: #808080; padding-top: 3px; } "
+ "td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
"td.cmd-request { color: #006060; } "
"td.cmd-error { color: red; } "
"b { color: #006060; } "
- );
+ ).arg(fixedFontInfo.family(), ptSize)
+ );
message(CMD_REPLY, (tr("Welcome to the Bitcoin Core RPC console.") + "<br>" +
tr("Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen.") + "<br>" +
@@ -494,7 +500,7 @@ void RPCConsole::message(int category, const QString &message, bool html)
if(html)
out += message;
else
- out += GUIUtil::HtmlEscape(message, true);
+ out += GUIUtil::HtmlEscape(message, false);
out += "</td></tr></table>";
ui->messagesWidget->append(out);
}
@@ -849,4 +855,4 @@ void RPCConsole::showOrHideBanTableIfRequired()
bool visible = clientModel->getBanTableModel()->shouldShow();
ui->banlistWidget->setVisible(visible);
ui->banHeading->setVisible(visible);
-} \ No newline at end of file
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index b86f776786..d5932ff149 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -71,6 +71,7 @@ private Q_SLOTS:
public Q_SLOTS:
void clear();
+ /** Append the message to the message widget */
void message(int category, const QString &message, bool html = false);
/** Set number of connections shown in the UI */
void setNumConnections(int count);
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index a083a6f80e..ab277171c8 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -172,7 +172,7 @@ void SendCoinsDialog::setModel(WalletModel *model)
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables()));
connect(ui->checkBoxFreeTx, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- ui->customFee->setSingleStep(CWallet::minTxFee.GetFeePerK());
+ ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
@@ -569,7 +569,7 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
void SendCoinsDialog::setMinimumFee()
{
ui->radioCustomPerKilobyte->setChecked(true);
- ui->customFee->setValue(CWallet::minTxFee.GetFeePerK());
+ ui->customFee->setValue(CWallet::GetRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls()
@@ -621,8 +621,8 @@ void SendCoinsDialog::updateFeeMinimizedLabel()
void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
- ui->checkBoxMinimumFee->setText(tr("Pay only the minimum fee of %1").arg(
- BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB")
+ ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
+ BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB")
);
}
@@ -635,7 +635,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
CFeeRate feeRate = mempool.estimateFee(nBlocksToConfirm);
if (feeRate <= CFeeRate(0)) // not enough data => minfee
{
- ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::minTxFee.GetFeePerK()) + "/kB");
+ ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB");
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
ui->labelFeeEstimation->setText("");
}
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 44aa8ad1af..4f4b5b70d5 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -40,7 +40,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *pare
// normal bitcoin address field
GUIUtil::setupAddressWidget(ui->payTo, this);
// just a label for displaying bitcoin address(es)
- ui->payTo_is->setFont(GUIUtil::bitcoinAddressFont());
+ ui->payTo_is->setFont(GUIUtil::fixedPitchFont());
// Connect signals
connect(ui->payAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged()));
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 60e8e36ebe..96f50a2656 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -51,8 +51,8 @@ SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformSt
ui->messageIn_VM->installEventFilter(this);
ui->signatureIn_VM->installEventFilter(this);
- ui->signatureOut_SM->setFont(GUIUtil::bitcoinAddressFont());
- ui->signatureIn_VM->setFont(GUIUtil::bitcoinAddressFont());
+ ui->signatureOut_SM->setFont(GUIUtil::fixedPitchFont());
+ ui->signatureIn_VM->setFont(GUIUtil::fixedPitchFont());
}
SignVerifyMessageDialog::~SignVerifyMessageDialog()
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 4786d72a3f..146eb3905a 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -539,13 +539,15 @@ UniValue gettxout(const UniValue& params, bool fHelp)
UniValue verifychain(const UniValue& params, bool fHelp)
{
+ int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
+ int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (fHelp || params.size() > 2)
throw runtime_error(
"verifychain ( checklevel numblocks )\n"
"\nVerifies blockchain database.\n"
"\nArguments:\n"
- "1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n"
- "2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n"
+ "1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n"
+ "2. numblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n"
"\nResult:\n"
"true|false (boolean) Verified or not\n"
"\nExamples:\n"
@@ -555,8 +557,6 @@ UniValue verifychain(const UniValue& params, bool fHelp)
LOCK(cs_main);
- int nCheckLevel = GetArg("-checklevel", 3);
- int nCheckDepth = GetArg("-checkblocks", 288);
if (params.size() > 0)
nCheckLevel = params[0].get_int();
if (params.size() > 1)
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index c49c3e5194..f42b31627c 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -211,7 +211,7 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
if (params.size() > 0)
fGenerate = params[0].get_bool();
- int nGenProcLimit = -1;
+ int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS);
if (params.size() > 1)
{
nGenProcLimit = params[1].get_int();
@@ -259,7 +259,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
- obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
+ obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS)));
obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index e5bc653c33..cf6122813c 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -293,7 +293,7 @@ void CDB::Flush()
if (fReadOnly)
nMinutes = 1;
- bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100) * 1024 : 0, nMinutes, 0);
+ bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
}
void CDB::Close()
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 64071caa3a..46bc0ac0a9 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -20,6 +20,8 @@
#include <db_cxx.h>
+static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
+
extern unsigned int nWalletDBUpdated;
class CDBEnv
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index a5bc52b8dc..8b9292bd14 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
BOOST_CHECK( wallet.SelectCoinsMinConf(34 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_GT(nValueRet, 34 * CENT); // but should get more than 34 cents
+ BOOST_CHECK_EQUAL(nValueRet, 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
@@ -185,33 +185,34 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
BOOST_CHECK_EQUAL(nValueRet, 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
- // empty the wallet and start again, now with fractions of a cent, to test sub-cent change avoidance
+ // empty the wallet and start again, now with fractions of a cent, to test small change avoidance
+
empty_wallet();
- add_coin(0.1*CENT);
- add_coin(0.2*CENT);
- add_coin(0.3*CENT);
- add_coin(0.4*CENT);
- add_coin(0.5*CENT);
-
- // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 = 1.5 cents
- // we'll get sub-cent change whatever happens, so can expect 1.0 exactly
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
+ add_coin(0.1*MIN_CHANGE);
+ add_coin(0.2*MIN_CHANGE);
+ add_coin(0.3*MIN_CHANGE);
+ add_coin(0.4*MIN_CHANGE);
+ add_coin(0.5*MIN_CHANGE);
+
+ // try making 1 * MIN_CHANGE from the 1.5 * MIN_CHANGE
+ // we'll get change smaller than MIN_CHANGE whatever happens, so can expect MIN_CHANGE exactly
+ BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE);
- // but if we add a bigger coin, making it possible to avoid sub-cent change, things change:
- add_coin(1111*CENT);
+ // but if we add a bigger coin, small change is avoided
+ add_coin(1111*MIN_CHANGE);
- // try making 1 cent from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5 cents
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
+ // try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
+ BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
- // if we add more sub-cent coins:
- add_coin(0.6*CENT);
- add_coin(0.7*CENT);
+ // if we add more small coins:
+ add_coin(0.6*MIN_CHANGE);
+ add_coin(0.7*MIN_CHANGE);
- // and try again to make 1.0 cents, we can still make 1.0 cents
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
+ // and try again to make 1.0 * MIN_CHANGE
+ BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
@@ -223,45 +224,65 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
BOOST_CHECK_EQUAL(nValueRet, 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 10U); // in ten coins
- // if there's not enough in the smaller coins to make at least 1 cent change (0.5+0.6+0.7 < 1.0+1.0),
+ // if there's not enough in the smaller coins to make at least 1 * MIN_CHANGE change (0.5+0.6+0.7 < 1.0+1.0),
// we need to try finding an exact subset anyway
// sometimes it will fail, and so we use the next biggest coin:
empty_wallet();
- add_coin(0.5 * CENT);
- add_coin(0.6 * CENT);
- add_coin(0.7 * CENT);
- add_coin(1111 * CENT);
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1111 * CENT); // we get the bigger coin
+ add_coin(0.5 * MIN_CHANGE);
+ add_coin(0.6 * MIN_CHANGE);
+ add_coin(0.7 * MIN_CHANGE);
+ add_coin(1111 * MIN_CHANGE);
+ BOOST_CHECK( wallet.SelectCoinsMinConf(1 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1111 * MIN_CHANGE); // we get the bigger coin
BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)
empty_wallet();
- add_coin(0.4 * CENT);
- add_coin(0.6 * CENT);
- add_coin(0.8 * CENT);
- add_coin(1111 * CENT);
- BOOST_CHECK( wallet.SelectCoinsMinConf(1 * CENT, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1 * CENT); // we should get the exact amount
+ add_coin(0.4 * MIN_CHANGE);
+ add_coin(0.6 * MIN_CHANGE);
+ add_coin(0.8 * MIN_CHANGE);
+ add_coin(1111 * MIN_CHANGE);
+ BOOST_CHECK( wallet.SelectCoinsMinConf(MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, MIN_CHANGE); // we should get the exact amount
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U); // in two coins 0.4+0.6
- // test avoiding sub-cent change
+ // test avoiding small change
empty_wallet();
- add_coin(0.0005 * COIN);
- add_coin(0.01 * COIN);
- add_coin(1 * COIN);
+ add_coin(0.05 * MIN_CHANGE);
+ add_coin(1 * MIN_CHANGE);
+ add_coin(100 * MIN_CHANGE);
- // trying to make 1.0001 from these three coins
- BOOST_CHECK( wallet.SelectCoinsMinConf(1.0001 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1.0105 * COIN); // we should get all coins
+ // trying to make 100.01 from these three coins
+ BOOST_CHECK( wallet.SelectCoinsMinConf(100.01 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 101.05 * MIN_CHANGE); // we should get all coins
BOOST_CHECK_EQUAL(setCoinsRet.size(), 3U);
- // but if we try to make 0.999, we should take the bigger of the two small coins to avoid sub-cent change
- BOOST_CHECK( wallet.SelectCoinsMinConf(0.999 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
- BOOST_CHECK_EQUAL(nValueRet, 1.01 * COIN); // we should get 1 + 0.01
+ // but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
+ BOOST_CHECK( wallet.SelectCoinsMinConf(99.9 * MIN_CHANGE, 1, 1, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 101 * MIN_CHANGE);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
+ // test with many inputs
+ for (CAmount amt=1500; amt < COIN; amt*=10) {
+ empty_wallet();
+ // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input)
+ for (uint16_t j = 0; j < 676; j++)
+ add_coin(amt);
+ BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, vCoins, setCoinsRet, nValueRet));
+ if (amt - 2000 < MIN_CHANGE) {
+ // needs more than one input:
+ uint16_t returnSize = std::ceil((2000.0 + MIN_CHANGE)/amt);
+ CAmount returnValue = amt * returnSize;
+ BOOST_CHECK_EQUAL(nValueRet, returnValue);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), returnSize);
+ } else {
+ // one input is sufficient:
+ BOOST_CHECK_EQUAL(nValueRet, amt);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 1U);
+ }
+ }
+
// test randomness
{
empty_wallet();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 3f2d5a05f6..cce3e40f38 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -47,7 +47,7 @@ bool fPayAtLeastCustomFee = true;
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)
* Override with -mintxfee
*/
-CFeeRate CWallet::minTxFee = CFeeRate(1000);
+CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE);
/** @defgroup mapWallet
*
@@ -1497,9 +1497,6 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
return nTotal;
}
-/**
- * populate vCoins with vector of available COutputs.
- */
void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const
{
vCoins.clear();
@@ -1619,7 +1616,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
nValueRet += coin.first;
return true;
}
- else if (n < nTargetValue + CENT)
+ else if (n < nTargetValue + MIN_CHANGE)
{
vValue.push_back(coin);
nTotalLower += n;
@@ -1654,14 +1651,14 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
vector<char> vfBest;
CAmount nBest;
- ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000);
- if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT)
- ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000);
+ ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);
+ if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE)
+ ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
// or the next bigger coin is closer), return the bigger coin
if (coinLowestLarger.second.first &&
- ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest))
+ ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest))
{
setCoinsRet.insert(coinLowestLarger.second);
nValueRet += coinLowestLarger.first;
@@ -1844,6 +1841,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
LOCK2(cs_main, cs_wallet);
{
nFeeRet = 0;
+ // Start with no fee and loop until there is enough fee
while (true)
{
txNew.vin.clear();
@@ -2120,6 +2118,11 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
return true;
}
+CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
+{
+ return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
+}
+
CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool)
{
// payTxFee is user-set "I want to pay this much"
@@ -2131,9 +2134,9 @@ CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarge
if (nFeeNeeded == 0)
nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes);
// ... unless we don't have enough mempool data, in which case fall
- // back to a hard-coded fee
+ // back to the required fee
if (nFeeNeeded == 0)
- nFeeNeeded = minTxFee.GetFee(nTxBytes);
+ nFeeNeeded = GetRequiredFee(nTxBytes);
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes))
nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 34e98cfb81..719f11f206 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -41,8 +41,12 @@ extern bool fPayAtLeastCustomFee;
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
+//! -mintxfee default
+static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
//! -maxtxfee default
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
+//! minimum change amount
+static const CAmount MIN_CHANGE = CENT;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
@@ -442,6 +446,11 @@ public:
class CWallet : public CCryptoKeyStore, public CValidationInterface
{
private:
+ /**
+ * Select a set of coins such that nValueRet >= nTargetValue and at least
+ * all coins from coinControl are selected; Never select unconfirmed coins
+ * if they are not ours
+ */
bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const;
CWalletDB *pwalletdbEncryption;
@@ -539,7 +548,17 @@ public:
//! check whether we are allowed to upgrade (or already support) to the named feature
bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
+ /**
+ * populate vCoins with vector of available COutputs.
+ */
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const;
+
+ /**
+ * Shuffle and select coins until nTargetValue is reached while avoiding
+ * small change; This method is stochastic for some inputs and upon
+ * completion the coin set and corresponding actual target value is
+ * assembled
+ */
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
bool IsSpent(const uint256& hash, unsigned int n) const;
@@ -622,13 +641,32 @@ public:
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
+
+ /**
+ * Insert additional inputs into the transaction by
+ * calling CreateTransaction();
+ */
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, bool includeWatching);
+
+ /**
+ * Create a new transaction paying the recipients with a set of coins
+ * selected by SelectCoins(); Also create the change output, when needed
+ */
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
static CFeeRate minTxFee;
+ /**
+ * Estimate the minimum fee considering user set parameters
+ * and the required fee
+ */
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
+ /**
+ * Return the minimum required fee taking into account the
+ * floating relay fee and user set minimum transaction fee
+ */
+ static CAmount GetRequiredFee(unsigned int nTxBytes);
bool NewKeyPool();
bool TopUpKeyPool(unsigned int kpSize = 0);
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 388b86707b..09fe3aeb4c 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -21,8 +21,7 @@ CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL)
CZMQNotificationInterface::~CZMQNotificationInterface()
{
- // ensure Shutdown if Initialize is called
- assert(!pcontext);
+ Shutdown();
for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)
{
@@ -59,6 +58,12 @@ CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const
{
notificationInterface = new CZMQNotificationInterface();
notificationInterface->notifiers = notifiers;
+
+ if (!notificationInterface->Initialize())
+ {
+ delete notificationInterface;
+ notificationInterface = NULL;
+ }
}
return notificationInterface;
@@ -99,7 +104,7 @@ bool CZMQNotificationInterface::Initialize()
return false;
}
- return false;
+ return true;
}
// Called during shutdown sequence
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index 8eea15c068..3ccfaf341d 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -19,10 +19,11 @@ public:
static CZMQNotificationInterface* CreateWithArguments(const std::map<std::string, std::string> &args);
+protected:
bool Initialize();
void Shutdown();
-protected: // CValidationInterface
+ // CValidationInterface
void SyncTransaction(const CTransaction &tx, const CBlock *pblock);
void UpdatedBlockTip(const CBlockIndex *pindex);