diff options
49 files changed, 1650 insertions, 890 deletions
@@ -1,9 +1,9 @@ Building Bitcoin -See doc/readme-qt.rst for instructions on building Bitcoin-Qt, +See doc/readme-qt.md for instructions on building Bitcoin-Qt, the intended-for-end-users, nice-graphical-interface, reference implementation of Bitcoin. -See doc/build-*.txt for instructions on building bitcoind, +See doc/build-*.md for instructions on building bitcoind, the intended-for-services, no-graphical-interface, reference implementation of Bitcoin.
\ No newline at end of file diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 1d62941e68..c36e384673 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -339,7 +339,6 @@ QMAKE_EXTRA_COMPILERS += TSQM # "Other files" to show in Qt Creator OTHER_FILES += README.md \ - doc/*.rst \ doc/*.txt \ doc/*.md \ src/bitcoind.cpp \ diff --git a/contrib/debian/README b/contrib/debian/README new file mode 100644 index 0000000000..1cb9b75fbd --- /dev/null +++ b/contrib/debian/README @@ -0,0 +1,20 @@ +This directory contains files used to package bitcoind/bitcoin-qt +for Debian-based Linux systems. + +If you compile bitcoind/bitcoin-qt yourself, there are some +useful files here: + +bitcoin: URI support +-------------------- + +bitcoin-qt.desktop (Gnome / Open Desktop) +To install: + sudo desktop-file-install bitcoin-qt.desktop + sudo update-desktop-database + +If you build yourself, you will either need to modify the paths in +the .desktop file or copy or symlink your bitcoin-qt binary to /usr/bin +and the ../../share/pixmaps/bitcoin128.png to /usr/share/pixmaps + +bitcoin-qt.protocol (KDE) + diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop index 5d6f781e4e..b2a2cef622 100644 --- a/contrib/debian/bitcoin-qt.desktop +++ b/contrib/debian/bitcoin-qt.desktop @@ -4,7 +4,7 @@ Name=Bitcoin Comment=Bitcoin P2P Cryptocurrency Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi -Exec=/usr/bin/bitcoin-qt +Exec=/usr/bin/bitcoin-qt %u Terminal=false Type=Application Icon=/usr/share/pixmaps/bitcoin128.png diff --git a/contrib/gitian-downloader/linux-download-config b/contrib/gitian-downloader/linux-download-config index aef614d0ca..8340a5dd24 100644 --- a/contrib/gitian-downloader/linux-download-config +++ b/contrib/gitian-downloader/linux-download-config @@ -35,4 +35,8 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami minimum_weight: 120 diff --git a/contrib/gitian-downloader/win32-download-config b/contrib/gitian-downloader/win32-download-config index 0f7032e643..49d52851b6 100644 --- a/contrib/gitian-downloader/win32-download-config +++ b/contrib/gitian-downloader/win32-download-config @@ -35,4 +35,8 @@ signers: weight: 40 name: "Wladimir J. van der Laan" key: laanwj + AEC1884398647C47413C1C3FB1179EB7347DC10D: + weight: 40 + name: "Warren Togami" + key: wtogami minimum_weight: 120 diff --git a/contrib/gitian-downloader/wtogami-key.pgp b/contrib/gitian-downloader/wtogami-key.pgp new file mode 100644 index 0000000000..e0f6c4c5fd --- /dev/null +++ b/contrib/gitian-downloader/wtogami-key.pgp @@ -0,0 +1,131 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.13 (GNU/Linux) + +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 +=icdI +-----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/README.md b/doc/README.md index cdd31057ad..1238033fb7 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,10 +1,9 @@ -Bitcoin 0.8.2 BETA +Bitcoin 0.8.2 BETA ==================== Copyright (c) 2009-2013 Bitcoin Developers -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. +Distributed under the [MIT/X11 software license](http://www.opensource.org/licenses/mit-license.php). This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. @@ -19,8 +18,13 @@ with each other, with the help of a P2P network to check for double-spending. Setup --------------------- +[Bitcoin-Qt](http://bitcoin.org/en/download) is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions; depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. + +### Unix + You need the Qt4 run-time libraries to run Bitcoin-Qt. On Debian or Ubuntu: - `sudo apt-get install libqtgui4` + + sudo apt-get install libqtgui4 Unpack the files into a directory and run: @@ -29,18 +33,38 @@ Unpack the files into a directory and run: - bin/64/bitcoin-qt (GUI, 64-bit) - bin/64/bitcoind (headless, 64-bit) -See the documentation at the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page) -for help and more information. -Other Pages +### Windows + +Unpack the files into a directory and run bitcoin-qt.exe. + +### Need Help? + +* See the documentation at the [Bitcoin Wiki](https://en.bitcoin.it/wiki/Main_Page) +for help and more information. +* Ask for help on [#bitcoin](http://webchat.freenode.net?channels=bitcoin) on Freenode. If you don't have an IRC client use [webchat here](http://webchat.freenode.net?channels=bitcoin). +* Ask for help on the [BitcoinTalk](https://bitcointalk.org/) forums. + +Building --------------------- -- [Unix Build Notes](build-unix.md) +- [Bitcoin-Qt Readme](readme-qt.md) - [OSX Build Notes](build-osx.md) +- [Unix Build Notes](build-unix.md) - [Windows Build Notes](build-msw.md) + +Development +--------------------- - [Coding Guidelines](coding.md) -- [Release Process](release-process.md) -- [Release Notes](release-notes.md) - [Multiwallet Qt Development](multiwallet-qt.md) +- [Release Notes](release-notes.md) +- [Release Process](release-process.md) +- [Source Code Documentation (External Link)](https://dev.visucore.com/bitcoin/doxygen/) +- [Translation Process](translation_process.md) - [Unit Tests](unit-tests.md) -- [Translation Process](translation_process.md)
\ No newline at end of file + +Other Pages +--------------------- +- [Assets Attribution](assets-attribution.md) +- [Files](files.md) +- [Tor Support](tor.md)
\ No newline at end of file diff --git a/doc/assets-attribution.md b/doc/assets-attribution.md new file mode 100644 index 0000000000..e85e74522d --- /dev/null +++ b/doc/assets-attribution.md @@ -0,0 +1,104 @@ +The following is a list of assets used in the bitcoin source and their proper attribution. + +[Wladimir van der Laan](https://github.com/laanwj) +----------------------- +#### Info +* License: MIT +### Assets Used + + src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png, + src/qt/res/src/clock_green.svg, src/qt/res/src/clock1.svg, + src/qt/res/src/clock2.svg, src/qt/res/src/clock3.svg, + src/qt/res/src/clock4.svg, src/qt/res/src/clock5.svg, + src/qt/res/src/inout.svg, src/qt/res/src/questionmark.svg + +[David Vignoni](www.icon-king.com) +----------------------- + +### Info +* Icon Pack: NUVOLA ICON THEME for KDE 3.x +* Designer: David Vignoni (david@icon-king.com) +* License: LGPL +* Site: [http://www.icon-king.com/projects/nuvola/](http://www.icon-king.com/projects/nuvola/) + +### Assets Used + src/qt/res/icons/address-book.png, src/qt/res/icons/export.png, + src/qt/res/icons/history.png, src/qt/res/icons/key.png, + src/qt/res/icons/lock_*.png, src/qt/res/icons/overview.png, + src/qt/res/icons/receive.png, src/qt/res/icons/send.png, + src/qt/res/icons/synced.png, src/qt/res/icons/filesave.png + +schollidesign +----------------------- + +### Info +* Icon Pack: Human-O2 +* Designer: schollidesign +* License: GNU/GPL +* Site: [http://findicons.com/icon/93743/blocks_gnome_netstatus_0](http://findicons.com/icon/93743/blocks_gnome_netstatus_0) + +### Assets Used + src/qt/res/icons/connect*.png + +md2k7 +----------------------- + +### Info +* Designer: md2k7 +* Site: https://bitcointalk.org/index.php?topic=15276.0 +* License: You are free to do with these icons as you wish, including selling, + copying, modifying etc. +* License: MIT + +### Assets Used + src/qt/res/icons/transaction*.png + +[Everaldo.com](http://www.everaldo.com) +----------------------- + +### Info +* Designer: [http://www.everaldo.com](http://www.everaldo.com) +* Icon Pack: Crystal SVG +* License: LGPL + +### Assets Used + src/qt/res/icons/configure.png, src/qt/res/icons/quit.png, + src/qt/res/icons/editcopy.png, src/qt/res/icons/editpaste.png, + src/qt/res/icons/add.png, src/qt/res/icons/edit.png, + src/qt/res/icons/remove.png (edited) + +Everaldo (Everaldo Coelho) +----------------------- + +### Info +* Icon Pack: Kids +* Designer: Everaldo (Everaldo Coelho) +* License: GNU/GPL +* Site: [http://findicons.com/icon/17102/reload?id=17102](http://findicons.com/icon/17102/reload?id=17102) +### Assets Used + scripts/img/reload.xcf (modified), src/qt/res/movies/update_spinner.mng + +[Vignoni David](http://www.oxygen-icons.org/) +----------------------- + +### Info +* Designer: Vignoni David +* Site: http://www.oxygen-icons.org/ +* License: Oxygen icon theme is dual licensed. You may copy it under the Creative Common Attribution-ShareAlike 3.0 License or the GNU Library General Public License. + +### Assets Used + src/qt/res/icons/debugwindow.png + +Jonas Schnelli +----------------------- + +### Info +* Designer: Jonas Schnelli (based on the original bitcoin logo from Bitboy) +* License: MIT + +### Assets Used + src/qt/res/icons/bitcoin.icns, src/qt/res/src/bitcoin.svg, + src/qt/res/src/bitcoin.ico, src/qt/res/src/bitcoin.png, + src/qt/res/src/bitcoin_testnet.png, docs/bitcoin_logo_doxygen.png, + src/qt/res/icons/toolbar.png, src/qt/res/icons/toolbar_testnet.png, + src/qt/res/images/splash.png, src/qt/res/images/splash_testnet.png
\ No newline at end of file diff --git a/doc/build-msw.md b/doc/build-msw.md index b7abe28877..d348ad7cc3 100644 --- a/doc/build-msw.md +++ b/doc/build-msw.md @@ -1,17 +1,9 @@ -Copyright (c) 2009-2013 Bitcoin Developers - -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes -cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. - - -See readme-qt.rst for instructions on building Bitcoin-Qt, the -graphical user interface. - WINDOWS BUILD NOTES =================== +See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the +graphical user interface. + Compilers Supported ------------------- TODO: What works? @@ -22,11 +14,12 @@ Dependencies ------------ Libraries you need to download separately and build: - default path download -OpenSSL \openssl-1.0.1c-mgw http://www.openssl.org/source/ -Berkeley DB \db-4.8.30.NC-mgw http://www.oracle.com/technology/software/products/berkeley-db/index.html -Boost \boost-1.50.0-mgw http://www.boost.org/users/download/ -miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/ + name default path download + -------------------------------------------------------------------------------------------------------------------- + OpenSSL \openssl-1.0.1c-mgw http://www.openssl.org/source/ + Berkeley DB \db-4.8.30.NC-mgw http://www.oracle.com/technology/software/products/berkeley-db/index.html + Boost \boost-1.50.0-mgw http://www.boost.org/users/download/ + miniupnpc \miniupnpc-1.6-mgw http://miniupnp.tuxfamily.org/files/ Their licenses: diff --git a/doc/build-osx.md b/doc/build-osx.md index 1fc33b15a3..271f8f55bd 100644 --- a/doc/build-osx.md +++ b/doc/build-osx.md @@ -1,38 +1,15 @@ -Mac OS X bitcoind build instructions +Mac OS X Build Instructions and Notes ==================================== - -Authors -------- - -* Laszlo Hanyecz <solar@heliacal.net> -* Douglas Huff <dhuff@jrbobdobbs.org> -* Colin Dean <cad@cad.cx> -* Gavin Andresen <gavinandresen@gmail.com> - -License -------- - -Copyright (c) 2009-2012 Bitcoin Developers - -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. - -This product includes software developed by the OpenSSL Project for use in -the OpenSSL Toolkit (http://www.openssl.org/). - -This product includes cryptographic software written by -Eric Young (eay@cryptsoft.com) and UPnP software written by Thomas Bernard. +This guide will show you how to build bitcoind(headless client) for OSX. Notes ----- -See `doc/readme-qt.rst` for instructions on building Bitcoin-Qt, the +* See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the graphical user interface. - -Tested on OS X 10.5 through 10.8 on Intel processors only. PPC is not +* Tested on OS X 10.5 through 10.8 on Intel processors only. PPC is not supported because it is big-endian. - -All of the commands should be executed in a Terminal application. The +* All of the commands should be executed in a Terminal application. The built-in one is located in `/Applications/Utilities`. Preparation diff --git a/doc/build-unix.md b/doc/build-unix.md index 6181bb255d..4653bba495 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -1,12 +1,6 @@ -Copyright (c) 2009-2013 Bitcoin Developers - -Distributed under the MIT/X11 software license, see the accompanying -file COPYING or http://www.opensource.org/licenses/mit-license.php. -This product includes software developed by the OpenSSL Project for use in the [OpenSSL Toolkit](http://www.openssl.org/). This product includes -cryptographic software written by Eric Young ([eay@cryptsoft.com](mailto:eay@cryptsoft.com)), and UPnP software written by Thomas Bernard. - UNIX BUILD NOTES ==================== +Some notes on how to build Bitcoin in Unix. To Build --------------------- @@ -14,7 +8,7 @@ To Build cd src/ make -f makefile.unix # Headless bitcoin -See readme-qt.rst for instructions on building Bitcoin-Qt, the graphical user interface. +See [readme-qt.md](readme-qt.md) for instructions on building Bitcoin-Qt, the graphical user interface. Dependencies --------------------- diff --git a/doc/files.md b/doc/files.md new file mode 100644 index 0000000000..80195535bb --- /dev/null +++ b/doc/files.md @@ -0,0 +1,23 @@ +Used in 0.8.0 +--------------------- +* wallet.dat: personal wallet (BDB) with keys and transactions +* peers.dat: peer IP address database (custom format); since 0.7.0 +* blocks/blk000??.dat: block data (custom, 128 MiB per file); since 0.8.0 +* blocks/rev000??.dat; block undo data (custom); since 0.8.0 (format changed since pre-0.8) +* blocks/index/*; block index (LevelDB); since 0.8.0 +* chainstate/*; block chain state database (LevelDB); since 0.8.0 +* database/*: BDB database environment; only used for wallet since 0.8.0 + +Only used in pre-0.8.0 +--------------------- +* blktree/*; block chain index (LevelDB); since pre-0.8, replaced by blocks/index/* in 0.8.0 +* coins/*; unspent transaction output database (LevelDB); since pre-0.8, replaced by chainstate/* in 0.8.0 + +Only used before 0.8.0 +--------------------- +* blkindex.dat: block chain index database (BDB); replaced by {chainstate/*,blocks/index/*,blocks/rev000??.dat} in 0.8.0 +* blk000?.dat: block data (custom, 2 GiB per file); replaced by blocks/blk000??.dat in 0.8.0 + +Only used before 0.7.0 +--------------------- +* addr.dat: peer IP address database (BDB); replaced by peers.dat in 0.7.0 diff --git a/doc/readme-qt.md b/doc/readme-qt.md new file mode 100644 index 0000000000..083db32794 --- /dev/null +++ b/doc/readme-qt.md @@ -0,0 +1,128 @@ +Bitcoin-Qt Readme +=============================== +Contains build and configuration instructions for Bitcoin-Qt (Qt4 GUI for Bitcoin). + +Build Instructions +--------------------- + +### Debian + + +First, make sure that the required packages for Qt4 development of your +distribution are installed, these are + + + +for Debian and Ubuntu <= 11.10 : + + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb4.8++-dev + +for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): + + apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ + libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ + libssl-dev libdb++-dev libminiupnpc-dev + +For Qt 5 you need the following, otherwise you get an error with lrelease when running qmake: + + + apt-get install qt5-qmake libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev-tools + +then execute the following: + + qmake + make + +Alternatively, install [Qt Creator](http://qt-project.org/downloads/) and open the `bitcoin-qt.pro` file. +An executable named `bitcoin-qt` will be built. + + + +### Mac OS X + +* Download and install the [Qt Mac OS X SDK](https://qt-project.org/downloads). It is recommended to also install Apple's Xcode with UNIX tools. +* Download and install either [MacPorts](https://www.macports.org/) or [HomeBrew](http://mxcl.github.io/homebrew/). +* Execute the following commands in a terminal to get the dependencies using MacPorts + + sudo port selfupdate + sudo port install boost db48 miniupnpc + +* Execute the following commands in a terminal to get the dependencies using HomeBrew: + + brew update + brew install boost miniupnpc openssl berkeley-db4 + +- If using HomeBrew, edit `bitcoin-qt.pro` to account for library location differences. There's a diff in `contrib/homebrew/bitcoin-qt-pro.patch` that shows what you need to change, or you can just patch by doing + + patch -p1 < contrib/homebrew/bitcoin.qt.pro.patch + +- Open the bitcoin-qt.pro file in Qt Creator and build as normal (cmd+B) + + +Build Configuration Options +--------------------- + +### UPnP port forwarding + +To use UPnP for port forwarding behind a NAT router (recommended, as more connections overall allow for a faster and more stable bitcoin experience), pass the following argument to qmake: + + + + qmake "USE_UPNP=1" + +(in **Qt Creator**, you can find the setting for additional qmake arguments under "Projects" -> "Build Settings" -> "Build Steps", then click "Details" next to **qmake**) + +This requires miniupnpc for UPnP port mapping. It can be downloaded from [here]( +http://miniupnp.tuxfamily.org/files/). UPnP support is not compiled in by default. + +Set USE_UPNP to a different value to control this: + + + USE_UPNP=- no UPnP support, miniupnpc not required; + USE_UPNP=0 (the default) built with UPnP, support turned off by default at runtime; + USE_UPNP=1 build with UPnP support turned on by default at runtime. + +### Notification support for recent (k)ubuntu versions + +To see desktop notifications on (k)ubuntu versions starting from 10.04, enable usage of the +FreeDesktop notification interface through DBUS using the following qmake option: + + + + qmake "USE_DBUS=1" + +### Generation of QR codes + +[libqrencode](http://fukuchi.org/works/qrencode/) may be used to generate QRCode images for payment requests. Pass the USE_QRCODE flag to qmake to control this: + + + USE_QRCODE=0 (the default) No QRCode support - libarcode not required + USE_QRCODE=1 QRCode support enabled + +Warnings +--------------------- + +### Berkely DB Version Warning + + +A warning for people using the *static binary* version of Bitcoin on a Linux/UNIX-ish system (tl;dr: **Berkely DB databases are not forward compatible**). + +The static binary version of Bitcoin is linked against libdb4.8 (see also [this Debian issue](http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621425)). + +Now the nasty thing is that databases from 5.X are not compatible with 4.X. + +If the globally installed development package of Berkely DB installed on your system is 5.X, any source you build yourself will be linked against that. The first time you run with a 5.X version the database will be upgraded, and 4.X cannot open the new format. This means that you cannot go back to the old statically linked version without significant hassle! + +### Ubuntu 11.10 Warning + + +Ubuntu 11.10 has a package called 'qt-at-spi' installed by default. At the time of writing, having that package installed causes bitcoin-qt to crash intermittently. The issue has been reported as [launchpad bug 857790](https://bugs.launchpad.net/ubuntu/+source/qt-at-spi/+bug/857790), but +isn't yet fixed. + +Until the bug is fixed, you can remove the qt-at-spi package to work around the problem, though this will presumably disable screen reader functionality for Qt apps: + + sudo apt-get remove qt-at-spi + diff --git a/doc/readme-qt.rst b/doc/readme-qt.rst deleted file mode 100644 index 95cb33650f..0000000000 --- a/doc/readme-qt.rst +++ /dev/null @@ -1,163 +0,0 @@ -Bitcoin-Qt: Qt4 GUI for Bitcoin -=============================== - -Build instructions -=================== - -Debian -------- - -First, make sure that the required packages for Qt4 development of your -distribution are installed, these are - -:: - -for Debian and Ubuntu <= 11.10 : - -:: - - apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ - libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ - libssl-dev libdb4.8++-dev - -for Ubuntu >= 12.04 (please read the 'Berkely DB version warning' below): - -:: - - apt-get install qt4-qmake libqt4-dev build-essential libboost-dev libboost-system-dev \ - libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev \ - libssl-dev libdb++-dev libminiupnpc-dev - -For Qt 5 you need the following, otherwise you get an error with lrelease when running qmake: - -:: - - apt-get install qt5-qmake libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev-tools - -then execute the following: - -:: - - qmake - make - -Alternatively, install `Qt Creator`_ and open the `bitcoin-qt.pro` file. - -An executable named `bitcoin-qt` will be built. - -.. _`Qt Creator`: http://qt-project.org/downloads/ - -Mac OS X --------- - -- Download and install the `Qt Mac OS X SDK`_. It is recommended to also install Apple's Xcode with UNIX tools. - -- Download and install either `MacPorts`_ or `HomeBrew`_. - -- Execute the following commands in a terminal to get the dependencies using MacPorts: - -:: - - sudo port selfupdate - sudo port install boost db48 miniupnpc - -- Execute the following commands in a terminal to get the dependencies using HomeBrew: - -:: - - brew update - brew install boost miniupnpc openssl berkeley-db4 - -- If using HomeBrew, edit `bitcoin-qt.pro` to account for library location differences. There's a diff in `contrib/homebrew/bitcoin-qt-pro.patch` that shows what you need to change, or you can just patch by doing - - patch -p1 < contrib/homebrew/bitcoin.qt.pro.patch - -- Open the bitcoin-qt.pro file in Qt Creator and build as normal (cmd-B) - -.. _`Qt Mac OS X SDK`: http://qt-project.org/downloads/ -.. _`MacPorts`: http://www.macports.org/install.php -.. _`HomeBrew`: http://mxcl.github.io/homebrew/ - - -Build configuration options -============================ - -UPnP port forwarding ---------------------- - -To use UPnP for port forwarding behind a NAT router (recommended, as more connections overall allow for a faster and more stable bitcoin experience), pass the following argument to qmake: - -:: - - qmake "USE_UPNP=1" - -(in **Qt Creator**, you can find the setting for additional qmake arguments under "Projects" -> "Build Settings" -> "Build Steps", then click "Details" next to **qmake**) - -This requires miniupnpc for UPnP port mapping. It can be downloaded from -http://miniupnp.tuxfamily.org/files/. UPnP support is not compiled in by default. - -Set USE_UPNP to a different value to control this: - -+------------+--------------------------------------------------------------------------+ -| USE_UPNP=- | no UPnP support, miniupnpc not required; | -+------------+--------------------------------------------------------------------------+ -| USE_UPNP=0 | (the default) built with UPnP, support turned off by default at runtime; | -+------------+--------------------------------------------------------------------------+ -| USE_UPNP=1 | build with UPnP support turned on by default at runtime. | -+------------+--------------------------------------------------------------------------+ - -Notification support for recent (k)ubuntu versions ---------------------------------------------------- - -To see desktop notifications on (k)ubuntu versions starting from 10.04, enable usage of the -FreeDesktop notification interface through DBUS using the following qmake option: - -:: - - qmake "USE_DBUS=1" - -Generation of QR codes ------------------------ - -libqrencode may be used to generate QRCode images for payment requests. -It can be downloaded from http://fukuchi.org/works/qrencode/index.html.en, or installed via your package manager. Pass the USE_QRCODE -flag to qmake to control this: - -+--------------+--------------------------------------------------------------------------+ -| USE_QRCODE=0 | (the default) No QRCode support - libarcode not required | -+--------------+--------------------------------------------------------------------------+ -| USE_QRCODE=1 | QRCode support enabled | -+--------------+--------------------------------------------------------------------------+ - - -Berkely DB version warning -========================== - -A warning for people using the *static binary* version of Bitcoin on a Linux/UNIX-ish system (tl;dr: **Berkely DB databases are not forward compatible**). - -The static binary version of Bitcoin is linked against libdb4.8 (see also `this Debian issue`_). - -Now the nasty thing is that databases from 5.X are not compatible with 4.X. - -If the globally installed development package of Berkely DB installed on your system is 5.X, any source you -build yourself will be linked against that. The first time you run with a 5.X version the database will be upgraded, -and 4.X cannot open the new format. This means that you cannot go back to the old statically linked version without -significant hassle! - -.. _`this Debian issue`: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=621425 - -Ubuntu 11.10 warning -==================== - -Ubuntu 11.10 has a package called 'qt-at-spi' installed by default. At the time of writing, having that package -installed causes bitcoin-qt to crash intermittently. The issue has been reported as `launchpad bug 857790`_, but -isn't yet fixed. - -Until the bug is fixed, you can remove the qt-at-spi package to work around the problem, though this will presumably -disable screen reader functionality for Qt apps: - -:: - - sudo apt-get remove qt-at-spi - -.. _`launchpad bug 857790`: https://bugs.launchpad.net/ubuntu/+source/qt-at-spi/+bug/857790 diff --git a/doc/release-process.md b/doc/release-process.md index dc2101e1c1..7b0a73a81e 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -31,7 +31,7 @@ Release Process export SIGNER=(your gitian key, ie bluematt, sipa, etc) export VERSION=(new version, e.g. 0.8.0) - cd ./gitian-builder + pushd ./gitian-builder Fetch and build inputs: (first time, or when dependency versions change) @@ -58,13 +58,14 @@ Release Process ./bin/gsign --signer $SIGNER --release ${VERSION} --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian.yml pushd build/out zip -r bitcoin-${VERSION}-linux-gitian.zip * - mv bitcoin-${VERSION}-linux-gitian.zip ../../ + mv bitcoin-${VERSION}-linux-gitian.zip ../../../ popd ./bin/gbuild --commit bitcoin=v${VERSION} ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml ./bin/gsign --signer $SIGNER --release ${VERSION}-win32 --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win32.yml pushd build/out zip -r bitcoin-${VERSION}-win32-gitian.zip * - mv bitcoin-${VERSION}-win32-gitian.zip ../../ + mv bitcoin-${VERSION}-win32-gitian.zip ../../../ + popd popd Build output expected: diff --git a/doc/tor.md b/doc/tor.md new file mode 100644 index 0000000000..86d56cffd5 --- /dev/null +++ b/doc/tor.md @@ -0,0 +1,89 @@ +TOR SUPPORT IN BITCOIN +====================== + +It is possible to run Bitcoin as a Tor hidden service, and connect to such services. + +The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on a random port. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly +configure Tor. + + +1. Run bitcoin behind a Tor proxy +--------------------------------- + +The first step is running Bitcoin behind a Tor proxy. This will already make all +outgoing connections be anonimized, but more is possible. + + -socks=5 SOCKS5 supports connecting-to-hostname, which can be used instead + of doing a (leaking) local DNS lookup. SOCKS5 is the default, + but SOCKS4 does not support this. (SOCKS4a does, but isn't + implemented). + + -proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy + server will be used to try to reach .onion addresses as well. + + -tor=ip:port Set the proxy server to use for tor hidden services. You do not + need to set this if it's the same as -proxy. You can use -notor + to explicitly disable access to hidden service. + + -listen When using -proxy, listening is disabled by default. If you want + to run a hidden service (see next section), you'll need to enable + it explicitly. + + -connect=X When behind a Tor proxy, you can specify .onion addresses instead + -addnode=X of IP addresses or hostnames in these parameters. It requires + -seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with + other P2P nodes. + +In a typical situation, this suffices to run behind a Tor proxy: + + ./bitcoin -proxy=127.0.0.1:9050 + + +2. Run a bitcoin hidden server +------------------------------ + +If you configure your Tor system accordingly, it is possible to make your node also +reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent +config file): + + HiddenServiceDir /var/lib/tor/bitcoin-service/ + HiddenServicePort 8333 127.0.0.1:8333 + +The directory can be different of course, but (both) port numbers should be equal to +your bitcoind's P2P listen port (8333 by default). + + -externalip=X You can tell bitcoin about its publicly reachable address using + this option, and this can be a .onion address. Given the above + configuration, you can find your onion address in + /var/lib/tor/bitcoin-service/hostname. Onion addresses are given + preference for your node to advertize itself with, for connections + coming from unroutable addresses (such as 127.0.0.1, where the + Tor proxy typically runs). + + -listen You'll need to enable listening for incoming connections, as this + is off by default behind a proxy. + + -discover When -externalip is specified, no attempt is made to discover local + IPv4 or IPv6 addresses. If you want to run a dual stack, reachable + from both Tor and IPv4 (or IPv6), you'll need to either pass your + other addresses using -externalip, or explicitly enable -discover. + Note that both addresses of a dual-stack system may be easily + linkable using traffic analysis. + +In a typical situation, where you're only reachable via Tor, this should suffice: + + ./bitcoind -proxy=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -listen + +(obviously, replace the Onion address with your own). If you don't care too much +about hiding your node, and want to be reachable on IPv4 as well, additionally +specify: + + ./bitcoind ... -discover + +and open port 8333 on your firewall (or use -upnp). + +If you only want to use Tor to reach onion addresses, but not use it as a proxy +for normal IPv4/IPv6 communication, use: + + ./bitcoin -tor=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover + diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index febb475db3..11fac42213 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -195,6 +195,7 @@ static const CRPCCommand vRPCCommands[] = { "help", &help, true, true }, { "stop", &stop, true, true }, { "getblockcount", &getblockcount, true, false }, + { "getbestblockhash", &getbestblockhash, true, false }, { "getconnectioncount", &getconnectioncount, true, false }, { "getpeerinfo", &getpeerinfo, true, false }, { "addnode", &addnode, true, true }, @@ -243,7 +244,9 @@ static const CRPCCommand vRPCCommands[] = { "submitblock", &submitblock, false, false }, { "listsinceblock", &listsinceblock, false, false }, { "dumpprivkey", &dumpprivkey, true, false }, + { "dumpwallet", &dumpwallet, true, false }, { "importprivkey", &importprivkey, false, false }, + { "importwallet", &importwallet, false, false }, { "listunspent", &listunspent, false, false }, { "getrawtransaction", &getrawtransaction, false, false }, { "createrawtransaction", &createrawtransaction, false, false }, @@ -254,6 +257,7 @@ static const CRPCCommand vRPCCommands[] = { "gettxout", &gettxout, true, false }, { "lockunspent", &lockunspent, false, false }, { "listlockunspent", &listlockunspent, false, false }, + { "verifychain", &verifychain, true, false }, }; CRPCTable::CRPCTable() @@ -1194,6 +1198,8 @@ Array RPCConvertValues(const std::string &strMethod, const std::vector<std::stri if (strMethod == "lockunspent" && n > 0) ConvertTo<bool>(params[0]); if (strMethod == "lockunspent" && n > 1) ConvertTo<Array>(params[1]); if (strMethod == "importprivkey" && n > 2) ConvertTo<bool>(params[2]); + if (strMethod == "verifychain" && n > 0) ConvertTo<boost::int64_t>(params[0]); + if (strMethod == "verifychain" && n > 1) ConvertTo<boost::int64_t>(params[1]); return params; } diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 44c657f8dc..4d5599be84 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -145,8 +145,11 @@ extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, b extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp); + extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp); @@ -198,6 +201,7 @@ extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, b extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp +extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp); @@ -205,5 +209,6 @@ extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fH extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp); #endif diff --git a/src/bloom.cpp b/src/bloom.cpp index d9ec2efa81..b6799e143d 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -5,7 +5,7 @@ #include <stdlib.h> #include "bloom.h" -#include "main.h" +#include "core.h" #include "script.h" #define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455 diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8859424d20..3bb62fb793 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -6,7 +6,8 @@ #include "assert.h" #include "chainparams.h" -#include "main.h" +#include "core.h" +#include "protocol.h" #include "util.h" // diff --git a/src/core.cpp b/src/core.cpp index b12c90efe8..afba0959cf 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -4,4 +4,298 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "core.h" +#include "util.h" +std::string COutPoint::ToString() const +{ + return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); +} + +void COutPoint::print() const +{ + printf("%s\n", ToString().c_str()); +} + +CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn) +{ + prevout = prevoutIn; + scriptSig = scriptSigIn; + nSequence = nSequenceIn; +} + +CTxIn::CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn, unsigned int nSequenceIn) +{ + prevout = COutPoint(hashPrevTx, nOut); + scriptSig = scriptSigIn; + nSequence = nSequenceIn; +} + +std::string CTxIn::ToString() const +{ + std::string str; + str += "CTxIn("; + str += prevout.ToString(); + if (prevout.IsNull()) + str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); + else + str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); + if (nSequence != std::numeric_limits<unsigned int>::max()) + str += strprintf(", nSequence=%u", nSequence); + str += ")"; + return str; +} + +void CTxIn::print() const +{ + printf("%s\n", ToString().c_str()); +} + +CTxOut::CTxOut(int64 nValueIn, CScript scriptPubKeyIn) +{ + nValue = nValueIn; + scriptPubKey = scriptPubKeyIn; +} + +uint256 CTxOut::GetHash() const +{ + return SerializeHash(*this); +} + +std::string CTxOut::ToString() const +{ + if (scriptPubKey.size() < 6) + return "CTxOut(error)"; + return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); +} + +void CTxOut::print() const +{ + printf("%s\n", ToString().c_str()); +} + +uint256 CTransaction::GetHash() const +{ + return SerializeHash(*this); +} + +bool CTransaction::IsNewerThan(const CTransaction& old) const +{ + if (vin.size() != old.vin.size()) + return false; + for (unsigned int i = 0; i < vin.size(); i++) + if (vin[i].prevout != old.vin[i].prevout) + return false; + + bool fNewer = false; + unsigned int nLowest = std::numeric_limits<unsigned int>::max(); + for (unsigned int i = 0; i < vin.size(); i++) + { + if (vin[i].nSequence != old.vin[i].nSequence) + { + if (vin[i].nSequence <= nLowest) + { + fNewer = false; + nLowest = vin[i].nSequence; + } + if (old.vin[i].nSequence < nLowest) + { + fNewer = true; + nLowest = old.vin[i].nSequence; + } + } + } + return fNewer; +} + +std::string CTransaction::ToString() const +{ + std::string str; + str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", + GetHash().ToString().substr(0,10).c_str(), + nVersion, + vin.size(), + vout.size(), + nLockTime); + for (unsigned int i = 0; i < vin.size(); i++) + str += " " + vin[i].ToString() + "\n"; + for (unsigned int i = 0; i < vout.size(); i++) + str += " " + vout[i].ToString() + "\n"; + return str; +} + +void CTransaction::print() const +{ + printf("%s", ToString().c_str()); +} + +// Amount compression: +// * If the amount is 0, output 0 +// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) +// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) +// * call the result n +// * output 1 + 10*(9*n + d - 1) + e +// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 +// (this is decodable, as d is in [1-9] and e is in [0-9]) + +uint64 CTxOutCompressor::CompressAmount(uint64 n) +{ + if (n == 0) + return 0; + int e = 0; + while (((n % 10) == 0) && e < 9) { + n /= 10; + e++; + } + if (e < 9) { + int d = (n % 10); + assert(d >= 1 && d <= 9); + n /= 10; + return 1 + (n*9 + d - 1)*10 + e; + } else { + return 1 + (n - 1)*10 + 9; + } +} + +uint64 CTxOutCompressor::DecompressAmount(uint64 x) +{ + // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 + if (x == 0) + return 0; + x--; + // x = 10*(9*n + d - 1) + e + int e = x % 10; + x /= 10; + uint64 n = 0; + if (e < 9) { + // x = 9*n + d - 1 + int d = (x % 9) + 1; + x /= 9; + // x = n + n = x*10 + d; + } else { + n = x+1; + } + while (e) { + n *= 10; + e--; + } + return n; +} + +// calculate number of bytes for the bitmask, and its number of non-zero bytes +// each bit in the bitmask represents the availability of one output, but the +// availabilities of the first two outputs are encoded separately +void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { + unsigned int nLastUsedByte = 0; + for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { + bool fZero = true; + for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { + if (!vout[2+b*8+i].IsNull()) { + fZero = false; + continue; + } + } + if (!fZero) { + nLastUsedByte = b + 1; + nNonzeroBytes++; + } + } + nBytes += nLastUsedByte; +} + +bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) { + if (out.n >= vout.size()) + return false; + if (vout[out.n].IsNull()) + return false; + undo = CTxInUndo(vout[out.n]); + vout[out.n].SetNull(); + Cleanup(); + if (vout.size() == 0) { + undo.nHeight = nHeight; + undo.fCoinBase = fCoinBase; + undo.nVersion = this->nVersion; + } + return true; +} + +bool CCoins::Spend(int nPos) { + CTxInUndo undo; + COutPoint out(0, nPos); + return Spend(out, undo); +} + +uint256 CBlockHeader::GetHash() const +{ + return Hash(BEGIN(nVersion), END(nNonce)); +} + +uint256 CBlock::BuildMerkleTree() const +{ + vMerkleTree.clear(); + BOOST_FOREACH(const CTransaction& tx, vtx) + vMerkleTree.push_back(tx.GetHash()); + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + for (int i = 0; i < nSize; i += 2) + { + int i2 = std::min(i+1, nSize-1); + vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), + BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); + } + j += nSize; + } + return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); +} + +std::vector<uint256> CBlock::GetMerkleBranch(int nIndex) const +{ + if (vMerkleTree.empty()) + BuildMerkleTree(); + std::vector<uint256> vMerkleBranch; + int j = 0; + for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) + { + int i = std::min(nIndex^1, nSize-1); + vMerkleBranch.push_back(vMerkleTree[j+i]); + nIndex >>= 1; + j += nSize; + } + return vMerkleBranch; +} + +uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex) +{ + if (nIndex == -1) + return 0; + BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + { + if (nIndex & 1) + hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + else + hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + nIndex >>= 1; + } + return hash; +} + +void CBlock::print() const +{ + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", + GetHash().ToString().c_str(), + nVersion, + hashPrevBlock.ToString().c_str(), + hashMerkleRoot.ToString().c_str(), + nTime, nBits, nNonce, + vtx.size()); + for (unsigned int i = 0; i < vtx.size(); i++) + { + printf(" "); + vtx[i].print(); + } + printf(" vMerkleTree: "); + for (unsigned int i = 0; i < vMerkleTree.size(); i++) + printf("%s ", vMerkleTree[i].ToString().c_str()); + printf("\n"); +} diff --git a/src/core.h b/src/core.h index c568fd2ef9..1b9d4dd765 100644 --- a/src/core.h +++ b/src/core.h @@ -7,7 +7,6 @@ #include "uint256.h" #include "serialize.h" -#include "util.h" #include "script.h" #include <stdio.h> @@ -42,15 +41,8 @@ public: return !(a == b); } - std::string ToString() const - { - return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10).c_str(), n); - } - - void print() const - { - printf("%s\n", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; /** An inpoint - a combination of a transaction and an index n into its vin */ @@ -82,19 +74,8 @@ public: nSequence = std::numeric_limits<unsigned int>::max(); } - explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()) - { - prevout = prevoutIn; - scriptSig = scriptSigIn; - nSequence = nSequenceIn; - } - - CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()) - { - prevout = COutPoint(hashPrevTx, nOut); - scriptSig = scriptSigIn; - nSequence = nSequenceIn; - } + explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()); + CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max()); IMPLEMENT_SERIALIZE ( @@ -120,25 +101,8 @@ public: return !(a == b); } - std::string ToString() const - { - std::string str; - str += "CTxIn("; - str += prevout.ToString(); - if (prevout.IsNull()) - str += strprintf(", coinbase %s", HexStr(scriptSig).c_str()); - else - str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str()); - if (nSequence != std::numeric_limits<unsigned int>::max()) - str += strprintf(", nSequence=%u", nSequence); - str += ")"; - return str; - } - - void print() const - { - printf("%s\n", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; @@ -158,11 +122,7 @@ public: SetNull(); } - CTxOut(int64 nValueIn, CScript scriptPubKeyIn) - { - nValue = nValueIn; - scriptPubKey = scriptPubKeyIn; - } + CTxOut(int64 nValueIn, CScript scriptPubKeyIn); IMPLEMENT_SERIALIZE ( @@ -181,10 +141,7 @@ public: return (nValue == -1); } - uint256 GetHash() const - { - return SerializeHash(*this); - } + uint256 GetHash() const; bool IsDust(int64 nMinRelayTxFee) const { @@ -210,17 +167,8 @@ public: return !(a == b); } - std::string ToString() const - { - if (scriptPubKey.size() < 6) - return "CTxOut(error)"; - return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); - } - - void print() const - { - printf("%s\n", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; @@ -265,39 +213,8 @@ public: return (vin.empty() && vout.empty()); } - uint256 GetHash() const - { - return SerializeHash(*this); - } - - bool IsNewerThan(const CTransaction& old) const - { - if (vin.size() != old.vin.size()) - return false; - for (unsigned int i = 0; i < vin.size(); i++) - if (vin[i].prevout != old.vin[i].prevout) - return false; - - bool fNewer = false; - unsigned int nLowest = std::numeric_limits<unsigned int>::max(); - for (unsigned int i = 0; i < vin.size(); i++) - { - if (vin[i].nSequence != old.vin[i].nSequence) - { - if (vin[i].nSequence <= nLowest) - { - fNewer = false; - nLowest = vin[i].nSequence; - } - if (old.vin[i].nSequence < nLowest) - { - fNewer = true; - nLowest = old.vin[i].nSequence; - } - } - } - return fNewer; - } + uint256 GetHash() const; + bool IsNewerThan(const CTransaction& old) const; bool IsCoinBase() const { @@ -318,26 +235,8 @@ public: } - std::string ToString() const - { - std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%u)\n", - GetHash().ToString().substr(0,10).c_str(), - nVersion, - vin.size(), - vout.size(), - nLockTime); - for (unsigned int i = 0; i < vin.size(); i++) - str += " " + vin[i].ToString() + "\n"; - for (unsigned int i = 0; i < vout.size(); i++) - str += " " + vout[i].ToString() + "\n"; - return str; - } - - void print() const - { - printf("%s", ToString().c_str()); - } + std::string ToString() const; + void print() const; }; /** wrapper for CTxOut that provides a more compact serialization */ @@ -521,26 +420,7 @@ public: return !(a == b); } - // calculate number of bytes for the bitmask, and its number of non-zero bytes - // each bit in the bitmask represents the availability of one output, but the - // availabilities of the first two outputs are encoded separately - void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const { - unsigned int nLastUsedByte = 0; - for (unsigned int b = 0; 2+b*8 < vout.size(); b++) { - bool fZero = true; - for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++) { - if (!vout[2+b*8+i].IsNull()) { - fZero = false; - continue; - } - } - if (!fZero) { - nLastUsedByte = b + 1; - nNonzeroBytes++; - } - } - nBytes += nLastUsedByte; - } + void CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) const; bool IsCoinBase() const { return fCoinBase; @@ -633,28 +513,10 @@ public: } // mark an outpoint spent, and construct undo information - bool Spend(const COutPoint &out, CTxInUndo &undo) { - if (out.n >= vout.size()) - return false; - if (vout[out.n].IsNull()) - return false; - undo = CTxInUndo(vout[out.n]); - vout[out.n].SetNull(); - Cleanup(); - if (vout.size() == 0) { - undo.nHeight = nHeight; - undo.fCoinBase = fCoinBase; - undo.nVersion = this->nVersion; - } - return true; - } + bool Spend(const COutPoint &out, CTxInUndo &undo); // mark a vout spent - bool Spend(int nPos) { - CTxInUndo undo; - COutPoint out(0, nPos); - return Spend(out, undo); - } + bool Spend(int nPos); // check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { @@ -722,10 +584,7 @@ public: return (nBits == 0); } - uint256 GetHash() const - { - return Hash(BEGIN(nVersion), END(nNonce)); - } + uint256 GetHash() const; int64 GetBlockTime() const { @@ -733,4 +592,63 @@ public: } }; + +class CBlock : public CBlockHeader +{ +public: + // network and disk + std::vector<CTransaction> vtx; + + // memory only + mutable std::vector<uint256> vMerkleTree; + + CBlock() + { + SetNull(); + } + + CBlock(const CBlockHeader &header) + { + SetNull(); + *((CBlockHeader*)this) = header; + } + + IMPLEMENT_SERIALIZE + ( + READWRITE(*(CBlockHeader*)this); + READWRITE(vtx); + ) + + void SetNull() + { + CBlockHeader::SetNull(); + vtx.clear(); + vMerkleTree.clear(); + } + + CBlockHeader GetBlockHeader() const + { + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrevBlock; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + uint256 BuildMerkleTree() const; + + const uint256 &GetTxHash(unsigned int nIndex) const { + assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first + assert(nIndex < vtx.size()); + return vMerkleTree[nIndex]; + } + + std::vector<uint256> GetMerkleBranch(int nIndex) const; + static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex); + void print() const; +}; + #endif diff --git a/src/init.cpp b/src/init.cpp index 4e599048ac..f6b2c91b40 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -14,7 +14,6 @@ #include "util.h" #include "ui_interface.h" #include "checkpoints.h" -#include "chainparams.h" #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> @@ -120,7 +119,7 @@ void Shutdown() } bitdb.Flush(true); boost::filesystem::remove(GetPidFile()); - UnregisterWallet(pwalletMain); + UnregisterAllWallets(); delete pwalletMain; } @@ -750,20 +749,21 @@ bool AppInit2(boost::thread_group& threadGroup) if (!mapBlockIndex.empty() && pindexGenesisBlock == NULL) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); - // Check for changed -txindex state (only necessary if we are not reindexing anyway) - if (!fReindex && fTxIndex != GetBoolArg("-txindex", false)) { - strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); - break; - } - // Initialize the block index (no-op if non-empty database was already loaded) if (!InitBlockIndex()) { strLoadError = _("Error initializing block database"); break; } + // Check for changed -txindex state + if (fTxIndex != GetBoolArg("-txindex", false)) { + strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); + break; + } + uiInterface.InitMessage(_("Verifying blocks...")); - if (!VerifyDB()) { + if (!VerifyDB(GetArg("-checklevel", 3), + GetArg( "-checkblocks", 288))) { strLoadError = _("Corrupted block database detected"); break; } @@ -820,7 +820,7 @@ bool AppInit2(boost::thread_group& threadGroup) { CBlockIndex* pindex = (*mi).second; CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); block.BuildMerkleTree(); block.print(); printf("\n"); diff --git a/src/main.cpp b/src/main.cpp index 3879b78ad4..d358914406 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -99,9 +99,16 @@ void UnregisterWallet(CWallet* pwalletIn) } } +void UnregisterAllWallets() +{ + LOCK(cs_setpwalletRegistered); + setpwalletRegistered.clear(); +} + // get the wallet transaction with the given hash (if it exists) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) if (pwallet->GetTransaction(hashTx,wtx)) return true; @@ -111,6 +118,7 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) // erases transaction with the given hash from all wallets void static EraseFromWallets(uint256 hash) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->EraseFromWallet(hash); } @@ -118,6 +126,7 @@ void static EraseFromWallets(uint256 hash) // make sure all wallets know about the given transaction, in the given block void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate); } @@ -125,6 +134,7 @@ void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* // notify wallets about a new best chain void static SetBestChain(const CBlockLocator& loc) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->SetBestChain(loc); } @@ -132,6 +142,7 @@ void static SetBestChain(const CBlockLocator& loc) // notify wallets about an updated transaction void static UpdatedTransaction(const uint256& hashTx) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->UpdatedTransaction(hashTx); } @@ -139,6 +150,7 @@ void static UpdatedTransaction(const uint256& hashTx) // dump all wallets void static PrintWallets(const CBlock& block) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->PrintWallet(block); } @@ -146,6 +158,7 @@ void static PrintWallets(const CBlock& block) // notify wallets about an incoming inventory (for request counts) void static Inventory(const uint256& hash) { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->Inventory(hash); } @@ -153,6 +166,7 @@ void static Inventory(const uint256& hash) // ask wallets to resend their transactions void static ResendWalletTransactions() { + LOCK(cs_setpwalletRegistered); BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) pwallet->ResendWalletTransactions(); } @@ -642,7 +656,7 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) if (pcoinsTip->GetCoins(GetHash(), coins)) { CBlockIndex *pindex = FindBlockByHeight(coins.nHeight); if (pindex) { - if (!blockTmp.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(blockTmp, pindex)) return 0; pblock = &blockTmp; } @@ -1131,7 +1145,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock if (pindexSlow) { CBlock block; - if (block.ReadFromDisk(pindexSlow)) { + if (ReadBlockFromDisk(block, pindexSlow)) { BOOST_FOREACH(const CTransaction &tx, block.vtx) { if (tx.GetHash() == hash) { txOut = tx; @@ -1163,12 +1177,62 @@ CBlockIndex* FindBlockByHeight(int nHeight) return vBlockIndexByHeight[nHeight]; } -bool CBlock::ReadFromDisk(const CBlockIndex* pindex) +bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) +{ + // Open history file to append + CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + if (!fileout) + return error("WriteBlockToDisk() : OpenBlockFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(block); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write block + long fileOutPos = ftell(fileout); + if (fileOutPos < 0) + return error("WriteBlockToDisk() : ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << block; + + // Flush stdio buffers and commit to disk before returning + fflush(fileout); + if (!IsInitialBlockDownload()) + FileCommit(fileout); + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) +{ + block.SetNull(); + + // Open history file to read + CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (!filein) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : OpenBlockFile failed"); + + // Read block + try { + filein >> block; + } + catch (std::exception &e) { + return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); + } + + // Check the header + if (!CheckProofOfWork(block.GetHash(), block.nBits)) + return error("ReadBlockFromDisk(CBlock&, CDiskBlockPos&) : errors in block header"); + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) { - if (!ReadFromDisk(pindex->GetBlockPos())) + if (!ReadBlockFromDisk(block, pindex->GetBlockPos())) return false; - if (GetHash() != pindex->GetBlockHash()) - return error("CBlock::ReadFromDisk() : GetHash() doesn't match index"); + if (block.GetHash() != pindex->GetBlockHash()) + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*) : GetHash() doesn't match index"); return true; } @@ -1570,7 +1634,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCach -bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool *pfClean) +bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { assert(pindex == view.GetBestBlock()); @@ -1586,12 +1650,12 @@ bool CBlock::DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoin if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) return error("DisconnectBlock() : failure reading undo data"); - if (blockUndo.vtxundo.size() + 1 != vtx.size()) + if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) return error("DisconnectBlock() : block and undo data inconsistent"); // undo transactions in reverse order - for (int i = vtx.size() - 1; i >= 0; i--) { - const CTransaction &tx = vtx[i]; + for (int i = block.vtx.size() - 1; i >= 0; i--) { + const CTransaction &tx = block.vtx[i]; uint256 hash = tx.GetHash(); // check that all outputs are available @@ -1684,10 +1748,10 @@ void ThreadScriptCheck() { scriptcheckqueue.Thread(); } -bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsViewCache &view, bool fJustCheck) +bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!CheckBlock(state, !fJustCheck, !fJustCheck)) + if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) return false; // verify that the view's current state corresponds to the previous block @@ -1695,7 +1759,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi // Special case for the genesis block, skipping connection of its transactions // (its coinbase is unspendable) - if (GetHash() == Params().HashGenesisBlock()) { + if (block.GetHash() == Params().HashGenesisBlock()) { view.SetBestBlock(pindex); pindexGenesisBlock = pindex; return true; @@ -1719,8 +1783,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); if (fEnforceBIP30) { - for (unsigned int i=0; i<vtx.size(); i++) { - uint256 hash = GetTxHash(i); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + uint256 hash = block.GetTxHash(i); if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction")); } @@ -1741,12 +1805,12 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi int64 nFees = 0; int nInputs = 0; unsigned int nSigOps = 0; - CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(vtx.size())); + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector<std::pair<uint256, CDiskTxPos> > vPos; - vPos.reserve(vtx.size()); - for (unsigned int i=0; i<vtx.size(); i++) + vPos.reserve(block.vtx.size()); + for (unsigned int i = 0; i < block.vtx.size(); i++) { - const CTransaction &tx = vtx[i]; + const CTransaction &tx = block.vtx[i]; nInputs += tx.vin.size(); nSigOps += GetLegacySigOpCount(tx); @@ -1777,19 +1841,19 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi } CTxUndo txundo; - UpdateCoins(tx, state, view, txundo, pindex->nHeight, GetTxHash(i)); + UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i)); if (!tx.IsCoinBase()) blockundo.vtxundo.push_back(txundo); - vPos.push_back(std::make_pair(GetTxHash(i), pos)); + vPos.push_back(std::make_pair(block.GetTxHash(i), pos)); pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } int64 nTime = GetTimeMicros() - nStart; if (fBenchmark) - printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)vtx.size(), 0.001 * nTime, 0.001 * nTime / vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); + printf("- Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin)\n", (unsigned)block.vtx.size(), 0.001 * nTime, 0.001 * nTime / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * nTime / (nInputs-1)); - if (GetValueOut(vtx[0]) > GetBlockValue(pindex->nHeight, nFees)) - return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(vtx[0]), GetBlockValue(pindex->nHeight, nFees))); + if (GetValueOut(block.vtx[0]) > GetBlockValue(pindex->nHeight, nFees)) + return state.DoS(100, error("ConnectBlock() : coinbase pays too much (actual=%"PRI64d" vs limit=%"PRI64d")", GetValueOut(block.vtx[0]), GetBlockValue(pindex->nHeight, nFees))); if (!control.Wait()) return state.DoS(100, false); @@ -1830,8 +1894,8 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi assert(view.SetBestBlock(pindex)); // Watch for transactions paying to me - for (unsigned int i=0; i<vtx.size(); i++) - SyncWithWallets(GetTxHash(i), vtx[i], this, true); + for (unsigned int i = 0; i < block.vtx.size(); i++) + SyncWithWallets(block.GetTxHash(i), block.vtx[i], &block, true); return true; } @@ -1877,10 +1941,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) vector<CTransaction> vResurrect; BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); - if (!block.DisconnectBlock(state, pindex, view)) + if (!DisconnectBlock(block, state, pindex, view)) return error("SetBestBlock() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().c_str()); if (fBenchmark) printf("- Disconnect: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); @@ -1897,10 +1961,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) vector<CTransaction> vDelete; BOOST_FOREACH(CBlockIndex *pindex, vConnect) { CBlock block; - if (!block.ReadFromDisk(pindex)) + if (!ReadBlockFromDisk(block, pindex)) return state.Abort(_("Failed to read block")); int64 nStart = GetTimeMicros(); - if (!block.ConnectBlock(state, pindex, view)) { + if (!ConnectBlock(block, state, pindex, view)) { if (state.IsInvalid()) { InvalidChainFound(pindexNew); InvalidBlockFound(pindex); @@ -2010,25 +2074,25 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) } -bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) +bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos) { // Check for duplicate - uint256 hash = GetHash(); + uint256 hash = block.GetHash(); if (mapBlockIndex.count(hash)) return state.Invalid(error("AddToBlockIndex() : %s already exists", hash.ToString().c_str())); // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(*this); + CBlockIndex* pindexNew = new CBlockIndex(block); assert(pindexNew); map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); - map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock); + map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); if (miPrev != mapBlockIndex.end()) { pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->nTx = vtx.size(); + pindexNew->nTx = block.vtx.size(); pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + pindexNew->GetBlockWork().getuint256(); pindexNew->nChainTx = (pindexNew->pprev ? pindexNew->pprev->nChainTx : 0) + pindexNew->nTx; pindexNew->nFile = pos.nFile; @@ -2049,7 +2113,7 @@ bool CBlock::AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos) // Notify UI to display prev block's coinbase if it was ours static uint256 hashPrevBestCoinBase; UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = GetTxHash(0); + hashPrevBestCoinBase = block.GetTxHash(0); } if (!pblocktree->Flush()) @@ -2155,51 +2219,51 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne } -bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerkleRoot) const +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) { // These are checks that are independent of context // that can be verified before saving an orphan block. // Size limits - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) return state.DoS(100, error("CheckBlock() : size limits failed")); // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits)) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) return state.DoS(50, error("CheckBlock() : proof of work failed")); // Check timestamp - if (GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) return state.Invalid(error("CheckBlock() : block timestamp too far in the future")); // First transaction must be coinbase, the rest must not be - if (vtx.empty() || !vtx[0].IsCoinBase()) + if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock() : first tx is not coinbase")); - for (unsigned int i = 1; i < vtx.size(); i++) - if (vtx[i].IsCoinBase()) + for (unsigned int i = 1; i < block.vtx.size(); i++) + if (block.vtx[i].IsCoinBase()) return state.DoS(100, error("CheckBlock() : more than one coinbase")); // Check transactions - BOOST_FOREACH(const CTransaction& tx, vtx) + BOOST_FOREACH(const CTransaction& tx, block.vtx) if (!CheckTransaction(tx, state)) return error("CheckBlock() : CheckTransaction failed"); // Build the merkle tree already. We need it anyway later, and it makes the // block cache the transaction hashes, which means they don't need to be // recalculated many times during this block's validation. - BuildMerkleTree(); + block.BuildMerkleTree(); // Check for duplicate txids. This is caught by ConnectInputs(), // but catching it earlier avoids a potential DoS attack: set<uint256> uniqueTx; - for (unsigned int i=0; i<vtx.size(); i++) { - uniqueTx.insert(GetTxHash(i)); + for (unsigned int i = 0; i < block.vtx.size(); i++) { + uniqueTx.insert(block.GetTxHash(i)); } - if (uniqueTx.size() != vtx.size()) + if (uniqueTx.size() != block.vtx.size()) return state.DoS(100, error("CheckBlock() : duplicate transaction")); unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, vtx) + BOOST_FOREACH(const CTransaction& tx, block.vtx) { nSigOps += GetLegacySigOpCount(tx); } @@ -2207,16 +2271,16 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk return state.DoS(100, error("CheckBlock() : out-of-bounds SigOpCount")); // Check merkle root - if (fCheckMerkleRoot && hashMerkleRoot != BuildMerkleTree()) + if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree()) return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch")); return true; } -bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp) { // Check for duplicate - uint256 hash = GetHash(); + uint256 hash = block.GetHash(); if (mapBlockIndex.count(hash)) return state.Invalid(error("AcceptBlock() : block already in mapBlockIndex")); @@ -2224,23 +2288,23 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) CBlockIndex* pindexPrev = NULL; int nHeight = 0; if (hash != Params().HashGenesisBlock()) { - map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock); + map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) return state.DoS(10, error("AcceptBlock() : prev block not found")); pindexPrev = (*mi).second; nHeight = pindexPrev->nHeight+1; // Check proof of work - if (nBits != GetNextWorkRequired(pindexPrev, this)) + if (block.nBits != GetNextWorkRequired(pindexPrev, &block)) return state.DoS(100, error("AcceptBlock() : incorrect proof of work")); // Check timestamp against prev - if (GetBlockTime() <= pindexPrev->GetMedianTimePast()) + if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) return state.Invalid(error("AcceptBlock() : block's timestamp is too early")); // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, vtx) - if (!IsFinalTx(tx, nHeight, GetBlockTime())) + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!IsFinalTx(tx, nHeight, block.GetBlockTime())) return state.DoS(10, error("AcceptBlock() : contains a non-final transaction")); // Check that the block chain matches the known block chain up to a checkpoint @@ -2248,7 +2312,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight)); // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (nVersion < 2) + if (block.nVersion < 2) { if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 950, 1000)) || (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 75, 100))) @@ -2257,14 +2321,14 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) } } // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - if (nVersion >= 2) + if (block.nVersion >= 2) { // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): if ((!TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 750, 1000)) || (TestNet() && CBlockIndex::IsSuperMajority(2, pindexPrev, 51, 100))) { CScript expect = CScript() << nHeight; - if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) + if (!std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) return state.DoS(100, error("AcceptBlock() : block height mismatch in coinbase")); } } @@ -2272,16 +2336,16 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp) // Write block to history file try { - unsigned int nBlockSize = ::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION); + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); CDiskBlockPos blockPos; if (dbp != NULL) blockPos = *dbp; - if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, nTime, dbp != NULL)) + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.nTime, dbp != NULL)) return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) - if (!WriteToDisk(blockPos)) + if (!WriteBlockToDisk(block, blockPos)) return state.Abort(_("Failed to write block")); - if (!AddToBlockIndex(state, blockPos)) + if (!AddToBlockIndex(block, state, blockPos)) return error("AcceptBlock() : AddToBlockIndex failed"); } catch(std::runtime_error &e) { return state.Abort(_("System error: ") + e.what()); @@ -2333,7 +2397,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl return state.Invalid(error("ProcessBlock() : already have block (orphan) %s", hash.ToString().c_str())); // Preliminary checks - if (!pblock->CheckBlock(state)) + if (!CheckBlock(*pblock, state)) return error("ProcessBlock() : CheckBlock FAILED"); CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex); @@ -2374,7 +2438,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl } // Store to disk - if (!pblock->AcceptBlock(state, dbp)) + if (!AcceptBlock(*pblock, state, dbp)) return error("ProcessBlock() : AcceptBlock FAILED"); // Recursively process any orphan blocks that depended on this one @@ -2390,7 +2454,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl CBlock* pblockOrphan = (*mi).second; // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan resolution (that is, feeding people an invalid block based on LegitBlockX in order to get anyone relaying LegitBlockX banned) CValidationState stateDummy; - if (pblockOrphan->AcceptBlock(stateDummy)) + if (AcceptBlock(*pblockOrphan, stateDummy)) vWorkQueue.push_back(pblockOrphan->GetHash()); mapOrphanBlocks.erase(pblockOrphan->GetHash()); delete pblockOrphan; @@ -2703,14 +2767,13 @@ bool static LoadBlockIndexDB() return true; } -bool VerifyDB() { +bool VerifyDB(int nCheckLevel, int nCheckDepth) +{ if (pindexBest == NULL || pindexBest->pprev == NULL) return true; // Verify blocks in the best chain - int nCheckLevel = GetArg("-checklevel", 3); - int nCheckDepth = GetArg( "-checkblocks", 288); - if (nCheckDepth == 0) + if (nCheckDepth <= 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; @@ -2728,10 +2791,10 @@ bool VerifyDB() { break; CBlock block; // check level 0: read from disk - if (!block.ReadFromDisk(pindex)) - return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!ReadBlockFromDisk(block, pindex)) + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 1: verify block validity - if (nCheckLevel >= 1 && !block.CheckBlock(state)) + if (nCheckLevel >= 1 && !CheckBlock(block, state)) return error("VerifyDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); // check level 2: verify undo validity if (nCheckLevel >= 2 && pindex) { @@ -2745,7 +2808,7 @@ bool VerifyDB() { // check level 3: check for inconsistencies during memory-only disconnect of tip blocks if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) { bool fClean = true; - if (!block.DisconnectBlock(state, pindex, coins, &fClean)) + if (!DisconnectBlock(block, state, pindex, coins, &fClean)) return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexState = pindex->pprev; if (!fClean) { @@ -2765,9 +2828,9 @@ bool VerifyDB() { boost::this_thread::interruption_point(); pindex = pindex->GetNextInMainChain(); CBlock block; - if (!block.ReadFromDisk(pindex)) - return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); - if (!block.ConnectBlock(state, pindex, coins)) + if (!ReadBlockFromDisk(block, pindex)) + return error("VerifyDB() : *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); + if (!ConnectBlock(block, state, pindex, coins)) return error("VerifyDB() : *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); } } @@ -2818,9 +2881,9 @@ bool InitBlockIndex() { CValidationState state; if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.nTime)) return error("LoadBlockIndex() : FindBlockPos failed"); - if (!block.WriteToDisk(blockPos)) + if (!WriteBlockToDisk(block, blockPos)) return error("LoadBlockIndex() : writing genesis block to disk failed"); - if (!block.AddToBlockIndex(state, blockPos)) + if (!AddToBlockIndex(block, state, blockPos)) return error("LoadBlockIndex() : genesis block not accepted"); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); @@ -2876,7 +2939,7 @@ void PrintBlockTree() // print item CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); printf("%d (blk%05u.dat:0x%x) %s tx %"PRIszu"", pindex->nHeight, pindex->GetBlockPos().nFile, pindex->GetBlockPos().nPos, @@ -3100,7 +3163,7 @@ void static ProcessGetData(CNode* pfrom) if (mi != mapBlockIndex.end()) { CBlock block; - block.ReadFromDisk((*mi).second); + ReadBlockFromDisk(block, (*mi).second); if (inv.type == MSG_BLOCK) pfrom->PushMessage("block", block); else // MSG_FILTERED_BLOCK) @@ -3535,6 +3598,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CInv inv(MSG_TX, tx.GetHash()); pfrom->AddInventoryKnown(inv); + // Truncate messages to the size of the tx in them + unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + unsigned int oldSize = vMsg.size(); + if (nSize < oldSize) { + vMsg.resize(nSize); + printf("truncating oversized TX %s (%u -> %u)\n", + tx.GetHash().ToString().c_str(), + oldSize, nSize); + } + bool fMissingInputs = false; CValidationState state; if (mempool.accept(state, tx, true, &fMissingInputs)) @@ -4422,7 +4495,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey) indexDummy.nHeight = pindexPrev->nHeight + 1; CCoinsViewCache viewNew(*pcoinsTip, true); CValidationState state; - if (!pblock->ConnectBlock(state, &indexDummy, viewNew, true)) + if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); } @@ -4705,59 +4778,6 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet) minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); } -// Amount compression: -// * If the amount is 0, output 0 -// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) -// * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) -// * call the result n -// * output 1 + 10*(9*n + d - 1) + e -// * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 -// (this is decodable, as d is in [1-9] and e is in [0-9]) - -uint64 CTxOutCompressor::CompressAmount(uint64 n) -{ - if (n == 0) - return 0; - int e = 0; - while (((n % 10) == 0) && e < 9) { - n /= 10; - e++; - } - if (e < 9) { - int d = (n % 10); - assert(d >= 1 && d <= 9); - n /= 10; - return 1 + (n*9 + d - 1)*10 + e; - } else { - return 1 + (n - 1)*10 + 9; - } -} - -uint64 CTxOutCompressor::DecompressAmount(uint64 x) -{ - // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 - if (x == 0) - return 0; - x--; - // x = 10*(9*n + d - 1) + e - int e = x % 10; - x /= 10; - uint64 n = 0; - if (e < 9) { - // x = 9*n + d - 1 - int d = (x % 9) + 1; - x /= 9; - // x = n - n = x*10 + d; - } else { - n = x+1; - } - while (e) { - n *= 10; - e--; - } - return n; -} class CMainCleanup diff --git a/src/main.h b/src/main.h index b9879d1097..8ad2437c63 100644 --- a/src/main.h +++ b/src/main.h @@ -119,6 +119,8 @@ struct CBlockTemplate; void RegisterWallet(CWallet* pwalletIn); /** Unregister a wallet from core */ void UnregisterWallet(CWallet* pwalletIn); +/** Unregister all wallets from core */ +void UnregisterAllWallets(); /** Push an updated transaction to all registered wallets */ void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false); @@ -146,7 +148,7 @@ bool LoadBlockIndex(); /** Unload database information */ void UnloadBlockIndex(); /** Verify consistency of the block and coin databases */ -bool VerifyDB(); +bool VerifyDB(int nCheckLevel, int nCheckDepth); /** Print the loaded block tree */ void PrintBlockTree(); /** Find a block by height in the currently-connected chain */ @@ -581,204 +583,33 @@ public: }; -class CBlock : public CBlockHeader -{ -public: - // network and disk - std::vector<CTransaction> vtx; - - // memory only - mutable std::vector<uint256> vMerkleTree; - - CBlock() - { - SetNull(); - } - - CBlock(const CBlockHeader &header) - { - SetNull(); - *((CBlockHeader*)this) = header; - } - - IMPLEMENT_SERIALIZE - ( - READWRITE(*(CBlockHeader*)this); - READWRITE(vtx); - ) - - void SetNull() - { - CBlockHeader::SetNull(); - vtx.clear(); - vMerkleTree.clear(); - } - - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrevBlock; - block.hashMerkleRoot = hashMerkleRoot; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - uint256 BuildMerkleTree() const - { - vMerkleTree.clear(); - BOOST_FOREACH(const CTransaction& tx, vtx) - vMerkleTree.push_back(tx.GetHash()); - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - for (int i = 0; i < nSize; i += 2) - { - int i2 = std::min(i+1, nSize-1); - vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), - BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); - } - j += nSize; - } - return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); - } - - const uint256 &GetTxHash(unsigned int nIndex) const { - assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first - assert(nIndex < vtx.size()); - return vMerkleTree[nIndex]; - } - - std::vector<uint256> GetMerkleBranch(int nIndex) const - { - if (vMerkleTree.empty()) - BuildMerkleTree(); - std::vector<uint256> vMerkleBranch; - int j = 0; - for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) - { - int i = std::min(nIndex^1, nSize-1); - vMerkleBranch.push_back(vMerkleTree[j+i]); - nIndex >>= 1; - j += nSize; - } - return vMerkleBranch; - } - - static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex) - { - if (nIndex == -1) - return 0; - BOOST_FOREACH(const uint256& otherside, vMerkleBranch) - { - if (nIndex & 1) - hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); - else - hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); - nIndex >>= 1; - } - return hash; - } - - bool WriteToDisk(CDiskBlockPos &pos) - { - // Open history file to append - CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); - if (!fileout) - return error("CBlock::WriteToDisk() : OpenBlockFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(Params().MessageStart()) << nSize; - - // Write block - long fileOutPos = ftell(fileout); - if (fileOutPos < 0) - return error("CBlock::WriteToDisk() : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << *this; - - // Flush stdio buffers and commit to disk before returning - fflush(fileout); - if (!IsInitialBlockDownload()) - FileCommit(fileout); - - return true; - } - - bool ReadFromDisk(const CDiskBlockPos &pos) - { - SetNull(); - - // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); - if (!filein) - return error("CBlock::ReadFromDisk() : OpenBlockFile failed"); - // Read block - try { - filein >> *this; - } - catch (std::exception &e) { - return error("%s() : deserialize or I/O error", __PRETTY_FUNCTION__); - } +/** Functions for disk access for blocks */ +bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos); +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); - // Check the header - if (!CheckProofOfWork(GetHash(), nBits)) - return error("CBlock::ReadFromDisk() : errors in block header"); - return true; - } +/** Functions for validating blocks and updating the block tree */ +/** Undo the effects of this block (with given index) on the UTXO set represented by coins. + * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean + * will be true if no problems were found. Otherwise, the return value will be false in case + * of problems. Note that in any case, coins may be modified. */ +bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); +// Apply the effects of this block (with given index) on the UTXO set represented by coins +bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); - void print() const - { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu")\n", - GetHash().ToString().c_str(), - nVersion, - hashPrevBlock.ToString().c_str(), - hashMerkleRoot.ToString().c_str(), - nTime, nBits, nNonce, - vtx.size()); - for (unsigned int i = 0; i < vtx.size(); i++) - { - printf(" "); - vtx[i].print(); - } - printf(" vMerkleTree: "); - for (unsigned int i = 0; i < vMerkleTree.size(); i++) - printf("%s ", vMerkleTree[i].ToString().c_str()); - printf("\n"); - } - - - /** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean - * will be true if no problems were found. Otherwise, the return value will be false in case - * of problems. Note that in any case, coins may be modified. */ - bool DisconnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool *pfClean = NULL); - - // Apply the effects of this block (with given index) on the UTXO set represented by coins - bool ConnectBlock(CValidationState &state, CBlockIndex *pindex, CCoinsViewCache &coins, bool fJustCheck=false); - - // Read a block from disk - bool ReadFromDisk(const CBlockIndex* pindex); - - // Add this block to the block index, and if necessary, switch the active block chain to this - bool AddToBlockIndex(CValidationState &state, const CDiskBlockPos &pos); - - // Context-independent validity checks - bool CheckBlock(CValidationState &state, bool fCheckPOW=true, bool fCheckMerkleRoot=true) const; - - // Store block on disk - // if dbp is provided, the file is known to already reside on disk - bool AcceptBlock(CValidationState &state, CDiskBlockPos *dbp = NULL); -}; +// Add this block to the block index, and if necessary, switch the active block chain to this +bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos); +// Context-independent validity checks +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); +// Store block on disk +// if dbp is provided, the file is known to already reside on disk +bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp = NULL); diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index 9cfab5942a..26d541664e 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -93,7 +93,8 @@ OBJS= \ obj/hash.o \ obj/bloom.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o all: bitcoind.exe diff --git a/src/makefile.mingw b/src/makefile.mingw index 33cc7e6b4a..3659f52040 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -101,7 +101,8 @@ OBJS= \ obj/bloom.o \ obj/noui.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o all: bitcoind.exe diff --git a/src/makefile.osx b/src/makefile.osx index bef0ef3518..269460c1ba 100644 --- a/src/makefile.osx +++ b/src/makefile.osx @@ -104,7 +104,8 @@ OBJS= \ obj/bloom.o \ obj/noui.o \ obj/leveldb.o \ - obj/txdb.o + obj/txdb.o \ + obj/chainparams.o ifndef USE_UPNP override USE_UPNP = - diff --git a/src/net.cpp b/src/net.cpp index 0adf26ef0d..5418c3de40 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -22,6 +22,9 @@ #include <miniupnpc/upnperrors.h> #endif +// Dump addresses to peers.dat every 15 minutes (900s) +#define DUMP_ADDRESSES_INTERVAL 900 + using namespace std; using namespace boost; @@ -1730,7 +1733,7 @@ void StartNode(boost::thread_group& threadGroup) threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler)); // Dump network addresses - threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 10000)); + threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, DUMP_ADDRESSES_INTERVAL * 1000)); } bool StopNode() diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index b12e296f99..b502505f31 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -60,7 +60,9 @@ bool BitcoinAmountField::validate() bool valid = true; if (amount->value() == 0.0) valid = false; - if (valid && !BitcoinUnits::parse(currentUnit, text(), 0)) + else if (!BitcoinUnits::parse(currentUnit, text(), 0)) + valid = false; + else if (amount->value() > BitcoinUnits::maxAmount(currentUnit)) valid = false; setValid(valid); @@ -115,7 +117,7 @@ qint64 BitcoinAmountField::value(bool *valid_out) const { qint64 val_out = 0; bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out); - if(valid_out) + if (valid_out) { *valid_out = valid; } @@ -145,12 +147,12 @@ void BitcoinAmountField::unitChanged(int idx) amount->setDecimals(BitcoinUnits::decimals(currentUnit)); amount->setMaximum(qPow(10, BitcoinUnits::amountDigits(currentUnit)) - qPow(10, -amount->decimals())); - if(currentUnit == BitcoinUnits::uBTC) + if (currentUnit == BitcoinUnits::uBTC) amount->setSingleStep(0.01); else amount->setSingleStep(0.001); - if(valid) + if (valid) { // If value was valid, re-place it in the widget with the new unit setValue(currentValue); diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 1afce2eb7c..cb09e93e76 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -33,6 +33,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Cannot obtain a lock on data directory %s. Bitcoin is probably already " "running."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"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."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: The transaction was rejected! This might happen if some of the coins " "in your wallet were already spent, such as if you used a copy of wallet.dat " "and coins were spent in the copy but not marked as spent here."), @@ -133,6 +137,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Get help for a command"), QT_TRANSLATE_NOOP("bitcoin-core", "How many blocks to check at startup (default: 288, 0 = all)"), QT_TRANSLATE_NOOP("bitcoin-core", "How thorough the block verification is (0-4, default: 3)"), QT_TRANSLATE_NOOP("bitcoin-core", "Imports blocks from external blk000??.dat file"), +QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Information"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -proxy address: '%s'"), diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index d4715abaec..ae9791123d 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -63,6 +63,17 @@ qint64 BitcoinUnits::factor(int unit) } } +qint64 BitcoinUnits::maxAmount(int unit) +{ + switch(unit) + { + case BTC: return Q_INT64_C(21000000); + case mBTC: return Q_INT64_C(21000000000); + case uBTC: return Q_INT64_C(21000000000000); + default: return 0; + } +} + int BitcoinUnits::amountDigits(int unit) { switch(unit) diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index 6e96cef59d..f6fdf6c7be 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -38,6 +38,8 @@ public: static QString description(int unit); //! Number of Satoshis (1e-8) per unit static qint64 factor(int unit); + //! Max amount per unit + static qint64 maxAmount(int unit); //! Number of amount digits (to represent max number of coins) static int amountDigits(int unit); //! Number of decimals left diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 2006a5296b..7628b39bd3 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -143,7 +143,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Send &Coins</translation> </message> <message> - <location line="+260"/> + <location line="+265"/> <source>Export Address Book Data</source> <translation>Export Address Book Data</translation> </message> @@ -325,17 +325,17 @@ This product includes software developed by the OpenSSL Project for use in the O <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+233"/> + <location filename="../bitcoingui.cpp" line="+257"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+280"/> + <location line="+268"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-349"/> + <location line="-343"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -375,7 +375,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Quit application</translation> </message> <message> - <location line="+4"/> + <location line="+7"/> <source>Show information about Bitcoin</source> <translation>Show information about Bitcoin</translation> </message> @@ -395,7 +395,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Options...</translation> </message> <message> - <location line="+6"/> + <location line="+9"/> <source>&Encrypt Wallet...</source> <translation>&Encrypt Wallet...</translation> </message> @@ -410,7 +410,7 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Change Passphrase...</translation> </message> <message> - <location line="+285"/> + <location line="+273"/> <source>Importing blocks from disk...</source> <translation>Importing blocks from disk...</translation> </message> @@ -420,17 +420,17 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="-347"/> + <location line="-341"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> <message> - <location line="+49"/> + <location line="+52"/> <source>Modify configuration options for Bitcoin</source> <translation>Modify configuration options for Bitcoin</translation> </message> <message> - <location line="+9"/> + <location line="+12"/> <source>Backup wallet to another location</source> <translation>Backup wallet to another location</translation> </message> @@ -455,18 +455,20 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Verify message...</translation> </message> <message> - <location line="-165"/> + <location line="-183"/> + <location line="+6"/> <location line="+530"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-530"/> + <location line="-536"/> + <location line="+6"/> <source>Wallet</source> <translation>Wallet</translation> </message> <message> - <location line="+101"/> + <location line="+107"/> <source>&Send</source> <translation>&Send</translation> </message> @@ -481,12 +483,14 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>&Addresses</translation> </message> <message> - <location line="+22"/> + <location line="+23"/> + <location line="+2"/> <source>&About Bitcoin</source> <translation>&About Bitcoin</translation> </message> <message> - <location line="+9"/> + <location line="+10"/> + <location line="+2"/> <source>&Show / Hide</source> <translation>&Show / Hide</translation> </message> @@ -531,18 +535,19 @@ This product includes software developed by the OpenSSL Project for use in the O <translation>Tabs toolbar</translation> </message> <message> - <location line="+17"/> - <location line="+10"/> + <location line="-228"/> + <location line="+288"/> <source>[testnet]</source> <translation>[testnet]</translation> </message> <message> - <location line="+47"/> + <location line="-5"/> + <location line="+5"/> <source>Bitcoin client</source> <translation>Bitcoin client</translation> </message> <message numerus="yes"> - <location line="+141"/> + <location line="+143"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -684,7 +689,7 @@ Address: %4 <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location filename="../bitcoin.cpp" line="+111"/> + <location filename="../bitcoin.cpp" line="+109"/> <source>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</source> <translation>A fatal error occurred. Bitcoin can no longer continue safely and will quit.</translation> </message> @@ -692,7 +697,7 @@ Address: %4 <context> <name>ClientModel</name> <message> - <location filename="../clientmodel.cpp" line="+104"/> + <location filename="../clientmodel.cpp" line="+105"/> <source>Network Alert</source> <translation>Network Alert</translation> </message> @@ -768,7 +773,7 @@ Address: %4 <context> <name>GUIUtil::HelpMessageBox</name> <message> - <location filename="../guiutil.cpp" line="+424"/> + <location filename="../guiutil.cpp" line="+493"/> <location line="+12"/> <source>Bitcoin-Qt</source> <translation>Bitcoin-Qt</translation> @@ -982,7 +987,7 @@ Address: %4 <translation>&Apply</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+53"/> + <location filename="../optionsdialog.cpp" line="+54"/> <source>default</source> <translation>default</translation> </message> @@ -1028,17 +1033,12 @@ Address: %4 </message> <message> <location line="+50"/> - <location line="+166"/> + <location line="+202"/> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> <translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation> </message> <message> - <location line="-124"/> - <source>Balance:</source> - <translation>Balance:</translation> - </message> - <message> - <location line="+29"/> + <location line="-131"/> <source>Unconfirmed:</source> <translation>Unconfirmed:</translation> </message> @@ -1048,7 +1048,22 @@ Address: %4 <translation>Wallet</translation> </message> <message> - <location line="+107"/> + <location line="+49"/> + <source>Confirmed:</source> + <translation>Confirmed:</translation> + </message> + <message> + <location line="+16"/> + <source>Your current spendable balance</source> + <translation>Your current spendable balance</translation> + </message> + <message> + <location line="+29"/> + <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> + <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> + </message> + <message> + <location line="+13"/> <source>Immature:</source> <translation>Immature:</translation> </message> @@ -1058,19 +1073,19 @@ Address: %4 <translation>Mined balance that has not yet matured</translation> </message> <message> - <location line="+46"/> - <source><b>Recent transactions</b></source> - <translation><b>Recent transactions</b></translation> + <location line="+13"/> + <source>Total:</source> + <translation>Total:</translation> </message> <message> - <location line="-101"/> - <source>Your current balance</source> - <translation>Your current balance</translation> + <location line="+16"/> + <source>Your current total balance</source> + <translation>Your current total balance</translation> </message> <message> - <location line="+29"/> - <source>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</source> - <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the current balance</translation> + <location line="+53"/> + <source><b>Recent transactions</b></source> + <translation><b>Recent transactions</b></translation> </message> <message> <location filename="../overviewpage.cpp" line="+116"/> @@ -1082,7 +1097,7 @@ Address: %4 <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+107"/> + <location filename="../paymentserver.cpp" line="+109"/> <source>Cannot start bitcoin: click-to-pay handler</source> <translation>Cannot start bitcoin: click-to-pay handler</translation> </message> @@ -1120,7 +1135,7 @@ Address: %4 <translation>&Save As...</translation> </message> <message> - <location filename="../qrcodedialog.cpp" line="+62"/> + <location filename="../qrcodedialog.cpp" line="+64"/> <source>Error encoding URI into QR Code.</source> <translation>Error encoding URI into QR Code.</translation> </message> @@ -1162,7 +1177,7 @@ Address: %4 <location line="+53"/> <location line="+23"/> <location line="+23"/> - <location filename="../rpcconsole.cpp" line="+339"/> + <location filename="../rpcconsole.cpp" line="+343"/> <source>N/A</source> <translation>N/A</translation> </message> @@ -1296,7 +1311,7 @@ Address: %4 <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+124"/> + <location filename="../sendcoinsdialog.cpp" line="+128"/> <location line="+5"/> <location line="+5"/> <location line="+5"/> @@ -1347,12 +1362,13 @@ Address: %4 <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-59"/> + <location filename="../sendcoinsdialog.cpp" line="-62"/> + <location line="+2"/> <source><b>%1</b> to %2 (%3)</source> <translation><b>%1</b> to %2 (%3)</translation> </message> <message> - <location line="+5"/> + <location line="+6"/> <source>Confirm send coins</source> <translation>Confirm send coins</translation> </message> @@ -1662,7 +1678,7 @@ Address: %4 <context> <name>SplashScreen</name> <message> - <location filename="../splashscreen.cpp" line="+22"/> + <location filename="../splashscreen.cpp" line="+23"/> <source>The Bitcoin developers</source> <translation>The Bitcoin developers</translation> </message> @@ -2096,7 +2112,7 @@ Address: %4 <translation>Show transaction details</translation> </message> <message> - <location line="+139"/> + <location line="+143"/> <source>Export Transaction Data</source> <translation>Export Transaction Data</translation> </message> @@ -2172,7 +2188,7 @@ Address: %4 <context> <name>WalletView</name> <message> - <location filename="../walletview.cpp" line="+42"/> + <location filename="../walletview.cpp" line="+46"/> <source>&Export</source> <translation>&Export</translation> </message> @@ -2182,7 +2198,7 @@ Address: %4 <translation>Export the data in the current tab to a file</translation> </message> <message> - <location line="+193"/> + <location line="+197"/> <source>Backup Wallet</source> <translation>Backup Wallet</translation> </message> @@ -2215,12 +2231,12 @@ Address: %4 <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+94"/> + <location filename="../bitcoinstrings.cpp" line="+98"/> <source>Bitcoin version</source> <translation>Bitcoin version</translation> </message> <message> - <location line="+102"/> + <location line="+103"/> <source>Usage:</source> <translation>Usage:</translation> </message> @@ -2235,12 +2251,12 @@ Address: %4 <translation>List commands</translation> </message> <message> - <location line="-12"/> + <location line="-13"/> <source>Get help for a command</source> <translation>Get help for a command</translation> </message> <message> - <location line="+24"/> + <location line="+25"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -2275,12 +2291,12 @@ Address: %4 <translation>Maintain at most <n> connections to peers (default: 125)</translation> </message> <message> - <location line="-48"/> + <location line="-49"/> <source>Connect to a node to retrieve peer addresses, and disconnect</source> <translation>Connect to a node to retrieve peer addresses, and disconnect</translation> </message> <message> - <location line="+82"/> + <location line="+83"/> <source>Specify your own public address</source> <translation>Specify your own public address</translation> </message> @@ -2290,17 +2306,17 @@ Address: %4 <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation> </message> <message> - <location line="-134"/> + <location line="-135"/> <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> <translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation> </message> <message> - <location line="-29"/> + <location line="-33"/> <source>An error occurred while setting up the RPC port %u for listening on IPv4: %s</source> <translation>An error occurred while setting up the RPC port %u for listening on IPv4: %s</translation> </message> <message> - <location line="+27"/> + <location line="+31"/> <source>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</source> <translation>Listen for JSON-RPC connections on <port> (default: 8332 or testnet: 18332)</translation> </message> @@ -2310,7 +2326,7 @@ Address: %4 <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="+76"/> + <location line="+77"/> <source>Run in the background as a daemon and accept commands</source> <translation>Run in the background as a daemon and accept commands</translation> </message> @@ -2320,12 +2336,12 @@ Address: %4 <translation>Use the test network</translation> </message> <message> - <location line="-112"/> + <location line="-113"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> <message> - <location line="-80"/> + <location line="-84"/> <source>%s, you must set a rpcpassword in the configuration file: %s It is recommended you use the following random password: @@ -2366,6 +2382,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <location line="+3"/> + <source>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.</source> + <translation>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.</translation> + </message> + <message> + <location line="+4"/> <source>Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</source> <translation>Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.</translation> </message> @@ -2560,7 +2581,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>How thorough the block verification is (0-4, default: 3)</translation> </message> <message> - <location line="+19"/> + <location line="+2"/> + <source>Incorrect or no genesis block found. Wrong datadir for network?</source> + <translation>Incorrect or no genesis block found. Wrong datadir for network?</translation> + </message> + <message> + <location line="+18"/> <source>Not enough file descriptors available.</source> <translation>Not enough file descriptors available.</translation> </message> @@ -2585,7 +2611,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Verifying wallet...</translation> </message> <message> - <location line="-69"/> + <location line="+4"/> + <source>You need to rebuild the database using -reindex to change -txindex</source> + <translation>You need to rebuild the database using -reindex to change -txindex</translation> + </message> + <message> + <location line="-74"/> <source>Imports blocks from external blk000??.dat file</source> <translation>Imports blocks from external blk000??.dat file</translation> </message> @@ -2595,7 +2626,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Set the number of script verification threads (up to 16, 0 = auto, <0 = leave that many cores free, default: 0)</translation> </message> <message> - <location line="+77"/> + <location line="+78"/> <source>Information</source> <translation>Information</translation> </message> @@ -2750,12 +2781,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Warning: This version is obsolete, upgrade required!</translation> </message> <message> - <location line="+1"/> - <source>You need to rebuild the databases using -reindex to change -txindex</source> - <translation>You need to rebuild the databases using -reindex to change -txindex</translation> - </message> - <message> - <location line="+1"/> + <location line="+2"/> <source>wallet.dat corrupt, salvage failed</source> <translation>wallet.dat corrupt, salvage failed</translation> </message> @@ -2765,22 +2791,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-67"/> + <location line="-68"/> <source>Allow JSON-RPC connections from specified IP address</source> <translation>Allow JSON-RPC connections from specified IP address</translation> </message> <message> - <location line="+76"/> + <location line="+77"/> <source>Send commands to node running on <ip> (default: 127.0.0.1)</source> <translation>Send commands to node running on <ip> (default: 127.0.0.1)</translation> </message> <message> - <location line="-120"/> + <location line="-121"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+147"/> + <location line="+148"/> <source>Upgrade wallet to latest format</source> <translation>Upgrade wallet to latest format</translation> </message> @@ -2810,12 +2836,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Server private key (default: server.pem)</translation> </message> <message> - <location line="-151"/> + <location line="-156"/> <source>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</source> <translation>Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)</translation> </message> <message> - <location line="+165"/> + <location line="+170"/> <source>This help message</source> <translation>This help message</translation> </message> @@ -2825,7 +2851,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unable to bind to %s on this computer (bind returned error %d, %s)</translation> </message> <message> - <location line="-91"/> + <location line="-92"/> <source>Connect through socks proxy</source> <translation>Connect through socks proxy</translation> </message> @@ -2835,12 +2861,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+55"/> + <location line="+56"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> <message> - <location line="-35"/> + <location line="-36"/> <source>Error loading wallet.dat: Wallet corrupted</source> <translation>Error loading wallet.dat: Wallet corrupted</translation> </message> @@ -2850,17 +2876,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Error loading wallet.dat: Wallet requires newer version of Bitcoin</translation> </message> <message> - <location line="+93"/> + <location line="+94"/> <source>Wallet needed to be rewritten: restart Bitcoin to complete</source> <translation>Wallet needed to be rewritten: restart Bitcoin to complete</translation> </message> <message> - <location line="-95"/> + <location line="-96"/> <source>Error loading wallet.dat</source> <translation>Error loading wallet.dat</translation> </message> <message> - <location line="+28"/> + <location line="+29"/> <source>Invalid -proxy address: '%s'</source> <translation>Invalid -proxy address: '%s'</translation> </message> @@ -2875,7 +2901,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unknown -socks proxy version requested: %i</translation> </message> <message> - <location line="-96"/> + <location line="-97"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -2885,7 +2911,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot resolve -externalip address: '%s'</translation> </message> <message> - <location line="+44"/> + <location line="+45"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</translation> </message> @@ -2905,7 +2931,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Loading block index...</translation> </message> <message> - <location line="-57"/> + <location line="-58"/> <source>Add a node to connect to and attempt to keep the connection open</source> <translation>Add a node to connect to and attempt to keep the connection open</translation> </message> @@ -2920,12 +2946,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Fee per KB to add to transactions you send</translation> </message> <message> - <location line="+19"/> + <location line="+20"/> <source>Loading wallet...</source> <translation>Loading wallet...</translation> </message> <message> - <location line="-52"/> + <location line="-53"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> @@ -2935,22 +2961,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot write default address</translation> </message> <message> - <location line="+64"/> + <location line="+65"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> <message> - <location line="-57"/> + <location line="-58"/> <source>Done loading</source> <translation>Done loading</translation> </message> <message> - <location line="+82"/> + <location line="+83"/> <source>To use the %s option</source> <translation>To use the %s option</translation> </message> <message> - <location line="-74"/> + <location line="-75"/> <source>Error</source> <translation>Error</translation> </message> diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index a0ddc4d9ee..edaa732225 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -82,6 +82,15 @@ Value getblockcount(const Array& params, bool fHelp) return nBestHeight; } +Value getbestblockhash(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getbestblockhash\n" + "Returns the hash of the best (tip) block in the longest block chain."); + + return hashBestChain.GetHex(); +} Value getdifficulty(const Array& params, bool fHelp) { @@ -163,7 +172,7 @@ Value getblock(const Array& params, bool fHelp) CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; - block.ReadFromDisk(pblockindex); + ReadBlockFromDisk(block, pblockindex); if (!fVerbose) { @@ -243,4 +252,20 @@ Value gettxout(const Array& params, bool fHelp) return ret; } +Value verifychain(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "verifychain [check level] [num blocks]\n" + "Verifies blockchain database."); + + int nCheckLevel = GetArg("-checklevel", 3); + int nCheckDepth = GetArg("-checkblocks", 288); + if (params.size() > 0) + nCheckLevel = params[0].get_int(); + if (params.size() > 1) + nCheckDepth = params[1].get_int(); + + return VerifyDB(nCheckLevel, nCheckDepth); +} diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index d46309eaa4..dcfb023f35 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -2,35 +2,68 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <iostream> +#include <fstream> + #include "init.h" // for pwalletMain #include "bitcoinrpc.h" #include "ui_interface.h" #include "base58.h" +#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/lexical_cast.hpp> +#include <boost/variant/get.hpp> +#include <boost/algorithm/string.hpp> #define printf OutputDebugStringF using namespace json_spirit; using namespace std; -class CTxDump -{ -public: - CBlockIndex *pindex; - int64 nValue; - bool fSpent; - CWalletTx* ptx; - int nOut; - CTxDump(CWalletTx* ptx = NULL, int nOut = -1) - { - pindex = NULL; - nValue = 0; - fSpent = false; - this->ptx = ptx; - this->nOut = nOut; +void EnsureWalletIsUnlocked(); + +std::string static EncodeDumpTime(int64 nTime) { + return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); +} + +int64 static DecodeDumpTime(const std::string &str) { + static const boost::posix_time::time_input_facet facet("%Y-%m-%dT%H:%M:%SZ"); + static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0); + const std::locale loc(std::locale::classic(), &facet); + std::istringstream iss(str); + iss.imbue(loc); + boost::posix_time::ptime ptime(boost::date_time::not_a_date_time); + iss >> ptime; + if (ptime.is_not_a_date_time()) + return 0; + return (ptime - epoch).total_seconds(); +} + +std::string static EncodeDumpString(const std::string &str) { + std::stringstream ret; + BOOST_FOREACH(unsigned char c, str) { + if (c <= 32 || c >= 128 || c == '%') { + ret << '%' << HexStr(&c, &c + 1); + } else { + ret << c; + } + } + return ret.str(); +} + +std::string DecodeDumpString(const std::string &str) { + std::stringstream ret; + for (unsigned int pos = 0; pos < str.length(); pos++) { + unsigned char c = str[pos]; + if (c == '%' && pos+2 < str.length()) { + c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) | + ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15)); + pos += 2; + } + ret << c; } -}; + return ret.str(); +} Value importprivkey(const Array& params, bool fHelp) { @@ -63,6 +96,10 @@ Value importprivkey(const Array& params, bool fHelp) pwalletMain->MarkDirty(); pwalletMain->SetAddressBookName(vchAddress, strLabel); + // Don't throw error in case a key is already there + if (pwalletMain->HaveKey(vchAddress)) + return Value::null; + if (!pwalletMain->AddKeyPubKey(key, pubkey)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); @@ -75,6 +112,86 @@ Value importprivkey(const Array& params, bool fHelp) return Value::null; } +Value importwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "importwallet <filename>\n" + "Imports keys from a wallet dump file (see dumpwallet)."); + + EnsureWalletIsUnlocked(); + + ifstream file; + file.open(params[0].get_str().c_str()); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + + int64 nTimeBegin = pindexBest->nTime; + + bool fGood = true; + + while (file.good()) { + std::string line; + std::getline(file, line); + if (line.empty() || line[0] == '#') + continue; + + std::vector<std::string> vstr; + boost::split(vstr, line, boost::is_any_of(" ")); + if (vstr.size() < 2) + continue; + CBitcoinSecret vchSecret; + if (!vchSecret.SetString(vstr[0])) + continue; + CKey key = vchSecret.GetKey(); + CPubKey pubkey = key.GetPubKey(); + CKeyID keyid = pubkey.GetID(); + if (pwalletMain->HaveKey(keyid)) { + printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str()); + continue; + } + int64 nTime = DecodeDumpTime(vstr[1]); + std::string strLabel; + bool fLabel = true; + for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { + if (boost::algorithm::starts_with(vstr[nStr], "#")) + break; + if (vstr[nStr] == "change=1") + fLabel = false; + if (vstr[nStr] == "reserve=1") + fLabel = false; + if (boost::algorithm::starts_with(vstr[nStr], "label=")) { + strLabel = DecodeDumpString(vstr[nStr].substr(6)); + fLabel = true; + } + } + printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str()); + if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + fGood = false; + continue; + } + pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; + if (fLabel) + pwalletMain->SetAddressBookName(keyid, strLabel); + nTimeBegin = std::min(nTimeBegin, nTime); + } + file.close(); + + CBlockIndex *pindex = pindexBest; + while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200) + pindex = pindex->pprev; + + printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1); + pwalletMain->ScanForWalletTransactions(pindex); + pwalletMain->ReacceptWalletTransactions(); + pwalletMain->MarkDirty(); + + if (!fGood) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); + + return Value::null; +} + Value dumpprivkey(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -82,6 +199,8 @@ Value dumpprivkey(const Array& params, bool fHelp) "dumpprivkey <bitcoinaddress>\n" "Reveals the private key corresponding to <bitcoinaddress>."); + EnsureWalletIsUnlocked(); + string strAddress = params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) @@ -94,3 +213,58 @@ Value dumpprivkey(const Array& params, bool fHelp) throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); return CBitcoinSecret(vchSecret).ToString(); } + + +Value dumpwallet(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpwallet <filename>\n" + "Dumps all wallet keys in a human-readable format."); + + EnsureWalletIsUnlocked(); + + ofstream file; + file.open(params[0].get_str().c_str()); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); + + std::map<CKeyID, int64> mapKeyBirth; + std::set<CKeyID> setKeyPool; + pwalletMain->GetKeyBirthTimes(mapKeyBirth); + pwalletMain->GetAllReserveKeys(setKeyPool); + + // sort time/key pairs + std::vector<std::pair<int64, CKeyID> > vKeyBirth; + for (std::map<CKeyID, int64>::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { + vKeyBirth.push_back(std::make_pair(it->second, it->first)); + } + mapKeyBirth.clear(); + std::sort(vKeyBirth.begin(), vKeyBirth.end()); + + // produce output + file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str()); + file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str()); + file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str()); + file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str()); + file << "\n"; + for (std::vector<std::pair<int64, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { + const CKeyID &keyid = it->second; + std::string strTime = EncodeDumpTime(it->first); + std::string strAddr = CBitcoinAddress(keyid).ToString(); + CKey key; + if (pwalletMain->GetKey(keyid, key)) { + if (pwalletMain->mapAddressBook.count(keyid)) { + file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), EncodeDumpString(pwalletMain->mapAddressBook[keyid]).c_str(), strAddr.c_str()); + } else if (setKeyPool.count(keyid)) { + file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), strAddr.c_str()); + } else { + file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(key).ToString().c_str(), strTime.c_str(), strAddr.c_str()); + } + } + } + file << "\n"; + file << "# End of dump\n"; + file.close(); + return Value::null; +} diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index d0b0a70be4..a70c0958df 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -4,7 +4,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "chainparams.h" -#include "main.h" #include "db.h" #include "init.h" #include "bitcoinrpc.h" diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 61cb4e390e..f08688d386 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -9,7 +9,6 @@ #include "bitcoinrpc.h" #include "db.h" #include "init.h" -#include "main.h" #include "net.h" #include "wallet.h" diff --git a/src/script.cpp b/src/script.cpp index cf6eeaf392..14fe80e207 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -1474,6 +1474,42 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto return true; } +class CAffectedKeysVisitor : public boost::static_visitor<void> { +private: + const CKeyStore &keystore; + std::vector<CKeyID> &vKeys; + +public: + CAffectedKeysVisitor(const CKeyStore &keystoreIn, std::vector<CKeyID> &vKeysIn) : keystore(keystoreIn), vKeys(vKeysIn) {} + + void Process(const CScript &script) { + txnouttype type; + std::vector<CTxDestination> vDest; + int nRequired; + if (ExtractDestinations(script, type, vDest, nRequired)) { + BOOST_FOREACH(const CTxDestination &dest, vDest) + boost::apply_visitor(*this, dest); + } + } + + void operator()(const CKeyID &keyId) { + if (keystore.HaveKey(keyId)) + vKeys.push_back(keyId); + } + + void operator()(const CScriptID &scriptId) { + CScript script; + if (keystore.GetCScript(scriptId, script)) + Process(script); + } + + void operator()(const CNoDestination &none) {} +}; + +void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys) { + CAffectedKeysVisitor(keystore, vKeys).Process(scriptPubKey); +} + bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags, int nHashType) { diff --git a/src/script.h b/src/script.h index f963467c94..03afe8b652 100644 --- a/src/script.h +++ b/src/script.h @@ -674,6 +674,7 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c bool IsStandard(const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CTxDestination &dest); +void ExtractAffectedKeys(const CKeyStore &keystore, const CScript& scriptPubKey, std::vector<CKeyID> &vKeys); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet); bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); diff --git a/src/sync.h b/src/sync.h index 930c9b2b80..64de7cc57c 100644 --- a/src/sync.h +++ b/src/sync.h @@ -11,6 +11,48 @@ #include <boost/thread/condition_variable.hpp> #include "threadsafety.h" + +//////////////////////////////////////////////// +// // +// THE SIMPLE DEFINITON, EXCLUDING DEBUG CODE // +// // +//////////////////////////////////////////////// + +/* + + + +CCriticalSection mutex; + boost::recursive_mutex mutex; + +LOCK(mutex); + boost::unique_lock<boost::recursive_mutex> criticalblock(mutex); + +LOCK2(mutex1, mutex2); + boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1); + boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2); + +TRY_LOCK(mutex, name); + boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t); + +ENTER_CRITICAL_SECTION(mutex); // no RAII + mutex.lock(); + +LEAVE_CRITICAL_SECTION(mutex); // no RAII + mutex.unlock(); + + + + */ + + + +/////////////////////////////// +// // +// THE ACTUAL IMPLEMENTATION // +// // +/////////////////////////////// + // Template mixin that adds -Wthread-safety locking annotations to a // subset of the mutex API. template <typename PARENT> diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index d626f9a6f4..5675c40e76 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(May15) // After May 15'th, big blocks are OK: forkingBlock.nTime = tMay15; // Invalidates PoW - BOOST_CHECK(forkingBlock.CheckBlock(state, false, false)); + BOOST_CHECK(CheckBlock(forkingBlock, state, false, false)); } SetMockTime(0); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 64bd3a1b28..fd936517fd 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -263,28 +263,10 @@ BOOST_AUTO_TEST_CASE(util_IsHex) BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) { - // Expected results for the determinstic seed. - const uint32_t exp_vals[11] = { 91632771U,1889679809U,3842137544U,3256031132U, - 1761911779U, 489223532U,2692793790U,2737472863U, - 2796262275U,1309899767U,840571781U}; - // Expected 0s in rand()%(idx+2) for the determinstic seed. - const int exp_count[9] = {5013,3346,2415,1972,1644,1386,1176,1096,1009}; int i; int count=0; - seed_insecure_rand(); - - //Does the non-determistic rand give us results that look too like the determinstic one? - for (i=0;i<10;i++) - { - int match = 0; - uint32_t rval = insecure_rand(); - for (int j=0;j<11;j++)match |= rval==exp_vals[j]; - count += match; - } - // sum(binomial(10,i)*(11/(2^32))^i*(1-(11/(2^32)))^(10-i),i,0,4) ~= 1-1/2^134.73 - // So _very_ unlikely to throw a false failure here. - BOOST_CHECK(count<=4); + seed_insecure_rand(true); for (int mod=2;mod<11;mod++) { @@ -307,20 +289,6 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) BOOST_CHECK(count<=10000/mod+err); BOOST_CHECK(count>=10000/mod-err); } - - seed_insecure_rand(true); - - for (i=0;i<11;i++) - { - BOOST_CHECK_EQUAL(insecure_rand(),exp_vals[i]); - } - - for (int mod=2;mod<11;mod++) - { - count = 0; - for (i=0;i<10000;i++) count += insecure_rand()%mod==0; - BOOST_CHECK_EQUAL(count,exp_count[mod-2]); - } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util.h b/src/util.h index 86a38ad331..bee2749c16 100644 --- a/src/util.h +++ b/src/util.h @@ -527,7 +527,7 @@ inline uint32_t ByteReverse(uint32_t value) // Standard wrapper for do-something-forever thread functions. // "Forever" really means until the thread is interrupted. // Use it like: -// new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 10000)); +// new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 900000)); // or maybe: // boost::function<void()> f = boost::bind(&FunctionWithArg, argument); // threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds)); @@ -540,8 +540,8 @@ template <typename Callable> void LoopForever(const char* name, Callable func, { while (1) { - func(); MilliSleep(msecs); + func(); } } catch (boost::thread_interrupted) diff --git a/src/version.cpp b/src/version.cpp index 8af406feab..d9d6724a02 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -36,7 +36,7 @@ const std::string CLIENT_NAME("Satoshi"); // git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$ #ifdef GIT_ARCHIVE # define GIT_COMMIT_ID "$Format:%h$" -# define GIT_COMMIT_DATE "$Format:%cD" +# define GIT_COMMIT_DATE "$Format:%cD$" #endif #define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \ diff --git a/src/wallet.cpp b/src/wallet.cpp index a205d52b55..488787f967 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -804,7 +804,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) } CBlock block; - block.ReadFromDisk(pindex); + ReadBlockFromDisk(block, pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) @@ -1846,7 +1846,7 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) +void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const { setAddress.clear(); @@ -1908,3 +1908,53 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) } } +void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const { + mapKeyBirth.clear(); + + // get birth times for keys with metadata + for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) + if (it->second.nCreateTime) + mapKeyBirth[it->first] = it->second.nCreateTime; + + // map in which we'll infer heights of other keys + CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin + std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock; + std::set<CKeyID> setKeys; + GetKeys(setKeys); + BOOST_FOREACH(const CKeyID &keyid, setKeys) { + if (mapKeyBirth.count(keyid) == 0) + mapKeyFirstBlock[keyid] = pindexMax; + } + setKeys.clear(); + + // if there are no such keys, we're done + if (mapKeyFirstBlock.empty()) + return; + + // find first block that affects those keys, if there are any left + std::vector<CKeyID> vAffected; + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { + // iterate over all wallet transactions... + const CWalletTx &wtx = (*it).second; + std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock); + if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) { + // ... which are already in a block + int nHeight = blit->second->nHeight; + BOOST_FOREACH(const CTxOut &txout, wtx.vout) { + // iterate over all their outputs + ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected); + BOOST_FOREACH(const CKeyID &keyid, vAffected) { + // ... and all their affected keys + std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid); + if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight) + rit->second = blit->second; + } + vAffected.clear(); + } + } + } + + // Extract block timestamps for those keys + for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) + mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off +} diff --git a/src/wallet.h b/src/wallet.h index 48bd511971..36b3608fb0 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -159,6 +159,8 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); + void GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const; + /** Increment the next transaction order id @return next transaction order id */ @@ -200,7 +202,7 @@ public: void ReturnKey(int64 nIndex); bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true); int64 GetOldestKeyPoolTime(); - void GetAllReserveKeys(std::set<CKeyID>& setAddress); + void GetAllReserveKeys(std::set<CKeyID>& setAddress) const; std::set< std::set<CTxDestination> > GetAddressGroupings(); std::map<CTxDestination, int64> GetAddressBalances(); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index bf23357f79..702e219a5b 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -365,7 +365,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { int64 nIndex; ssKey >> nIndex; + CKeyPool keypool; + ssValue >> keypool; pwallet->setKeyPool.insert(nIndex); + + // If no metadata exists yet, create a default with the pool key's + // creation time. Note that this may be overwritten by actually + // stored metadata for that key later, which is fine. + CKeyID keyid = keypool.vchPubKey.GetID(); + if (pwallet->mapKeyMetadata.count(keyid) == 0) + pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); } else if (strType == "version") { |