diff options
34 files changed, 614 insertions, 212 deletions
diff --git a/configure.ac b/configure.ac index 34509993a0..af230c355d 100644 --- a/configure.ac +++ b/configure.ac @@ -531,10 +531,9 @@ else CPPFLAGS="$CPPFLAGS $QT_INCLUDES" fi ]) - - BITCOIN_QT_CHECK(AC_CHECK_HEADER([QtPlugin],,BITCOIN_QT_FAIL(QtCore headers missing),)) - BITCOIN_QT_CHECK(AC_CHECK_HEADER([QApplication],, BITCOIN_QT_FAIL(QtGui headers missing),)) - BITCOIN_QT_CHECK(AC_CHECK_HEADER([QLocalSocket],, BITCOIN_QT_FAIL(QtNetwork headers missing),)) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtPlugin],,BITCOIN_QT_FAIL(QtCore headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QApplication],, BITCOIN_QT_FAIL(QtGui headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QLocalSocket],, BITCOIN_QT_FAIL(QtNetwork headers missing))]) BITCOIN_QT_CHECK([ if test x$use_tests = xyes; then diff --git a/doc/build-osx.md b/doc/build-osx.md index f70da685e9..6268a440a8 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -62,7 +62,7 @@ Installing the dependencies using MacPorts is very straightforward. 3. It is a good idea to build and run the unit tests, too: - make test + make check Instructions: HomeBrew ---------------------- @@ -87,7 +87,7 @@ Rerunning "openssl version" should now return the correct version. 1. Clone the github tree to get the source code and go into the directory. - git clone git@github.com:bitcoin/bitcoin.git bitcoin + git clone https://github.com/bitcoin/bitcoin.git cd bitcoin 2. Build bitcoind: @@ -98,7 +98,7 @@ Rerunning "openssl version" should now return the correct version. 3. It is a good idea to build and run the unit tests, too: - make test + make check Creating a release build ------------------------ diff --git a/doc/build-unix.md b/doc/build-unix.md index 673d1502a0..b88186a70e 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -11,11 +11,6 @@ To Build This will build bitcoin-qt as well if the dependencies are met. -**Note:** on Ubuntu 13.10 (Saucy Salamander) the boost configuration script doesn't look in the -correct directory and an error about boost-system will appear. For now you need to do - - ./configure --with-boost-libdir=/usr/lib/x86_64-linux-gnu - Dependencies --------------------- @@ -93,7 +88,7 @@ are installed. Qt 4 is currently necessary to build the GUI. To build with Qt 4 you need the following: - apt-get install libqt4-dev libprotobuf-dev + apt-get install libqt4-dev libprotobuf-dev protobuf-compiler libqrencode (optional) can be installed with: @@ -190,3 +185,7 @@ disable-wallet mode with: ./configure --disable-wallet In this case there is no dependency on Berkeley DB 4.8. + +Mining is also possible in disable-wallet mode, but only using the `getblocktemplate` RPC +call not `getwork`. + diff --git a/doc/release-process.md b/doc/release-process.md index 3d5c577f86..2c0e2a3677 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -172,4 +172,15 @@ From a directory containing bitcoin source, gitian.sigs and gitian zips popd - Upload gitian zips to SourceForge + +- Announce the release: + + - Add the release to bitcoin.org: https://github.com/bitcoin/bitcoin.org/tree/master/_releases + + - Release sticky on bitcointalk: https://bitcointalk.org/index.php?board=1.0 + + - Bitcoin-development mailing list + + - Optionally reddit /r/Bitcoin, ... + - Celebrate diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index d0dd796561..54ced278f2 100644 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -4,18 +4,25 @@ <dict> <key>CFBundleIconFile</key> <string>bitcoin.icns</string> + <key>CFBundlePackageType</key> <string>APPL</string> + <key>CFBundleGetInfoString</key> <string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin developers</string> + <key>CFBundleShortVersionString</key> <string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@</string> + <key>CFBundleVersion</key> <string>@CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@</string> + <key>CFBundleSignature</key> <string>????</string> + <key>CFBundleExecutable</key> <string>Bitcoin-Qt</string> + <key>CFBundleIdentifier</key> <string>org.bitcoinfoundation.Bitcoin-Qt</string> @@ -69,7 +76,11 @@ <string>Owner</string> </dict> </array> + + <key>NSPrincipalClass</key> + <string>NSApplication</string> + <key>NSHighResolutionCapable</key> - <true/> + <string>True</string> </dict> </plist> diff --git a/src/Makefile.am b/src/Makefile.am index df4087c313..62dd63abef 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,9 +48,11 @@ libbitcoin_server_a_SOURCES = \ keystore.cpp \ leveldbwrapper.cpp \ main.cpp \ + miner.cpp \ net.cpp \ noui.cpp \ rpcblockchain.cpp \ + rpcmining.cpp \ rpcnet.cpp \ rpcrawtransaction.cpp \ txdb.cpp \ @@ -61,9 +63,7 @@ libbitcoin_server_a_SOURCES = \ libbitcoin_wallet_a_SOURCES = \ db.cpp \ crypter.cpp \ - miner.cpp \ rpcdump.cpp \ - rpcmining.cpp \ rpcwallet.cpp \ wallet.cpp \ walletdb.cpp \ diff --git a/src/init.cpp b/src/init.cpp index df3cedc202..40dd2d04cd 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -11,10 +11,11 @@ #include "addrman.h" #include "db.h" -#include "rpcserver.h" #include "checkpoints.h" +#include "main.h" #include "miner.h" #include "net.h" +#include "rpcserver.h" #include "txdb.h" #include "ui_interface.h" #include "util.h" @@ -113,8 +114,8 @@ void Shutdown() RenameThread("bitcoin-shutoff"); mempool.AddTransactionsUpdated(1); StopRPCThreads(); -#ifdef ENABLE_WALLET ShutdownRPCMining(); +#ifdef ENABLE_WALLET if (pwalletMain) bitdb.Flush(false); GenerateBitcoins(false, NULL, 0); @@ -199,9 +200,9 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n"; strUsage += " -dbcache=<n> " + _("Set database cache size in megabytes (default: 25)") + "\n"; strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n"; - strUsage += " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n"; - strUsage += " -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n"; - strUsage += " -onion=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"; + strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS proxy") + "\n"; + strUsage += " -socks=<n> " + _("Select SOCKS version for -proxy (4 or 5, default: 5)") + "\n"; + strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n"; strUsage += " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n"; strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n"; strUsage += " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n"; @@ -226,7 +227,7 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 0)") + "\n"; #endif #endif - strUsage += " -paytxfee=<amt> " + _("Fee per KB to add to transactions you send") + "\n"; + strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n"; strUsage += " -debug=<category> " + _("Output debugging information (default: 0, supplying <category> is optional)") + "\n"; strUsage += _("If <category> is not supplied, output all debugging information.") + "\n"; strUsage += _("<category> can be:"); @@ -243,7 +244,7 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += " -shrinkdebugfile " + _("Shrink debug.log file on client startup (default: 1 when no -debug)") + "\n"; strUsage += " -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n"; strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be " - "solved instantly. This is intended for regression testing tools and app development.") + "\n"; + "solved instantly. This is intended for regression testing tools and app development.") + "\n"; #ifdef WIN32 strUsage += " -printtodebugger " + _("Send trace/debug info to debugger") + "\n"; #endif @@ -281,9 +282,9 @@ std::string HelpMessage(HelpMessageMode hmm) strUsage += " -par=<n> " + _("Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)") + "\n"; strUsage += "\n" + _("Block creation options:") + "\n"; - strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n"; - strUsage += " -blockmaxsize=<n> " + _("Set maximum block size in bytes (default: 250000)") + "\n"; - strUsage += " -blockprioritysize=<n> " + _("Set maximum size of high-priority/low-fee transactions in bytes (default: 27000)") + "\n"; + strUsage += " -blockminsize=<n> " + _("Set minimum block size in bytes (default: 0)") + "\n"; + strUsage += " -blockmaxsize=<n> " + strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE) + "\n"; + strUsage += " -blockprioritysize=<n> " + strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE) + "\n"; strUsage += "\n" + _("SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n"; strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n"; @@ -1042,10 +1043,8 @@ bool AppInit2(boost::thread_group& threadGroup, bool fForceServer) #endif StartNode(threadGroup); -#ifdef ENABLE_WALLET // InitRPCMining is needed here so getwork/getblocktemplate in the GUI debug console works properly. InitRPCMining(); -#endif if (fServer) StartRPCThreads(); diff --git a/src/m4/ax_boost_base.m4 b/src/m4/ax_boost_base.m4 index 57d14fe48d..c675f12d84 100644 --- a/src/m4/ax_boost_base.m4 +++ b/src/m4/ax_boost_base.m4 @@ -33,7 +33,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 21 +#serial 22 AC_DEFUN([AX_BOOST_BASE], [ @@ -97,6 +97,12 @@ if test "x$want_boost" = "xyes"; then ;; esac + dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give + dnl them priority over the other paths since, if libs are found there, they + dnl are almost assuredly the ones desired. + AC_REQUIRE([AC_CANONICAL_HOST]) + libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs" + dnl first we check the system location for boost libraries dnl this location ist chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM diff --git a/src/main.h b/src/main.h index c52f37cc87..fd5e352cb6 100644 --- a/src/main.h +++ b/src/main.h @@ -35,10 +35,12 @@ class CInv; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 1000000; -/** The maximum size for mined blocks */ -static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; +/** Default for -blockmaxsize, maximum size for mined blocks **/ +static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; +/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/ +static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; /** The maximum size for transactions we're willing to relay/mine */ -static const unsigned int MAX_STANDARD_TX_SIZE = MAX_BLOCK_SIZE_GEN/5; +static const unsigned int MAX_STANDARD_TX_SIZE = 100000; /** The maximum allowed number of signature check operations in a block (network rule) */ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** The maximum number of orphan transactions kept in memory */ @@ -55,8 +57,6 @@ static const int COINBASE_MATURITY = 100; static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC /** Maximum number of script-checking threads allowed */ static const int MAX_SCRIPTCHECK_THREADS = 16; -/** Default amount of block size reserved for high-priority transactions (in bytes) */ -static const int DEFAULT_BLOCK_PRIORITY_SIZE = 27000; #ifdef USE_UPNP static const int fHaveUPnP = true; #else diff --git a/src/miner.cpp b/src/miner.cpp index ecc40ac708..edfbbf5736 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -10,9 +10,6 @@ #include "net.h" #include "wallet.h" -double dHashesPerSec = 0.0; -int64_t nHPSTimerStart = 0; - ////////////////////////////////////////////////////////////////////////////// // // BitcoinMiner @@ -54,41 +51,6 @@ void SHA256Transform(void* pstate, void* pinput, const void* pinit) ((uint32_t*)pstate)[i] = ctx.h[i]; } -// -// ScanHash scans nonces looking for a hash with at least some zero bits. -// It operates on big endian data. Caller does the byte reversing. -// All input buffers are 16-byte aligned. nNonce is usually preserved -// between calls, but periodically or if nNonce is 0xffff0000 or above, -// the block is rebuilt and nNonce starts over at zero. -// -unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) -{ - unsigned int& nNonce = *(unsigned int*)(pdata + 12); - for (;;) - { - // Crypto++ SHA256 - // Hash pdata using pmidstate as the starting state into - // pre-formatted buffer phash1, then hash phash1 into phash - nNonce++; - SHA256Transform(phash1, pdata, pmidstate); - SHA256Transform(phash, phash1, pSHA256InitState); - - // Return the nonce if the hash has at least some zero bits, - // caller will check if it has enough to reach the target - if (((unsigned short*)phash)[14] == 0) - return nNonce; - - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xffff) == 0) - { - nHashesDone = 0xffff+1; - return (unsigned int) -1; - } - if ((nNonce & 0xfff) == 0) - boost::this_thread::interruption_point(); - } -} - // Some explaining would be appreciated class COrphan { @@ -162,7 +124,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: - unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); + unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); @@ -381,16 +343,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return pblocktemplate.release(); } -CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) -{ - CPubKey pubkey; - if (!reservekey.GetReservedKey(pubkey)) - return NULL; - - CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG; - return CreateNewBlock(scriptPubKey); -} - void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { // Update nExtraNonce @@ -454,6 +406,58 @@ void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash memcpy(phash1, &tmp.hash1, 64); } +#ifdef ENABLE_WALLET +////////////////////////////////////////////////////////////////////////////// +// +// Internal miner +// +double dHashesPerSec = 0.0; +int64_t nHPSTimerStart = 0; + +// +// ScanHash scans nonces looking for a hash with at least some zero bits. +// It operates on big endian data. Caller does the byte reversing. +// All input buffers are 16-byte aligned. nNonce is usually preserved +// between calls, but periodically or if nNonce is 0xffff0000 or above, +// the block is rebuilt and nNonce starts over at zero. +// +unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) +{ + unsigned int& nNonce = *(unsigned int*)(pdata + 12); + for (;;) + { + // Crypto++ SHA256 + // Hash pdata using pmidstate as the starting state into + // pre-formatted buffer phash1, then hash phash1 into phash + nNonce++; + SHA256Transform(phash1, pdata, pmidstate); + SHA256Transform(phash, phash1, pSHA256InitState); + + // Return the nonce if the hash has at least some zero bits, + // caller will check if it has enough to reach the target + if (((unsigned short*)phash)[14] == 0) + return nNonce; + + // If nothing found after trying for a while, return -1 + if ((nNonce & 0xffff) == 0) + { + nHashesDone = 0xffff+1; + return (unsigned int) -1; + } + if ((nNonce & 0xfff) == 0) + boost::this_thread::interruption_point(); + } +} + +CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey) +{ + CPubKey pubkey; + if (!reservekey.GetReservedKey(pubkey)) + return NULL; + + CScript scriptPubKey = CScript() << pubkey << OP_CHECKSIG; + return CreateNewBlock(scriptPubKey); +} bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { @@ -665,5 +669,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); } - +#endif diff --git a/src/net.cpp b/src/net.cpp index a6a04cdd46..6ae749c657 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1678,7 +1678,7 @@ bool BindListenPort(const CService &addrBind, string& strError) return true; } -void static Discover() +void static Discover(boost::thread_group& threadGroup) { if (!fDiscover) return; @@ -1731,7 +1731,7 @@ void static Discover() // Don't use external IPv4 discovery, when -onlynet="IPv6" if (!IsLimited(NET_IPV4)) - boost::thread(boost::bind(&TraceThread<void (*)()>, "ext-ip", &ThreadGetMyExternalIP)); + threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "ext-ip", &ThreadGetMyExternalIP)); } void StartNode(boost::thread_group& threadGroup) @@ -1745,7 +1745,7 @@ void StartNode(boost::thread_group& threadGroup) if (pnodeLocalHost == NULL) pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); - Discover(); + Discover(threadGroup); // // Start threads diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index 08846604ea..434373da29 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -96,6 +96,7 @@ QT_MOC_CPP = moc_aboutdialog.cpp moc_addressbookpage.cpp \ moc_optionsmodel.cpp moc_overviewpage.cpp moc_paymentserver.cpp \ moc_receiverequestdialog.cpp moc_qvalidatedlineedit.cpp moc_qvaluecombobox.cpp \ moc_receivecoinsdialog.cpp \ + moc_recentrequeststablemodel.cpp \ moc_rpcconsole.cpp moc_sendcoinsdialog.cpp moc_sendcoinsentry.cpp \ moc_signverifymessagedialog.cpp moc_splashscreen.cpp moc_trafficgraphwidget.cpp moc_transactiondesc.cpp \ moc_transactiondescdialog.cpp moc_transactionfilterproxy.cpp \ @@ -122,6 +123,7 @@ BITCOIN_QT_H = aboutdialog.h addressbookpage.h addresstablemodel.h \ optionsdialog.h \ optionsmodel.h overviewpage.h paymentrequestplus.h paymentserver.h \ receivecoinsdialog.h \ + recentrequeststablemodel.h \ receiverequestdialog.h qvalidatedlineedit.h qvaluecombobox.h rpcconsole.h \ sendcoinsdialog.h sendcoinsentry.h signverifymessagedialog.h splashscreen.h \ trafficgraphwidget.h transactiondescdialog.h transactiondesc.h transactionfilterproxy.h \ @@ -157,6 +159,7 @@ BITCOIN_QT_CPP = aboutdialog.cpp addressbookpage.cpp \ optionsdialog.cpp optionsmodel.cpp overviewpage.cpp paymentrequestplus.cpp \ paymentserver.cpp qvalidatedlineedit.cpp qvaluecombobox.cpp \ receivecoinsdialog.cpp receiverequestdialog.cpp \ + recentrequeststablemodel.cpp \ rpcconsole.cpp sendcoinsdialog.cpp sendcoinsentry.cpp \ signverifymessagedialog.cpp splashscreen.cpp trafficgraphwidget.cpp transactiondesc.cpp \ transactiondescdialog.cpp transactionfilterproxy.cpp transactionrecord.cpp \ diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index d686cd4fd8..5e7d8e6178 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -297,7 +297,7 @@ QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, { if(orientation == Qt::Horizontal) { - if(role == Qt::DisplayRole) + if(role == Qt::DisplayRole && section < columns.size()) { return columns[section]; } diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 2f9e205c8d..2b3bf3bfb5 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -200,6 +200,13 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(bitcoin); QApplication app(argc, argv); +#if QT_VERSION > 0x050100 + // Generate high-dpi pixmaps + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif +#ifdef Q_OS_MAC + QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); +#endif // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType< bool* >(); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b3a566428d..b1daba5cba 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -69,28 +69,32 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : { GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this); -#ifndef Q_OS_MAC if (!fIsTestnet) { setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet")); +#ifndef Q_OS_MAC QApplication::setWindowIcon(QIcon(":icons/bitcoin")); setWindowIcon(QIcon(":icons/bitcoin")); +#else + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin")); +#endif } else { setWindowTitle(tr("Bitcoin") + " - " + tr("Wallet") + " " + tr("[testnet]")); +#ifndef Q_OS_MAC QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet")); setWindowIcon(QIcon(":icons/bitcoin_testnet")); - } #else - setUnifiedTitleAndToolBarOnMac(true); - QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); - - if (!fIsTestnet) - MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin")); - else MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); #endif + } + +#if defined(Q_OS_MAC) && QT_VERSION < 0x050000 + // This property is not implemented in Qt 5. Setting it has no effect. + // A replacement API (QtMacUnifiedToolBar) is available in QtMacExtras. + setUnifiedTitleAndToolBarOnMac(true); +#endif // Create wallet frame and make it the central widget walletFrame = new WalletFrame(this); diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 6d1a72ecd2..e7138f5371 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -7,35 +7,60 @@ <x>0</x> <y>0</y> <width>776</width> - <height>343</height> + <height>364</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> <layout class="QGridLayout" name="gridLayout"> - <item row="3" column="0"> - <widget class="QLabel" name="label"> + <item row="7" column="2"> + <widget class="QCheckBox" name="reuseAddress"> + <property name="toolTip"> + <string>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</string> + </property> <property name="text"> - <string>&Amount:</string> + <string>R&euse an existing receiving address (not recommended)</string> + </property> + </widget> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>&Message:</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> <property name="buddy"> - <cstring>reqAmount</cstring> + <cstring>reqMessage</cstring> </property> </widget> </item> - <item row="3" column="1"> - <widget class="BitcoinAmountField" name="reqAmount"> - <property name="minimumSize"> - <size> - <width>80</width> - <height>0</height> - </size> + <item row="4" column="2"> + <widget class="QLineEdit" name="reqLabel"> + <property name="toolTip"> + <string>The label to associate with the new receiving address</string> </property> + </widget> + </item> + <item row="6" column="2"> + <widget class="QLineEdit" name="reqMessage"> <property name="toolTip"> - <string>The amount to request</string> + <string>The message to attach to payment request</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Use this form to request payments. All fields are optional.</string> </property> </widget> </item> @@ -52,73 +77,35 @@ </property> </widget> </item> - <item row="4" column="1"> - <widget class="QLineEdit" name="reqLabel"> - <property name="toolTip"> - <string>The label to associate with the receiving address</string> - </property> - </widget> - </item> <item row="5" column="0"> - <widget class="QLabel" name="label_3"> + <widget class="QLabel" name="label"> <property name="text"> - <string>&Message:</string> + <string>&Amount:</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> <property name="buddy"> - <cstring>reqMessage</cstring> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QLineEdit" name="reqMessage"> - <property name="toolTip"> - <string>The message to attach to payment request</string> + <cstring>reqAmount</cstring> </property> </widget> </item> - <item row="6" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string/> + <item row="5" column="2"> + <widget class="BitcoinAmountField" name="reqAmount"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> </property> - </widget> - </item> - <item row="6" column="1"> - <widget class="QCheckBox" name="reuseAddress"> <property name="toolTip"> - <string>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</string> - </property> - <property name="text"> - <string>R&euse an existing receiving address (not recommended)</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Use this form to request payments. All fields are optional.</string> + <string>The amount to request</string> </property> </widget> </item> </layout> </item> <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QPushButton" name="clearButton"> @@ -178,6 +165,98 @@ </item> </layout> </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label_6"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Previously requested payments</string> + </property> + </widget> + </item> + <item> + <widget class="QTableView" name="recentRequestsView"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="showRequestButton"> + <property name="toolTip"> + <string>Show the selected request (does the same as double clicking an entry)</string> + </property> + <property name="text"> + <string>Show</string> + </property> + <property name="icon"> + <iconset resource="../bitcoin.qrc"> + <normaloff>:/icons/edit</normaloff>:/icons/edit</iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="removeRequestButton"> + <property name="toolTip"> + <string>Remove the selected entries from the list</string> + </property> + <property name="text"> + <string>Remove</string> + </property> + <property name="icon"> + <iconset resource="../bitcoin.qrc"> + <normaloff>:/icons/remove</normaloff>:/icons/remove</iconset> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> </layout> </widget> <customwidgets> @@ -187,6 +266,17 @@ <header>bitcoinamountfield.h</header> </customwidget> </customwidgets> + <tabstops> + <tabstop>reqLabel</tabstop> + <tabstop>reqAmount</tabstop> + <tabstop>reqMessage</tabstop> + <tabstop>reuseAddress</tabstop> + <tabstop>clearButton</tabstop> + <tabstop>receiveButton</tabstop> + <tabstop>recentRequestsView</tabstop> + <tabstop>showRequestButton</tabstop> + <tabstop>removeRequestButton</tabstop> + </tabstops> <resources> <include location="../bitcoin.qrc"/> </resources> diff --git a/src/qt/forms/receiverequestdialog.ui b/src/qt/forms/receiverequestdialog.ui index c9cb3de69f..85928c9be5 100644 --- a/src/qt/forms/receiverequestdialog.ui +++ b/src/qt/forms/receiverequestdialog.ui @@ -84,13 +84,6 @@ </widget> </item> <item> - <widget class="QPushButton" name="btnCopyImage"> - <property name="text"> - <string>&Copy Image</string> - </property> - </widget> - </item> - <item> <widget class="QPushButton" name="btnSaveAs"> <property name="text"> <string>&Save Image...</string> diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index cad41abd66..075a16dabf 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -12,6 +12,7 @@ #include "guiutil.h" #include "receiverequestdialog.h" #include "addresstablemodel.h" +#include "recentrequeststablemodel.h" #include <QMessageBox> #include <QTextDocument> @@ -27,6 +28,8 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) : #ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac ui->clearButton->setIcon(QIcon()); ui->receiveButton->setIcon(QIcon()); + ui->showRequestButton->setIcon(QIcon()); + ui->removeRequestButton->setIcon(QIcon()); #endif connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear())); } @@ -39,6 +42,19 @@ void ReceiveCoinsDialog::setModel(WalletModel *model) { connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); updateDisplayUnit(); + + ui->recentRequestsView->setModel(model->getRecentRequestsTableModel()); + ui->recentRequestsView->setAlternatingRowColors(true); + ui->recentRequestsView->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->recentRequestsView->setSelectionMode(QAbstractItemView::ContiguousSelection); + ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Date, 130); + ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Label, 120); +#if QT_VERSION < 0x050000 + ui->recentRequestsView->horizontalHeader()->setResizeMode(RecentRequestsTableModel::Message, QHeaderView::Stretch); +#else + ui->recentRequestsView->horizontalHeader()->setSectionResizeMode(RecentRequestsTableModel::Message, QHeaderView::Stretch); +#endif + ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Amount, 100); } } @@ -76,7 +92,7 @@ void ReceiveCoinsDialog::updateDisplayUnit() void ReceiveCoinsDialog::on_receiveButton_clicked() { - if(!model || !model->getOptionsModel() || !model->getAddressTableModel()) + if(!model || !model->getOptionsModel() || !model->getAddressTableModel() || !model->getRecentRequestsTableModel()) return; QString address; @@ -108,4 +124,41 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() dialog->setInfo(info); dialog->show(); clear(); + + /* Store request for later reference */ + model->getRecentRequestsTableModel()->addNewRequest(info); +} + +void ReceiveCoinsDialog::on_recentRequestsView_doubleClicked(const QModelIndex &index) +{ + const RecentRequestsTableModel *submodel = model->getRecentRequestsTableModel(); + ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this); + dialog->setModel(model->getOptionsModel()); + dialog->setInfo(submodel->entry(index.row()).recipient); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->show(); +} + +void ReceiveCoinsDialog::on_showRequestButton_clicked() +{ + if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel()) + return; + QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows(); + + foreach (QModelIndex index, selection) + { + on_recentRequestsView_doubleClicked(index); + } +} + +void ReceiveCoinsDialog::on_removeRequestButton_clicked() +{ + if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel()) + return; + QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows(); + if(selection.empty()) + return; + // correct for selection mode ContiguousSelection + QModelIndex firstIndex = selection.at(0); + model->getRecentRequestsTableModel()->removeRows(firstIndex.row(), selection.length(), firstIndex.parent()); } diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index 9980edd1f5..4435bf6694 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -13,6 +13,9 @@ namespace Ui { } class WalletModel; class OptionsModel; +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE /** Dialog for requesting payment of bitcoins */ class ReceiveCoinsDialog : public QDialog @@ -36,6 +39,9 @@ private: private slots: void on_receiveButton_clicked(); + void on_showRequestButton_clicked(); + void on_removeRequestButton_clicked(); + void on_recentRequestsView_doubleClicked(const QModelIndex &index); void updateDisplayUnit(); }; diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 7e92715df8..b5e45341d9 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -85,12 +85,10 @@ ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) : #ifndef USE_QRCODE ui->btnSaveAs->setVisible(false); - ui->btnCopyImage->setVisible(false); ui->lblQRCode->setVisible(false); #endif connect(ui->btnSaveAs, SIGNAL(clicked()), ui->lblQRCode, SLOT(saveImage())); - connect(ui->btnCopyImage, SIGNAL(clicked()), ui->lblQRCode, SLOT(copyImage())); } ReceiveRequestDialog::~ReceiveRequestDialog() diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp new file mode 100644 index 0000000000..06f64af146 --- /dev/null +++ b/src/qt/recentrequeststablemodel.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "recentrequeststablemodel.h" +#include "guiutil.h" +#include "bitcoinunits.h" +#include "optionsmodel.h" + +RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent): + walletModel(parent) +{ + /* These columns must match the indices in the ColumnIndex enumeration */ + columns << tr("Date") << tr("Label") << tr("Message") << tr("Amount"); +} + +RecentRequestsTableModel::~RecentRequestsTableModel() +{ + /* Intentionally left empty */ +} + +int RecentRequestsTableModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return list.length(); +} + +int RecentRequestsTableModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return columns.length(); +} + +QVariant RecentRequestsTableModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid() || index.row() >= list.length()) + return QVariant(); + + const RecentRequestEntry *rec = &list[index.row()]; + + if(role == Qt::DisplayRole || role == Qt::EditRole) + { + switch(index.column()) + { + case Date: + return GUIUtil::dateTimeStr(rec->date); + case Label: + if(rec->recipient.label.isEmpty() && role == Qt::DisplayRole) + { + return tr("(no label)"); + } + else + { + return rec->recipient.label; + } + case Message: + if(rec->recipient.message.isEmpty() && role == Qt::DisplayRole) + { + return tr("(no message)"); + } + else + { + return rec->recipient.message; + } + case Amount: + return BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), rec->recipient.amount); + } + } + return QVariant(); +} + +bool RecentRequestsTableModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + return true; +} + +QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(orientation == Qt::Horizontal) + { + if(role == Qt::DisplayRole && section < columns.size()) + { + return columns[section]; + } + } + return QVariant(); +} + +QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const +{ + return createIndex(row, column, 0); +} + +bool RecentRequestsTableModel::removeRows(int row, int count, const QModelIndex &parent) +{ + Q_UNUSED(parent); + if(count > 0 && row >= 0 && (row+count) <= list.size()) + { + beginRemoveRows(parent, row, row + count - 1); + list.erase(list.begin() + row, list.begin() + row + count); + endRemoveRows(); + return true; + } else { + return false; + } +} + +Qt::ItemFlags RecentRequestsTableModel::flags(const QModelIndex &index) const +{ + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient) +{ + RecentRequestEntry newEntry; + newEntry.date = QDateTime::currentDateTime(); + newEntry.recipient = recipient; + beginInsertRows(QModelIndex(), 0, 0); + list.prepend(newEntry); + endInsertRows(); +} diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h new file mode 100644 index 0000000000..d00a2a9055 --- /dev/null +++ b/src/qt/recentrequeststablemodel.h @@ -0,0 +1,61 @@ +// Copyright (c) 2011-2013 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef RECENTREQUESTSTABLEMODEL_H +#define RECENTREQUESTSTABLEMODEL_H + +#include <QAbstractTableModel> +#include <QStringList> +#include <QDateTime> + +#include "walletmodel.h" + +class CWallet; + +struct RecentRequestEntry +{ + QDateTime date; + SendCoinsRecipient recipient; +}; + +/** Model for list of recently generated payment requests / bitcoin URIs. + * Part of wallet model. + */ +class RecentRequestsTableModel: public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit RecentRequestsTableModel(CWallet *wallet, WalletModel *parent = 0); + ~RecentRequestsTableModel(); + + enum ColumnIndex { + Date = 0, + Label = 1, + Message = 2, + Amount = 3 + }; + + /** @name Methods overridden from QAbstractTableModel + @{*/ + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + Qt::ItemFlags flags(const QModelIndex &index) const; + /*@}*/ + + const RecentRequestEntry &entry(int row) const { return list[row]; } + void addNewRequest(const SendCoinsRecipient &recipient); + +private: + WalletModel *walletModel; + QStringList columns; + QList<RecentRequestEntry> list; +}; + +#endif diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 0a4e80811f..03cf7f51ea 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -306,12 +306,14 @@ void SendCoinsDialog::updateTabsAndLabels() void SendCoinsDialog::removeEntry(SendCoinsEntry* entry) { - entry->deleteLater(); + entry->hide(); - // If the last entry was removed add an empty one - if (!ui->entries->count()) + // If the last entry is about to be removed add an empty one + if (ui->entries->count() == 1) addEntry(); + entry->deleteLater(); + updateTabsAndLabels(); } @@ -543,7 +545,7 @@ void SendCoinsDialog::coinControlChangeChecked(int state) } // Coin Control: custom change address changed -void SendCoinsDialog::coinControlChangeEdited(const QString & text) +void SendCoinsDialog::coinControlChangeEdited(const QString& text) { if (model) { diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 2470af41a0..984a5a2e71 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -7,6 +7,7 @@ #include "addresstablemodel.h" #include "guiconstants.h" #include "transactiontablemodel.h" +#include "recentrequeststablemodel.h" #include "base58.h" #include "db.h" @@ -26,6 +27,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), transactionTableModel(0), + recentRequestsTableModel(0), cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0), cachedNumTransactions(0), cachedEncryptionStatus(Unencrypted), @@ -33,6 +35,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p { addressTableModel = new AddressTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this); + recentRequestsTableModel = new RecentRequestsTableModel(wallet, this); // This timer will be fired repeatedly to update the balance pollTimer = new QTimer(this); @@ -325,6 +328,11 @@ TransactionTableModel *WalletModel::getTransactionTableModel() return transactionTableModel; } +RecentRequestsTableModel *WalletModel::getRecentRequestsTableModel() +{ + return recentRequestsTableModel; +} + WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const { if(!wallet->IsCrypted()) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 32ddbbc6f6..44a1912ecc 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -18,6 +18,7 @@ class AddressTableModel; class OptionsModel; class TransactionTableModel; +class RecentRequestsTableModel; class WalletModelTransaction; class CCoinControl; @@ -88,6 +89,7 @@ public: OptionsModel *getOptionsModel(); AddressTableModel *getAddressTableModel(); TransactionTableModel *getTransactionTableModel(); + RecentRequestsTableModel *getRecentRequestsTableModel(); qint64 getBalance(const CCoinControl *coinControl = NULL) const; qint64 getUnconfirmedBalance() const; @@ -160,6 +162,7 @@ private: AddressTableModel *addressTableModel; TransactionTableModel *transactionTableModel; + RecentRequestsTableModel *recentRequestsTableModel; // Cache some values to be able to detect changes qint64 cachedBalance; diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index a3168917fc..c404ac274b 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -257,7 +257,7 @@ std::string HelpMessageCli(bool mainProgram) strUsage += " -datadir=<dir> " + _("Specify data directory") + "\n"; strUsage += " -testnet " + _("Use the test network") + "\n"; strUsage += " -regtest " + _("Enter regression test mode, which uses a special chain in which blocks can be " - "solved instantly. This is intended for regression testing tools and app development.") + "\n"; + "solved instantly. This is intended for regression testing tools and app development.") + "\n"; } else { strUsage += _("RPC client options:") + "\n"; } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 131a258c84..b81433120e 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -20,7 +20,8 @@ using namespace json_spirit; using namespace std; -// Key used by getwork/getblocktemplate miners. +#ifdef ENABLE_WALLET +// Key used by getwork miners. // Allocated in InitRPCMining, free'd in ShutdownRPCMining static CReserveKey* pMiningKey = NULL; @@ -40,6 +41,14 @@ void ShutdownRPCMining() delete pMiningKey; pMiningKey = NULL; } +#else +void InitRPCMining() +{ +} +void ShutdownRPCMining() +{ +} +#endif // Return average network hashes per second based on the last 'lookup' blocks, // or from the last difficulty change if 'lookup' is nonpositive. @@ -99,7 +108,7 @@ Value getnetworkhashps(const Array& params, bool fHelp) return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } - +#ifdef ENABLE_WALLET Value getgenerate(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -197,7 +206,6 @@ Value setgenerate(const Array& params, bool fHelp) return Value::null; } - Value gethashespersec(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -216,6 +224,7 @@ Value gethashespersec(const Array& params, bool fHelp) return (boost::int64_t)0; return (boost::int64_t)dHashesPerSec; } +#endif Value getmininginfo(const Array& params, bool fHelp) @@ -248,16 +257,19 @@ Value getmininginfo(const Array& 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("generate", getgenerate(params, false))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", TestNet())); +#ifdef ENABLE_WALLET + obj.push_back(Pair("generate", getgenerate(params, false))); + obj.push_back(Pair("hashespersec", gethashespersec(params, false))); +#endif return obj; } +#ifdef ENABLE_WALLET Value getwork(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -381,7 +393,7 @@ Value getwork(const Array& params, bool fHelp) return CheckWork(pblock, *pwalletMain, *pMiningKey); } } - +#endif Value getblocktemplate(const Array& params, bool fHelp) { diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 93811e80ed..fd72fe6386 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -1,8 +1,8 @@ // Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "rpcserver.h" +#include "rpcserver.h" #include "main.h" #include "net.h" @@ -11,10 +11,9 @@ #include "sync.h" #include "util.h" #ifdef ENABLE_WALLET -#include "wallet.h" // for getinfo #include "init.h" // for getinfo +#include "wallet.h" // for getinfo #endif -#include "main.h" // for getinfo #include <inttypes.h> diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2dc7b34f88..c95f450c82 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -248,12 +248,14 @@ static const CRPCCommand vRPCCommands[] = { "gettxout", &gettxout, true, false, false }, { "verifychain", &verifychain, true, false, false }, -#ifdef ENABLE_WALLET + /* Mining */ { "getnetworkhashps", &getnetworkhashps, true, false, false }, - { "getgenerate", &getgenerate, true, false, false }, - { "setgenerate", &setgenerate, true, true, false }, - { "gethashespersec", &gethashespersec, true, false, false }, { "getmininginfo", &getmininginfo, true, false, false }, + { "getblocktemplate", &getblocktemplate, true, false, false }, + { "submitblock", &submitblock, false, false, false }, + +#ifdef ENABLE_WALLET + /* Wallet */ { "getnewaddress", &getnewaddress, true, false, true }, { "getaccountaddress", &getaccountaddress, true, false, true }, { "getrawchangeaddress", &getrawchangeaddress, true, false, true }, @@ -283,10 +285,7 @@ static const CRPCCommand vRPCCommands[] = { "listaddressgroupings", &listaddressgroupings, false, false, true }, { "signmessage", &signmessage, false, false, true }, { "verifymessage", &verifymessage, false, false, false }, - { "getwork", &getwork, true, false, true }, { "listaccounts", &listaccounts, false, false, true }, - { "getblocktemplate", &getblocktemplate, true, false, false }, - { "submitblock", &submitblock, false, false, false }, { "listsinceblock", &listsinceblock, false, false, true }, { "dumpprivkey", &dumpprivkey, true, false, true }, { "dumpwallet", &dumpwallet, true, false, true }, @@ -295,6 +294,12 @@ static const CRPCCommand vRPCCommands[] = { "listunspent", &listunspent, false, false, true }, { "lockunspent", &lockunspent, false, false, true }, { "listlockunspent", &listlockunspent, false, false, true }, + + /* Wallet-enabled mining */ + { "getgenerate", &getgenerate, true, false, false }, + { "setgenerate", &setgenerate, true, true, false }, + { "gethashespersec", &gethashespersec, true, false, false }, + { "getwork", &getwork, true, false, true }, #endif // ENABLE_WALLET }; diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index bb87afec5b..82fa9d88c5 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -334,8 +334,7 @@ Value sendtoaddress(const Array& params, bool fHelp) if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty()) wtx.mapValue["to"] = params[3].get_str(); - if (pwalletMain->IsLocked()) - throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + EnsureWalletIsUnlocked(); string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); if (strError != "") @@ -1657,15 +1656,15 @@ Value keypoolrefill(const Array& params, bool fHelp) + HelpExampleRpc("keypoolrefill", "") ); - unsigned int kpSize = max(GetArg("-keypool", 100), (int64_t) 0); + // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool + unsigned int kpSize = 0; if (params.size() > 0) { if (params[0].get_int() < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size"); - kpSize = (unsigned int) params[0].get_int(); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size."); + kpSize = (unsigned int)params[0].get_int(); } EnsureWalletIsUnlocked(); - pwalletMain->TopUpKeyPool(kpSize); if (pwalletMain->GetKeyPoolSize() < kpSize) diff --git a/src/test/Makefile.am b/src/test/Makefile.am index dccd264e5a..ccc8da1690 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -31,14 +31,14 @@ test_bitcoin_SOURCES = alert_tests.cpp \ allocator_tests.cpp base32_tests.cpp base58_tests.cpp base64_tests.cpp \ bignum_tests.cpp bloom_tests.cpp canonical_tests.cpp checkblock_tests.cpp \ Checkpoints_tests.cpp compress_tests.cpp DoS_tests.cpp getarg_tests.cpp \ - key_tests.cpp mruset_tests.cpp multisig_tests.cpp \ + key_tests.cpp miner_tests.cpp mruset_tests.cpp multisig_tests.cpp \ netbase_tests.cpp pmt_tests.cpp rpc_tests.cpp script_P2SH_tests.cpp \ script_tests.cpp serialize_tests.cpp sigopcount_tests.cpp test_bitcoin.cpp \ transaction_tests.cpp uint160_tests.cpp uint256_tests.cpp util_tests.cpp \ sighash_tests.cpp $(JSON_TEST_FILES) $(RAW_TEST_FILES) if ENABLE_WALLET -test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp miner_tests.cpp rpc_wallet_tests.cpp +test_bitcoin_SOURCES += accounting_tests.cpp wallet_tests.cpp rpc_wallet_tests.cpp endif nodist_test_bitcoin_SOURCES = $(BUILT_SOURCES) diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json index a26f4a87db..e386f81fe6 100644 --- a/src/test/data/tx_invalid.json +++ b/src/test/data/tx_invalid.json @@ -65,5 +65,10 @@ ["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], [[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true] + "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", true], + +["Incorrect signature order"], +["Note the input is just required to make the tester happy"], +[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], +"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true] ] diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json index 63e7074a32..c33a7a035a 100644 --- a/src/test/data/tx_valid.json +++ b/src/test/data/tx_valid.json @@ -87,5 +87,10 @@ ["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"], [[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]], - "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", true] + "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", true], + +["Correct signature order"], +["Note the input is just required to make the tester happy"], +[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], +"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", true] ] diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 46c9ae021d..ea6abb7e9a 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -8,7 +8,6 @@ #include <boost/test/unit_test.hpp> -extern CWallet* pwalletMain; extern void SHA256Transform(void* pstate, void* pinput, const void* pinit); BOOST_AUTO_TEST_SUITE(miner_tests) @@ -51,7 +50,7 @@ struct { // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { - CReserveKey reservekey(pwalletMain); + CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; CBlockTemplate *pblocktemplate; CTransaction tx; CScript script; @@ -60,7 +59,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) LOCK(cs_main); // Simple block creation, nothing special yet: - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs // Therefore, load 100 blocks :) @@ -86,7 +85,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) delete pblocktemplate; // Just to make sure we can still make simple blocks - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; // block sigops > limit: 1000 CHECKMULTISIG + 1 @@ -104,7 +103,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -124,14 +123,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); tx.vin[0].prevout.hash = hash; } - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); // orphan in mempool hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -149,7 +148,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 5900000000LL; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -160,7 +159,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue = 0; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -178,7 +177,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].nValue -= 1000000; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); @@ -192,17 +191,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetHash(); mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11)); - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; mempool.clear(); // subsidy changing int nHeight = chainActive.Height(); chainActive.Tip()->nHeight = 209999; - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = 210000; - BOOST_CHECK(pblocktemplate = CreateNewBlockWithKey(reservekey)); + BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey)); delete pblocktemplate; chainActive.Tip()->nHeight = nHeight; |