diff options
-rw-r--r-- | build-aux/m4/bitcoin_qt.m4 | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | contrib/devtools/README.md | 5 | ||||
-rw-r--r-- | doc/build-osx.md | 2 | ||||
-rw-r--r-- | doc/build-unix.md | 19 | ||||
-rwxr-xr-x | qa/pull-tester/rpc-tests.py | 1 | ||||
-rwxr-xr-x | qa/rpc-tests/disablewallet.py | 32 | ||||
-rw-r--r-- | src/.clang-format | 3 | ||||
-rw-r--r-- | src/consensus/consensus.h | 6 | ||||
-rw-r--r-- | src/init.cpp | 2 | ||||
-rw-r--r-- | src/leveldb/util/env_win.cc | 236 | ||||
-rw-r--r-- | src/main.cpp | 53 | ||||
-rw-r--r-- | src/main.h | 4 | ||||
-rw-r--r-- | src/miner.cpp | 8 | ||||
-rw-r--r-- | src/policy/policy.h | 3 | ||||
-rw-r--r-- | src/qt/addresstablemodel.cpp | 2 | ||||
-rw-r--r-- | src/qt/coincontroldialog.cpp | 8 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 4 | ||||
-rw-r--r-- | src/qt/guiutil.h | 4 | ||||
-rw-r--r-- | src/qt/optionsdialog.cpp | 2 | ||||
-rw-r--r-- | src/qt/rpcconsole.cpp | 12 | ||||
-rw-r--r-- | src/qt/rpcconsole.h | 1 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 10 | ||||
-rw-r--r-- | src/qt/sendcoinsentry.cpp | 2 | ||||
-rw-r--r-- | src/qt/signverifymessagedialog.cpp | 4 | ||||
-rw-r--r-- | src/rpcmisc.cpp | 4 | ||||
-rw-r--r-- | src/test/miner_tests.cpp | 7 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 9 | ||||
-rw-r--r-- | src/wallet/wallet.h | 9 |
29 files changed, 206 insertions, 250 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/contrib/devtools/README.md b/contrib/devtools/README.md index 278794f14c..2e70c5adcc 100644 --- a/contrib/devtools/README.md +++ b/contrib/devtools/README.md @@ -62,6 +62,11 @@ optimize-pngs.py A script to optimize png files in the bitcoin repository (requires pngcrush). +security-check.py and test-security-check.py +============================================ + +Perform basic ELF security checks on a series of executables. + symbol-check.py =============== diff --git a/doc/build-osx.md b/doc/build-osx.md index 69c401b751..02498e5c4b 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -32,7 +32,7 @@ Instructions: Homebrew #### Install dependencies using Homebrew - brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 libevent + brew install autoconf automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf qt5 libevent NOTE: Building with Qt4 is still supported, however, could result in a broken UI. As such, building with Qt5 is recommended. diff --git a/doc/build-unix.md b/doc/build-unix.md index 25867e2993..57853a9c9d 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -61,24 +61,24 @@ 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 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: - 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 + 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 For Ubuntu before 15.10, or Debian 7 and later libboost-all-dev has to be installed: - sudo apt-get install libboost-all-dev + 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 + sudo add-apt-repository ppa:bitcoin/bitcoin + sudo apt-get update + sudo apt-get install libdb4.8-dev libdb4.8++-dev 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 @@ -89,18 +89,18 @@ 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) + 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 5 or Qt 4 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. +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 5 (recommended) you need the following: @@ -213,6 +213,7 @@ Hardening enables the following features: scanelf -e ./bitcoin The output should contain: + TYPE ET_DYN diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 3059fee426..c23dcbdb7c 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -68,6 +68,7 @@ testScripts = [ 'decodescript.py', 'p2p-fullblocktest.py', 'blockchain.py', + 'disablewallet.py', ] testScriptsExt = [ 'bip65-cltv.py', diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py new file mode 100755 index 0000000000..4cb01575e2 --- /dev/null +++ b/qa/rpc-tests/disablewallet.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Exercise API with -disablewallet. +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class DisableWalletTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir, [['-disablewallet']]) + self.is_network_split = False + self.sync_all() + + def run_test (self): + # Check regression: https://github.com/bitcoin/bitcoin/issues/6963#issuecomment-154548880 + x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') + assert(x['isvalid'] == False) + x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') + assert(x['isvalid'] == True) + +if __name__ == '__main__': + DisableWalletTest ().main () diff --git a/src/.clang-format b/src/.clang-format index 226a15d185..129f062ef8 100644 --- a/src/.clang-format +++ b/src/.clang-format @@ -1,4 +1,6 @@ +Language: Cpp AccessModifierOffset: -4 +AlignAfterOpenBracket: false AlignEscapedNewlinesLeft: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: false @@ -26,7 +28,6 @@ IndentCaseLabels: false IndentFunctionDeclarationAfterType: false IndentWidth: 4 KeepEmptyLinesAtTheStartOfBlocks: false -Language: Cpp MaxEmptyLinesToKeep: 2 NamespaceIndentation: None ObjCSpaceAfterProperty: false diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index f937844e9f..6d6ce7e099 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -13,4 +13,10 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; +/** Flags for LockTime() */ +enum { + /* Use GetMedianTimePast() instead of nTime for end point timestamp. */ + LOCKTIME_MEDIAN_TIME_PAST = (1 << 1), +}; + #endif // BITCOIN_CONSENSUS_CONSENSUS_H diff --git a/src/init.cpp b/src/init.cpp index 55ed153f1c..8fdafa392a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -439,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) 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 26a22ae6fd..9016fe42a0 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); @@ -650,10 +650,35 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) return true; } -bool CheckFinalTx(const CTransaction &tx) +bool CheckFinalTx(const CTransaction &tx, int flags) { AssertLockHeld(cs_main); - return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime()); + + // By convention a negative value for flags indicates that the + // current network-enforced consensus rules should be used. In + // a future soft-fork scenario that would mean checking which + // rules would be enforced for the next block and setting the + // appropriate flags. At the present time no soft-forks are + // scheduled, so no flags are set. + flags = std::max(flags, 0); + + // CheckFinalTx() uses chainActive.Height()+1 to evaluate + // nLockTime because when IsFinalTx() is called within + // CBlock::AcceptBlock(), the height of the block *being* + // evaluated is what is used. Thus if we want to know if a + // transaction can be part of the *next* block, we need to call + // IsFinalTx() with one more than chainActive.Height(). + const int nBlockHeight = chainActive.Height() + 1; + + // Timestamps on the other hand don't get any special treatment, + // because we can't know what timestamp the next block will have, + // and there aren't timestamp applications where it matters. + // However this changes once median past time-locks are enforced: + const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) + ? chainActive.Tip()->GetMedianTimePast() + : GetAdjustedTime(); + + return IsFinalTx(tx, nBlockHeight, nBlockTime); } unsigned int GetLegacySigOpCount(const CTransaction& tx) @@ -797,7 +822,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. - if (!CheckFinalTx(tx)) + if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); // is it already in the memory pool? @@ -2517,8 +2542,6 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd if (!fKnown) { while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { - LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); - FlushBlockFile(true); nFile++; if (vinfoBlockFile.size() <= nFile) { vinfoBlockFile.resize(nFile + 1); @@ -2528,7 +2551,14 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd pos.nPos = vinfoBlockFile[nFile].nSize; } - nLastBlockFile = nFile; + if (nFile != nLastBlockFile) { + if (!fKnown) { + LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); + } + FlushBlockFile(!fKnown); + nLastBlockFile = nFile; + } + vinfoBlockFile[nFile].AddBlock(nHeight, nTime); if (fKnown) vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); @@ -2723,10 +2753,15 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn const Consensus::Params& consensusParams = Params().GetConsensus(); // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) { + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + int nLockTimeFlags = 0; + int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) + ? pindexPrev->GetMedianTimePast() + : block.GetBlockTime(); + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } + } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): diff --git a/src/main.h b/src/main.h index c3874be663..273a450867 100644 --- a/src/main.h +++ b/src/main.h @@ -311,8 +311,10 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); * Check if transaction will be final in the next block to be created. * * Calls IsFinalTx() with current block height and appropriate block time. + * + * See consensus/consensus.h for flag definitions. */ -bool CheckFinalTx(const CTransaction &tx); +bool CheckFinalTx(const CTransaction &tx, int flags = -1); /** * Closure representing one script verification diff --git a/src/miner.cpp b/src/miner.cpp index 42c8bb970b..053d9cdbc4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -148,6 +148,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) CBlockIndex* pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; pblock->nTime = GetAdjustedTime(); + const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); CCoinsViewCache view(pcoinsTip); // Priority order to process transactions @@ -162,7 +163,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) mi != mempool.mapTx.end(); ++mi) { const CTransaction& tx = mi->GetTx(); - if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime)) + + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) + ? nMedianTimePast + : pblock->GetBlockTime(); + + if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff)) continue; COrphan* porphan = NULL; diff --git a/src/policy/policy.h b/src/policy/policy.h index 747c5ce8ce..f269e8d476 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -43,6 +43,9 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY /** For convenience, standard but not mandatory verify flags. */ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; +/** Used as the flags parameter to CheckFinalTx() in non-consensus code */ +static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_MEDIAN_TIME_PAST; + bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType); /** * Check for standard transaction types 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 74bc8dbec9..81b2597c3b 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -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 9e4d77bb15..0ee08a1b0c 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(); @@ -570,7 +570,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() @@ -622,8 +622,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") ); } @@ -636,7 +636,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/rpcmisc.cpp b/src/rpcmisc.cpp index 0f0457c5cf..0c656d5cf1 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -117,7 +117,7 @@ public: UniValue obj(UniValue::VOBJ); CPubKey vchPubKey; obj.push_back(Pair("isscript", false)); - if (pwalletMain->GetPubKey(keyID, vchPubKey)) { + if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) { obj.push_back(Pair("pubkey", HexStr(vchPubKey))); obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); } @@ -128,7 +128,7 @@ public: UniValue obj(UniValue::VOBJ); CScript subscript; obj.push_back(Pair("isscript", true)); - if (pwalletMain->GetCScript(scriptID, subscript)) { + if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) { std::vector<CTxDestination> addresses; txnouttype whichType; int nRequired; diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 91a3a5738e..827525783a 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -4,6 +4,7 @@ #include "chainparams.h" #include "coins.h" +#include "consensus/consensus.h" #include "consensus/validation.h" #include "main.h" #include "miner.h" @@ -229,7 +230,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.nLockTime = chainActive.Tip()->nHeight+1; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(!CheckFinalTx(tx)); + BOOST_CHECK(!CheckFinalTx(tx, LOCKTIME_MEDIAN_TIME_PAST)); // time locked tx2.vin.resize(1); @@ -243,7 +244,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1; hash = tx2.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(!CheckFinalTx(tx2)); + BOOST_CHECK(!CheckFinalTx(tx2, LOCKTIME_MEDIAN_TIME_PAST)); BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); @@ -261,7 +262,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) //BOOST_CHECK(CheckFinalTx(tx2)); BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); - BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3); + BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 2); delete pblocktemplate; chainActive.Tip()->nHeight--; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 93c7c7f247..cce3e40f38 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2118,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" @@ -2129,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 7e8dcc2914..719f11f206 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -657,7 +657,16 @@ public: 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); |