diff options
59 files changed, 617 insertions, 41 deletions
diff --git a/Makefile.am b/Makefile.am index 7a46652ec..0b3a822bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -162,7 +162,7 @@ check-local: @qa/pull-tester/run-bitcoind-for-test.sh $(JAVA) -jar $(JAVA_COMPARISON_TOOL) qa/tmp/compTool $(COMPARISON_TOOL_REORG_TESTS) endif -EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/pull-tester.sh $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) +EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/pull-tester.sh qa/rpc-tests $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) CLEANFILES = $(OSX_DMG) $(OSX_APP) $(BITCOIN_WIN_INSTALLER) diff --git a/doc/build-unix.md b/doc/build-unix.md index 31159d44b..b957baa91 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -52,6 +52,13 @@ Licenses of statically linked libraries: - protobuf 2.5.0 - libqrencode 3.2.0 +System requirements +-------------------- + +C++ compilers are memory-hungry. It is recommended to have at least 1 GB of +memory available when compiling Bitcoin Core. With 512MB of memory or less +compilation will take much longer due to swap thrashing. + Dependency Build Instructions: Ubuntu & Debian ---------------------------------------------- Build requirements: diff --git a/doc/gitian-building.md b/doc/gitian-building.md new file mode 100644 index 000000000..9fef66b76 --- /dev/null +++ b/doc/gitian-building.md @@ -0,0 +1,443 @@ +Gitian building +================ + +*Setup instructions for a gitian build of Bitcoin using a Debian VM or physical system.* + +Gitian is the deterministic build process that is used to build the Bitcoin +Core executables [1]. It provides a way to be reasonably sure that the +executables are really built from source on github. It also makes sure that +the same, tested dependencies are used and statically built into the executable. + +Multiple developers build the source code by following a specific descriptor +("recipe"), cryptographically sign the result, and upload the resulting signature. +These results are compared and only if they match, the build is accepted and uploaded +to bitcoin.org. + +More independent gitian builders are needed, which is why I wrote this +guide. It is preferred to follow these steps yourself instead of using someone else's +VM image to avoid 'contaminating' the build. + +[1] For all platforms except for MacOSX, at this point. Work for deterministic +builds for Mac is under way here: https://github.com/theuni/osx-cross-depends . + +Table of Contents +------------------ + +- [Create a new VirtualBox VM](#create-a-new-virtualbox-vm) +- [Connecting to the VM](#connecting-to-the-vm) +- [Setting up Debian for gitian building](#setting-up-debian-for-gitian-building) +- [Installing gitian](#installing-gitian) +- [Setting up gitian images](#setting-up-gitian-images) +- [Getting and building the inputs](#getting-and-building-the-inputs) +- [Building Bitcoin](#building-bitcoin) +- [Building an alternative repository](#building-an-alternative-repository) +- [Signing externally](#signing-externally) +- [Uploading signatures](#uploading-signatures) + +Create a new VirtualBox VM +--------------------------- + +The first step is to create a new Virtual Machine, which will be explained in +this section. This VM will be used to do the Gitian builds. In this guide it +will be explained how to set up the environment, and how to get the builds +started. + +Debian Linux was chosen as the host distribution because it has a lightweight install (in +contrast to Ubuntu) and is readily available. We here show the steps for +VirtualBox [1], but any kind of virtualization can be used. You can also install +on actual hardware instead of using a VM, in this case you can skip this section. + +In the VirtualBox GUI click "Create" and choose the following parameters in the wizard: + + + +- Type: Linux, Debian (64 bit) + + + +- Memory Size: at least 1024MB, anything lower will really slow the build down + + + +- Hard Drive: Create a virtual hard drive now + + + +- Hard Drive file type: Use the default, VDI (VirtualBox Disk Image) + + + +- Storage on Physical hard drive: Dynamically Allocated + + + +- Disk size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side +- Push the `Create` button + +Get the [Debian 7.4 net installer](http://cdimage.debian.org/debian-cd/7.4.0/amd64/iso-cd/debian-7.4.0-amd64-netinst.iso). +This DVD image can be validated using a SHA256 hashing tool, for example on +Unixy OSes by entering the following in a terminal: + + echo "b712a141bc60269db217d3b3e456179bd6b181645f90e4aac9c42ed63de492e9 /home/orion/Downloads/debian-7.4.0-amd64-netinst.iso" | sha256sum -c + # (must return OK) + +After creating the VM, we need to configure it. + +- Click the `Settings` button, then go to the `Network` tab. Adapter 1 should be attacked to `NAT`. + + + +- Click `Advanced`, then `Port Forwarding`. We want to set up a port through where we can reach the VM to get files in and out. +- Create a new rule by clicking the plus icon. + + + +- Set up the new rule the following way: + - Name: `SSH` + - Protocol: `TCP` + - Leave Host IP empty + - Host Port: `22222` + - Leave Guest IP empty + - Guest Port: `22` + +- Click `Ok` twice to save. + +Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso. + + + +[1] https://www.virtualbox.org/ + +Installing Debian +------------------ + +In this section it will be explained how to install Debian on the newly created VM. + +- Choose the non-graphical installer. We do not need the graphical environment, it will only increase installation time and disk usage. + + + +**Note**: Navigation in the Debian installer: To keep a setting at the default +and proceed, just press `Enter`. To select a different button, press `Tab`. + +- Choose locale and keyboard settings (doesn't matter, you can just go with the defaults or select your own information) + + + + + +- The VM will detect network settings using DHCP, this should all proceed automatically +- Configure the network: + - System name `debian`. + - Leave domain name empty. + + + +- Choose a root password and enter it twice (and remember it for later) + + + +- Name the new user `debian` (the full name doesn't matter, you can leave it empty) + + + + +- Choose a user password and enter it twice (and remember it for later) + + + +- The installer will set up the clock using a time server, this process should be automatic +- Set up the clock: choose a time zone (depends on the locale settings that you picked earlier; specifics don't matter) + + + +- Disk setup + - Partitioning method: Guided - Use the entire disk + + + + - Select disk to partition: SCSI1 (0,0,0) + + + + - Partitioning scheme: All files in one partition + + + + - Finish partitioning and write changes to disk -> *Yes* (`Tab`, `Enter` to select the `Yes` button) + + + + +- The base system will be installed, this will take a minute or so +- Choose a mirror (any will do) + + + +- Enter proxy information (unless you are on an intranet, you can leave this empty) + + + +- Wait a bit while 'Select and install software' runs +- Participate in popularity contest -> *No* +- Choose software to install. We need just the base system. + + + +- Make sure only 'SSH server' and 'Standard System Utilities' are checked +- Uncheck 'Debian Desktop Environment' and 'Print Server' + + + +- Install the GRUB boot loader to the master boot record? -> Yes + + + +- Installation Complete -> *Continue* +- After installation, the VM will reboot and you will have a working Debian VM. Congratulations! + +Connecting to the VM +---------------------- + +After the VM has booted you can connect to it using SSH, and files can be copied from and to the VM using a SFTP utility. +Connect to `localhost`, port `22222` (or the port configured when installing the VM). +On Windows you can use putty[1] and WinSCP[2]. + +For example to connect as `root` from a Linux command prompt use + + $ ssh root@localhost -p 22222 + The authenticity of host '[localhost]:22222 ([127.0.0.1]:22222)' can't be established. + ECDSA key fingerprint is 8e:71:f9:5b:62:46:de:44:01:da:fb:5f:34:b5:f2:18. + Are you sure you want to continue connecting (yes/no)? yes + Warning: Permanently added '[localhost]:22222' (ECDSA) to the list of known hosts. + root@localhost's password: (enter root password configured during install) + Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64 + root@debian:~# + +Replace `root` with `debian` to log in as user. + +[1] http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html +[2] http://winscp.net/eng/index.php + +Setting up Debian for gitian building +-------------------------------------- + +In this section we will be setting up the Debian installation for Gitian building. + +First we need to log in as `root` to set up dependencies and make sure that our +user can use the sudo command. Type/paste the following in the terminal: + + +```bash +apt-get install git ruby sudo apt-cacher-ng qemu-utils debootstrap lxc python-cheetah parted kpartx bridge-utils +adduser debian sudo +``` + +When you get a colorful screen with a question about the 'LXC directory', just +go with the default (`/var/lib/lxc`). + +Then set up LXC and the rest with the following is a complex jumble of settings and workarounds: + +```bash +# the version of lxc-start in Debian 7.4 needs to run as root, so make sure +# that the build script can exectute it without providing a password +echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-start" > /etc/sudoers.d/gitian-lxc +# add cgroup for LXC +echo "cgroup /sys/fs/cgroup cgroup defaults 0 0" >> /etc/fstab +# make /etc/rc.local script that sets up bridge between guest and host +echo '#!/bin/sh -e' > /etc/rc.local +echo 'brctl addbr br0' >> /etc/rc.local +echo 'ifconfig br0 10.0.3.2/24 up' >> /etc/rc.local +echo 'exit 0' >> /etc/rc.local +# make sure that USE_LXC is always set when logging in as debian +echo 'export USE_LXC=1' >> /home/debian/.profile +reboot +``` + +At the end the VM is rebooted to make sure that the changes take effect. + +**Note**: If you're following this guide on a physical system instead of a VirtualBox VM you could use `10.0.2.2` instead +of `10.0.3.2` in the above `ifconfig` line. This avoids having to patch gitian-builder in next section. + +Installing gitian +------------------ + +Re-login as the user `debian` that was created during installation. +The rest of the steps in this guide will be performed as that user. + +There is no `python-vm-builder` package in Debian, so we need to install it from source ourselves, + +```bash +wget http://archive.ubuntu.com/ubuntu/pool/universe/v/vm-builder/vm-builder_0.12.4+bzr489.orig.tar.gz +echo "ec12e0070a007989561bfee5862c89a32c301992dd2771c4d5078ef1b3014f03 vm-builder_0.12.4+bzr489.orig.tar.gz" | sha256sum -c +# (verification -- must return OK) +tar -zxvf vm-builder_0.12.4+bzr489.orig.tar.gz +cd vm-builder-0.12.4+bzr489 +sudo python setup.py install +cd .. +``` + +**Note**: When sudo asks for a password, enter the password for the user *debian* not for *root*. + +Clone the git repositories for bitcoin and gitian, + +```bash +git clone https://github.com/devrandom/gitian-builder.git +git clone https://github.com/bitcoin/bitcoin +``` + +We need to change the guest IP range for the gitian builder because otherwise it will +collide with VirtualBox its NAT IP range. Gitian does not have a way yet to configure +this, so we need to patch the IPs using `sed`. This is not nice but it will +have to do for now... (a [pull request +(#52)](https://github.com/devrandom/gitian-builder/pull/52) to make this +configurable without patching has been submitted): + +```bash +sed -i 's/10.0.2.2/10.0.3.2/g' gitian-builder/target-bin/bootstrap-fixup +sed -i 's/10.0.2.5/10.0.3.5/g' gitian-builder/etc/lxc.config.in +``` + +*note* After you update the gitian-builder repository, you may need to repeat these manual changes. + +Setting up gitian images +------------------------- + +Gitian needs virtual images of the operating system to build in. +Currently this is Ubuntu Precise for both x86 architectures. +These images will be copied and used every time that a build is started to +make sure that the build is deterministic. +Creating the images will take a while, but only has to be done once. + +Execute the following as user `debian`: + +```bash +cd gitian-builder +bin/make-base-vm --lxc --arch i386 --suite precise +bin/make-base-vm --lxc --arch amd64 --suite precise +``` + +There will be a lot of warnings printed during build of the images. These can be ignored. + +**Note**: When sudo asks for a password, enter the password for the user *debian* not for *root*. + +Getting and building the inputs +-------------------------------- + +In [doc/release-process.md](release-process.md) in the bitcoin repository under 'Fetch and build inputs'. +you will find a list of `wget` commands that can be executed to get the dependencies. + +I needed to add `--no-check-certificate` to the OpenSSL wget line to make it work. +Likely this is because the ca-certificates in Debian 7.4 is fairly old. This does not create a +security issue as the gitian descriptors check integrity of the input archives and refuse to work +if any one is corrupted. + +After downloading the archives, execute the `gbuild` commends to build the dependencies. +This can take a long time, but only has to be done when the dependencies change, for example +to upgrade the used version. + +**Note**: Do not forget to copy the result from `build/out` to `inputs` after every gbuild command! This will save +you a lot of time. + +At any time you can check the package installation and build progress with + +```bash +tail -f var/install.log +tail -f var/build.log +``` + +To make sure that the output is exactly the same, and that the time, date, locale and +even the ordering of files in the file system doesn't influence the result, +some special precautions are taken. This means that the result is expected to +be the same every time. The expected SHA256 hashes of the intermediate +inputs (at the time of release 0.9.0) are: + + 05fe8e9aef00d295f24a94deef7d3a918af5aeef371ba57fdd5a6acd8c51f6cb bitcoin-deps-linux32-gitian-r3.zip + 4227aa9d9fedbb4265b8d10a4f78b7435f34b00a54eb4d662bf78f59c6e70c27 bitcoin-deps-linux64-gitian-r3.zip + f29b7d9577417333fb56e023c2977f5726a7c297f320b175a4108cf7cd4c2d29 boost-linux32-1.55.0-gitian-r1.zip + 88232451c4104f7eb16e469ac6474fd1231bd485687253f7b2bdf46c0781d535 boost-linux64-1.55.0-gitian-r1.zip + 60dc2d3b61e9c7d5dbe2f90d5955772ad748a47918ff2d8b74e8db9b1b91c909 boost-win32-1.55.0-gitian-r6.zip + f65fcaf346bc7b73bc8db3a8614f4f6bee2f61fcbe495e9881133a7c2612a167 boost-win64-1.55.0-gitian-r6.zip + 0ba0855e1084132d05fd8687c19d8430b91f6c410a9ab7938e4fea650c2b22c8 bitcoin-deps-win32-gitian-r10.zip + 5f9ffba0c13ddefc1d339f66ab973ea64623c9cc1f9078cb2b145bce86bd28e2 bitcoin-deps-win64-gitian-r10.zip + 963e3e5e85879010a91143c90a711a5d1d5aba992e38672cdf7b54e42c56b2f1 qt-win32-5.2.0-gitian-r2.zip + 751c579830d173ef3e6f194e83d18b92ebef6df03289db13ab77a52b6bc86ef0 qt-win64-5.2.0-gitian-r2.zip + e2e403e1a08869c7eed4d4293bce13d51ec6a63592918b90ae215a0eceb44cb4 protobuf-win32-2.5.0-gitian-r4.zip + a0999037e8b0ef9ade13efd88fee261ba401f5ca910068b7e0cd3262ba667db0 protobuf-win64-2.5.0-gitian-r4.zip + +Building Bitcoin +---------------- + +To build Bitcoin (for Linux and/or Windows) just follow the steps under 'perform +gitian builds' in [doc/release-process.md](release-process.md) in the bitcoin repository. + +Output from `gbuild` will look something like + + Initialized empty Git repository in /home/debian/gitian-builder/inputs/bitcoin/.git/ + remote: Reusing existing pack: 35606, done. + remote: Total 35606 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (35606/35606), 26.52 MiB | 4.28 MiB/s, done. + Resolving deltas: 100% (25724/25724), done. + From https://github.com/bitcoin/bitcoin + ... (new tags, new branch etc) + --- Building for precise i386 --- + Stopping target if it is up + Making a new image copy + stdin: is not a tty + Starting target + Checking if target is up + Preparing build environment + Updating apt-get repository (log in var/install.log) + Installing additional packages (log in var/install.log) + Grabbing package manifest + stdin: is not a tty + Creating build script (var/build-script) + lxc-start: Connection refused - inotify event with no name (mask 32768) + Running build script (log in var/build.log) + +As when building the dependencies, the progress of package installation and building +can be inspected in `var/install.log` and `var/build.log`. + +Building an alternative repository +----------------------------------- + +If you want to do a test build of a pull on github it can be useful to point +the gitian builder at an alternative repository, using the same descriptors +and inputs. + +For example: +```bash +URL=https://github.com/laanwj/bitcoin.git +COMMIT=2014_03_windows_unicode_path +./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml +./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml +``` + +Signing externally +------------------- + +If you want to do the PGP signing on another device that's possible too; just define `SIGNER` as mentioned +and follow the steps in the build process as normally. + + gpg: skipped "laanwj": secret key not available + +When you execute `gsign` you will get an error from GPG, which can be ignored. Copy the resulting `.assert` files +in `gitian.sigs` to your signing machine and do + +```bash + gpg --detach-sign ${VERSION}/${SIGNER}/bitcoin-build.assert + gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-build.assert +``` + +This will create the `.sig` files that can be committed together with the `.assert` files to assert your +gitian build. + +Uploading signatures +--------------------- + +After building and signing you can push your signatures (both the `.assert` and +`.assert.sig` files) to the +[bitcoin/gitian.sigs](https://github.com/bitcoin/gitian.sigs/) repository, or +if not possible create a pull request. You can also mail the files to me +([email protected]) and I'll commit them. + diff --git a/doc/gitian-building/create_vm_file_location_size.png b/doc/gitian-building/create_vm_file_location_size.png Binary files differnew file mode 100644 index 000000000..14aef5aba --- /dev/null +++ b/doc/gitian-building/create_vm_file_location_size.png diff --git a/doc/gitian-building/create_vm_hard_drive.png b/doc/gitian-building/create_vm_hard_drive.png Binary files differnew file mode 100644 index 000000000..a1706e14f --- /dev/null +++ b/doc/gitian-building/create_vm_hard_drive.png diff --git a/doc/gitian-building/create_vm_hard_drive_file_type.png b/doc/gitian-building/create_vm_hard_drive_file_type.png Binary files differnew file mode 100644 index 000000000..251b8ee3e --- /dev/null +++ b/doc/gitian-building/create_vm_hard_drive_file_type.png diff --git a/doc/gitian-building/create_vm_memsize.png b/doc/gitian-building/create_vm_memsize.png Binary files differnew file mode 100644 index 000000000..33717867a --- /dev/null +++ b/doc/gitian-building/create_vm_memsize.png diff --git a/doc/gitian-building/create_vm_page1.png b/doc/gitian-building/create_vm_page1.png Binary files differnew file mode 100644 index 000000000..edaebc622 --- /dev/null +++ b/doc/gitian-building/create_vm_page1.png diff --git a/doc/gitian-building/create_vm_storage_physical_hard_drive.png b/doc/gitian-building/create_vm_storage_physical_hard_drive.png Binary files differnew file mode 100644 index 000000000..987efaa40 --- /dev/null +++ b/doc/gitian-building/create_vm_storage_physical_hard_drive.png diff --git a/doc/gitian-building/debian_install_10_configure_clock.png b/doc/gitian-building/debian_install_10_configure_clock.png Binary files differnew file mode 100644 index 000000000..467c79018 --- /dev/null +++ b/doc/gitian-building/debian_install_10_configure_clock.png diff --git a/doc/gitian-building/debian_install_11_partition_disks.png b/doc/gitian-building/debian_install_11_partition_disks.png Binary files differnew file mode 100644 index 000000000..18110734d --- /dev/null +++ b/doc/gitian-building/debian_install_11_partition_disks.png diff --git a/doc/gitian-building/debian_install_12_choose_disk.png b/doc/gitian-building/debian_install_12_choose_disk.png Binary files differnew file mode 100644 index 000000000..a00d4abf1 --- /dev/null +++ b/doc/gitian-building/debian_install_12_choose_disk.png diff --git a/doc/gitian-building/debian_install_13_partition_scheme.png b/doc/gitian-building/debian_install_13_partition_scheme.png Binary files differnew file mode 100644 index 000000000..2f80f19b6 --- /dev/null +++ b/doc/gitian-building/debian_install_13_partition_scheme.png diff --git a/doc/gitian-building/debian_install_14_finish.png b/doc/gitian-building/debian_install_14_finish.png Binary files differnew file mode 100644 index 000000000..411d457e9 --- /dev/null +++ b/doc/gitian-building/debian_install_14_finish.png diff --git a/doc/gitian-building/debian_install_15_write_changes.png b/doc/gitian-building/debian_install_15_write_changes.png Binary files differnew file mode 100644 index 000000000..f26093982 --- /dev/null +++ b/doc/gitian-building/debian_install_15_write_changes.png diff --git a/doc/gitian-building/debian_install_16_choose_a_mirror.png b/doc/gitian-building/debian_install_16_choose_a_mirror.png Binary files differnew file mode 100644 index 000000000..d2c2e9523 --- /dev/null +++ b/doc/gitian-building/debian_install_16_choose_a_mirror.png diff --git a/doc/gitian-building/debian_install_17_choose_a_mirror2.png b/doc/gitian-building/debian_install_17_choose_a_mirror2.png Binary files differnew file mode 100644 index 000000000..cef2db078 --- /dev/null +++ b/doc/gitian-building/debian_install_17_choose_a_mirror2.png diff --git a/doc/gitian-building/debian_install_18_proxy_settings.png b/doc/gitian-building/debian_install_18_proxy_settings.png Binary files differnew file mode 100644 index 000000000..24ba25c10 --- /dev/null +++ b/doc/gitian-building/debian_install_18_proxy_settings.png diff --git a/doc/gitian-building/debian_install_19_software_selection.png b/doc/gitian-building/debian_install_19_software_selection.png Binary files differnew file mode 100644 index 000000000..d462757af --- /dev/null +++ b/doc/gitian-building/debian_install_19_software_selection.png diff --git a/doc/gitian-building/debian_install_1_boot_menu.png b/doc/gitian-building/debian_install_1_boot_menu.png Binary files differnew file mode 100644 index 000000000..27fd849b4 --- /dev/null +++ b/doc/gitian-building/debian_install_1_boot_menu.png diff --git a/doc/gitian-building/debian_install_20_install_grub.png b/doc/gitian-building/debian_install_20_install_grub.png Binary files differnew file mode 100644 index 000000000..de4f9be0c --- /dev/null +++ b/doc/gitian-building/debian_install_20_install_grub.png diff --git a/doc/gitian-building/debian_install_21_finish_installation.png b/doc/gitian-building/debian_install_21_finish_installation.png Binary files differnew file mode 100644 index 000000000..b967c3550 --- /dev/null +++ b/doc/gitian-building/debian_install_21_finish_installation.png diff --git a/doc/gitian-building/debian_install_2_select_a_language.png b/doc/gitian-building/debian_install_2_select_a_language.png Binary files differnew file mode 100644 index 000000000..1c9e0bcfc --- /dev/null +++ b/doc/gitian-building/debian_install_2_select_a_language.png diff --git a/doc/gitian-building/debian_install_3_select_location.png b/doc/gitian-building/debian_install_3_select_location.png Binary files differnew file mode 100644 index 000000000..005c39565 --- /dev/null +++ b/doc/gitian-building/debian_install_3_select_location.png diff --git a/doc/gitian-building/debian_install_4_configure_keyboard.png b/doc/gitian-building/debian_install_4_configure_keyboard.png Binary files differnew file mode 100644 index 000000000..580c8af7c --- /dev/null +++ b/doc/gitian-building/debian_install_4_configure_keyboard.png diff --git a/doc/gitian-building/debian_install_5_configure_the_network.png b/doc/gitian-building/debian_install_5_configure_the_network.png Binary files differnew file mode 100644 index 000000000..a7fdffc66 --- /dev/null +++ b/doc/gitian-building/debian_install_5_configure_the_network.png diff --git a/doc/gitian-building/debian_install_6_domain_name.png b/doc/gitian-building/debian_install_6_domain_name.png Binary files differnew file mode 100644 index 000000000..7a986d92f --- /dev/null +++ b/doc/gitian-building/debian_install_6_domain_name.png diff --git a/doc/gitian-building/debian_install_6a_set_up_root_password.png b/doc/gitian-building/debian_install_6a_set_up_root_password.png Binary files differnew file mode 100644 index 000000000..31bd210f3 --- /dev/null +++ b/doc/gitian-building/debian_install_6a_set_up_root_password.png diff --git a/doc/gitian-building/debian_install_7_set_up_user_fullname.png b/doc/gitian-building/debian_install_7_set_up_user_fullname.png Binary files differnew file mode 100644 index 000000000..bffc6ccd7 --- /dev/null +++ b/doc/gitian-building/debian_install_7_set_up_user_fullname.png diff --git a/doc/gitian-building/debian_install_8_set_up_username.png b/doc/gitian-building/debian_install_8_set_up_username.png Binary files differnew file mode 100644 index 000000000..9e2750ad4 --- /dev/null +++ b/doc/gitian-building/debian_install_8_set_up_username.png diff --git a/doc/gitian-building/debian_install_9_user_password.png b/doc/gitian-building/debian_install_9_user_password.png Binary files differnew file mode 100644 index 000000000..a26d30cba --- /dev/null +++ b/doc/gitian-building/debian_install_9_user_password.png diff --git a/doc/gitian-building/network_settings.png b/doc/gitian-building/network_settings.png Binary files differnew file mode 100644 index 000000000..1d9b6428a --- /dev/null +++ b/doc/gitian-building/network_settings.png diff --git a/doc/gitian-building/port_forwarding_rules.png b/doc/gitian-building/port_forwarding_rules.png Binary files differnew file mode 100644 index 000000000..e45c9efff --- /dev/null +++ b/doc/gitian-building/port_forwarding_rules.png diff --git a/doc/gitian-building/select_startup_disk.png b/doc/gitian-building/select_startup_disk.png Binary files differnew file mode 100644 index 000000000..729b368fd --- /dev/null +++ b/doc/gitian-building/select_startup_disk.png diff --git a/qa/pull-tester/build-tests.sh.in b/qa/pull-tester/build-tests.sh.in index e7db72111..ebf377a48 100755 --- a/qa/pull-tester/build-tests.sh.in +++ b/qa/pull-tester/build-tests.sh.in @@ -74,6 +74,9 @@ make check # Run RPC integration test on Linux: @abs_top_srcdir@/qa/rpc-tests/wallet.sh @abs_top_srcdir@/linux-build/src +@abs_top_srcdir@/qa/rpc-tests/listtransactions.py --srcdir @abs_top_srcdir@/linux-build/src +# Clean up cache/ directory that the python regression tests create +rm -rf cache if [ $RUN_EXPENSIVE_TESTS = 1 ]; then # Run unit tests and blockchain-tester on Windows: diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py index fa0700f1c..1d0896a3f 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -65,6 +65,7 @@ def initialize_chain(test_dir): """ if not os.path.isdir(os.path.join("cache", "node0")): + devnull = open("/dev/null", "w+") # Create cache directories, run bitcoinds: for i in range(4): datadir = os.path.join("cache", "node"+str(i)) @@ -79,9 +80,9 @@ def initialize_chain(test_dir): if i > 0: args.append("-connect=127.0.0.1:"+str(START_P2P_PORT)) bitcoind_processes.append(subprocess.Popen(args)) - subprocess.check_output([ "bitcoin-cli", "-datadir="+datadir, - "-rpcwait", "getblockcount"]) - + subprocess.check_call([ "bitcoin-cli", "-datadir="+datadir, + "-rpcwait", "getblockcount"], stdout=devnull) + devnull.close() rpcs = [] for i in range(4): try: @@ -113,12 +114,14 @@ def initialize_chain(test_dir): def start_nodes(num_nodes, dir): # Start bitcoinds, and wait for RPC interface to be up and running: + devnull = open("/dev/null", "w+") for i in range(num_nodes): datadir = os.path.join(dir, "node"+str(i)) args = [ "bitcoind", "-datadir="+datadir ] bitcoind_processes.append(subprocess.Popen(args)) - subprocess.check_output([ "bitcoin-cli", "-datadir="+datadir, - "-rpcwait", "getblockcount"]) + subprocess.check_call([ "bitcoin-cli", "-datadir="+datadir, + "-rpcwait", "getblockcount"], stdout=devnull) + devnull.close() # Create&return JSON-RPC connections rpc_connections = [] for i in range(num_nodes): diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 9db1f5e10..9ab8b6844 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -21,7 +21,7 @@ namespace Checkpoints // every system. When reindexing from a fast disk with a slow CPU, it // can be up to 20, while when downloading from a slow network with a // fast multicore CPU, it won't be much higher than 1. - static const double fSigcheckVerificationFactor = 5.0; + static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; struct CCheckpointData { const MapCheckpoints *mapCheckpoints; @@ -104,12 +104,13 @@ namespace Checkpoints } // Guess how far we are in the verification process at the given block index - double GuessVerificationProgress(CBlockIndex *pindex) { + double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks) { if (pindex==NULL) return 0.0; int64_t nNow = time(NULL); + double fSigcheckVerificationFactor = fSigchecks ? SIGCHECK_VERIFICATION_FACTOR : 1.0; double fWorkBefore = 0.0; // Amount of work done before pindex double fWorkAfter = 0.0; // Amount of work left after pindex (estimated) // Work is defined as: 1.0 per transaction before the last checkpoint, and diff --git a/src/checkpoints.h b/src/checkpoints.h index 3724c5753..1b4aacee2 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -24,7 +24,7 @@ namespace Checkpoints // Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex); - double GuessVerificationProgress(CBlockIndex *pindex); + double GuessVerificationProgress(CBlockIndex *pindex, bool fSigchecks = true); extern bool fEnabled; } diff --git a/src/m4/ax_boost_chrono.m4 b/src/m4/ax_boost_chrono.m4 index 9b3958ec7..318ecea17 100644 --- a/src/m4/ax_boost_chrono.m4 +++ b/src/m4/ax_boost_chrono.m4 @@ -81,6 +81,7 @@ AC_DEFUN([AX_BOOST_CHRONO], LDFLAGS_SAVE=$LDFLAGS if test "x$ax_boost_user_chrono_lib" = "x"; then + ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, @@ -105,7 +106,7 @@ AC_DEFUN([AX_BOOST_CHRONO], fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) + AC_MSG_ERROR(Could not find a version of the boost_chrono library!) fi if test "x$link_chrono" = "xno"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/src/m4/ax_boost_filesystem.m4 b/src/m4/ax_boost_filesystem.m4 index f162163cd..f5c9d5647 100644 --- a/src/m4/ax_boost_filesystem.m4 +++ b/src/m4/ax_boost_filesystem.m4 @@ -80,6 +80,7 @@ AC_DEFUN([AX_BOOST_FILESYSTEM], if test "x$ax_cv_boost_filesystem" = "xyes"; then AC_DEFINE(HAVE_BOOST_FILESYSTEM,,[define if the Boost::Filesystem library is available]) BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + ax_lib= if test "x$ax_boost_user_filesystem_lib" = "x"; then for libextension in `ls -r $BOOSTLIBDIR/libboost_filesystem* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do ax_lib=${libextension} @@ -104,7 +105,7 @@ AC_DEFUN([AX_BOOST_FILESYSTEM], fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) + AC_MSG_ERROR(Could not find a version of the boost_filesystem library!) fi if test "x$link_filesystem" != "xyes"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/src/m4/ax_boost_program_options.m4 b/src/m4/ax_boost_program_options.m4 index 65a39c8c7..f59144185 100644 --- a/src/m4/ax_boost_program_options.m4 +++ b/src/m4/ax_boost_program_options.m4 @@ -74,6 +74,7 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available]) BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` if test "x$ax_boost_user_program_options_lib" = "x"; then + ax_lib= for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, @@ -96,7 +97,7 @@ AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS], done fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) + AC_MSG_ERROR(Could not find a version of the boost_program_options library!) fi if test "x$link_program_options" != "xyes"; then AC_MSG_ERROR([Could not link against [$ax_lib] !]) diff --git a/src/m4/ax_boost_system.m4 b/src/m4/ax_boost_system.m4 index c4c45559d..9c78280fc 100644 --- a/src/m4/ax_boost_system.m4 +++ b/src/m4/ax_boost_system.m4 @@ -83,6 +83,7 @@ AC_DEFUN([AX_BOOST_SYSTEM], LDFLAGS_SAVE=$LDFLAGS if test "x$ax_boost_user_system_lib" = "x"; then + ax_lib= for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, @@ -107,7 +108,7 @@ AC_DEFUN([AX_BOOST_SYSTEM], fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) + AC_MSG_ERROR(Could not find a version of the boost_system library!) fi if test "x$link_system" = "xno"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/src/m4/ax_boost_thread.m4 b/src/m4/ax_boost_thread.m4 index 79e12cdb4..9f0bd0b23 100644 --- a/src/m4/ax_boost_thread.m4 +++ b/src/m4/ax_boost_thread.m4 @@ -104,6 +104,7 @@ AC_DEFUN([AX_BOOST_THREAD], ;; esac if test "x$ax_boost_user_thread_lib" = "x"; then + ax_lib= for libextension in `ls -r $BOOSTLIBDIR/libboost_thread* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'`; do ax_lib=${libextension} AC_CHECK_LIB($ax_lib, exit, @@ -128,7 +129,7 @@ AC_DEFUN([AX_BOOST_THREAD], fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) + AC_MSG_ERROR(Could not find a version of the boost_thread library!) fi if test "x$link_thread" = "xno"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/src/m4/ax_boost_unit_test_framework.m4 b/src/m4/ax_boost_unit_test_framework.m4 index 1115f5512..4efd1e2f1 100644 --- a/src/m4/ax_boost_unit_test_framework.m4 +++ b/src/m4/ax_boost_unit_test_framework.m4 @@ -76,6 +76,7 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], if test "x$ax_boost_user_unit_test_framework_lib" = "x"; then saved_ldflags="${LDFLAGS}" + ax_lib= for monitor_library in `ls $BOOSTLIBDIR/libboost_unit_test_framework*.so* $BOOSTLIBDIR/libboost_unit_test_framework*.dylib* $BOOSTLIBDIR/libboost_unit_test_framework*.a* 2>/dev/null` ; do if test -r $monitor_library ; then libextension=`echo $monitor_library | sed 's,.*/,,' | sed -e 's;^lib\(boost_unit_test_framework.*\)\.so.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_unit_test_framework.*\)\.a.*$;\1;'` @@ -124,7 +125,7 @@ AC_DEFUN([AX_BOOST_UNIT_TEST_FRAMEWORK], done fi if test "x$ax_lib" = "x"; then - AC_MSG_ERROR(Could not find a version of the library!) + AC_MSG_ERROR(Could not find a version of the boost_unit_test_framework library!) fi if test "x$link_unit_test_framework" != "xyes"; then AC_MSG_ERROR(Could not link against $ax_lib !) diff --git a/src/main.cpp b/src/main.cpp index 12f76cc9e..45f4935e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1176,9 +1176,14 @@ void static PruneOrphanBlocks() int64_t GetBlockValue(int nHeight, int64_t nFees) { int64_t nSubsidy = 50 * COIN; + int halvings = nHeight / Params().SubsidyHalvingInterval(); + + // Force block reward to zero when right shift is undefined. + if (halvings >= 64) + return nFees; // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years. - nSubsidy >>= (nHeight / Params().SubsidyHalvingInterval()); + nSubsidy >>= halvings; return nSubsidy + nFees; } diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index 3bbc8516a..dd0aa1f3f 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -276,7 +276,6 @@ BITCOIN_QT_CPP = \ qvalidatedlineedit.cpp \ qvaluecombobox.cpp \ rpcconsole.cpp \ - signverifymessagedialog.cpp \ splashscreen.cpp \ trafficgraphwidget.cpp \ utilitydialog.cpp @@ -298,6 +297,7 @@ BITCOIN_QT_CPP += \ recentrequeststablemodel.cpp \ sendcoinsdialog.cpp \ sendcoinsentry.cpp \ + signverifymessagedialog.cpp \ transactiondesc.cpp \ transactiondescdialog.cpp \ transactionfilterproxy.cpp \ diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d8e21c4aa..0db4308bf 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -25,7 +25,9 @@ #include "rpcserver.h" #include "ui_interface.h" #include "util.h" +#ifdef ENABLE_WALLET #include "wallet.h" +#endif #include <stdint.h> diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 9df8f180b..dc9d2afe2 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -97,7 +97,7 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) : connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool))); // click on checkbox - connect(ui->treeWidget, SIGNAL(itemChanged( QTreeWidgetItem*, int)), this, SLOT(viewItemChanged( QTreeWidgetItem*, int))); + connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(viewItemChanged(QTreeWidgetItem*, int))); // click on header #if QT_VERSION < 0x050000 @@ -434,7 +434,8 @@ void CoinControlDialog::updateLabelLocked() void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { - if (!model) return; + if (!model) + return; // nPayAmount qint64 nPayAmount = 0; @@ -640,17 +641,18 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) void CoinControlDialog::updateView() { + if (!model || !model->getOptionsModel() || !model->getAddressTableModel()) + return; + bool treeMode = ui->radioTreeMode->isChecked(); ui->treeWidget->clear(); ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox ui->treeWidget->setAlternatingRowColors(!treeMode); - QFlags<Qt::ItemFlag> flgCheckbox=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; - QFlags<Qt::ItemFlag> flgTristate=Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; + QFlags<Qt::ItemFlag> flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; + QFlags<Qt::ItemFlag> flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; - int nDisplayUnit = BitcoinUnits::BTC; - if (model && model->getOptionsModel()) - nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); + int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); map<QString, vector<COutput> > mapCoins; model->listCoins(mapCoins); @@ -658,11 +660,10 @@ void CoinControlDialog::updateView() BOOST_FOREACH(PAIRTYPE(QString, vector<COutput>) coins, mapCoins) { QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem(); + itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; - QString sWalletLabel = ""; - if (model->getAddressTableModel()) - sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); - if (sWalletLabel.length() == 0) + QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); + if (sWalletLabel.isEmpty()) sWalletLabel = tr("(no label)"); if (treeMode) @@ -671,7 +672,7 @@ void CoinControlDialog::updateView() ui->treeWidget->addTopLevelItem(itemWalletAddress); itemWalletAddress->setFlags(flgTristate); - itemWalletAddress->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); + itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); // label itemWalletAddress->setText(COLUMN_LABEL, sWalletLabel); @@ -722,10 +723,8 @@ void CoinControlDialog::updateView() } else if (!treeMode) { - QString sLabel = ""; - if (model->getAddressTableModel()) - sLabel = model->getAddressTableModel()->labelForAddress(sAddress); - if (sLabel.length() == 0) + QString sLabel = model->getAddressTableModel()->labelForAddress(sAddress); + if (sLabel.isEmpty()) sLabel = tr("(no label)"); itemOutput->setText(COLUMN_LABEL, sLabel); } @@ -766,7 +765,7 @@ void CoinControlDialog::updateView() // set checkbox if (coinControl->IsSelected(txhash, out.i)) - itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Checked); + itemOutput->setCheckState(COLUMN_CHECKBOX, Qt::Checked); } // amount diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index cacf5dc49..7c79b0efd 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -5,8 +5,12 @@ #include "splashscreen.h" #include "clientversion.h" +#include "init.h" #include "ui_interface.h" #include "util.h" +#ifdef ENABLE_WALLET +#include "wallet.h" +#endif #include <QApplication> #include <QPainter> @@ -109,14 +113,33 @@ static void InitMessage(SplashScreen *splash, const std::string &message) Q_ARG(QColor, QColor(55,55,55))); } +static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress) +{ + InitMessage(splash, title + strprintf("%d", nProgress) + "%"); +} + +#ifdef ENABLE_WALLET +static void ConnectWallet(SplashScreen *splash, CWallet* wallet) +{ + wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, _1, _2)); +} +#endif + void SplashScreen::subscribeToCoreSignals() { // Connect signals to client uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1)); +#ifdef ENABLE_WALLET + uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1)); +#endif } void SplashScreen::unsubscribeFromCoreSignals() { // Disconnect signals from client uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); +#ifdef ENABLE_WALLET + if(pwalletMain) + pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); +#endif } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index eae448fee..424c9ee27 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -419,8 +419,17 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, Q_ARG(int, status)); } +// queue notifications to show a non freezing progress dialog e.g. for rescan +static bool fQueueNotifications = false; +static std::vector<std::pair<uint256, ChangeType> > vQueueNotifications; static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, const uint256 &hash, ChangeType status) { + if (fQueueNotifications) + { + vQueueNotifications.push_back(make_pair(hash, status)); + return; + } + QString strHash = QString::fromStdString(hash.GetHex()); qDebug() << "NotifyTransactionChanged : " + strHash + " status= " + QString::number(status); @@ -429,12 +438,32 @@ static void NotifyTransactionChanged(WalletModel *walletmodel, CWallet *wallet, Q_ARG(int, status)); } +static void ShowProgress(WalletModel *walletmodel, const std::string &title, int nProgress) +{ + // emits signal "showProgress" + QMetaObject::invokeMethod(walletmodel, "showProgress", Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(title)), + Q_ARG(int, nProgress)); + + if (nProgress == 0) + fQueueNotifications = true; + + if (nProgress == 100) + { + fQueueNotifications = false; + BOOST_FOREACH(const PAIRTYPE(uint256, ChangeType)& notification, vQueueNotifications) + NotifyTransactionChanged(walletmodel, NULL, notification.first, notification.second); + std::vector<std::pair<uint256, ChangeType> >().swap(vQueueNotifications); // clear + } +} + void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); + wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); } void WalletModel::unsubscribeFromCoreSignals() @@ -443,6 +472,7 @@ void WalletModel::unsubscribeFromCoreSignals() wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); + wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); } // WalletModel::UnlockContext implementation diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 28a9169e2..ccf590aae 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -237,6 +237,9 @@ signals: // Coins sent: from wallet, to recipient, in (serialized) transaction: void coinsSent(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction); + // Show progress dialog e.g. for rescan + void showProgress(const QString &title, int nProgress); + public slots: /* Wallet status might have changed */ void updateStatus(); diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 1a9c7866d..1cef48344 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -24,6 +24,7 @@ #include <QActionGroup> #include <QFileDialog> #include <QHBoxLayout> +#include <QProgressDialog> #include <QPushButton> #include <QVBoxLayout> @@ -127,6 +128,9 @@ void WalletView::setWalletModel(WalletModel *walletModel) // Ask for passphrase if needed connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet())); + + // Show progress dialog + connect(walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int))); } } @@ -277,3 +281,26 @@ void WalletView::usedReceivingAddresses() dlg->setModel(walletModel->getAddressTableModel()); dlg->show(); } + +void WalletView::showProgress(const QString &title, int nProgress) +{ + if (nProgress == 0) + { + progressDialog = new QProgressDialog(title, "", 0, 100); + progressDialog->setWindowModality(Qt::ApplicationModal); + progressDialog->setMinimumDuration(0); + progressDialog->setCancelButton(0); + progressDialog->setAutoClose(false); + progressDialog->setValue(0); + } + else if (nProgress == 100) + { + if (progressDialog) + { + progressDialog->close(); + progressDialog->deleteLater(); + } + } + else if (progressDialog) + progressDialog->setValue(nProgress); +} diff --git a/src/qt/walletview.h b/src/qt/walletview.h index ecfa06ac5..9cfa8d676 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -18,6 +18,7 @@ class WalletModel; QT_BEGIN_NAMESPACE class QModelIndex; +class QProgressDialog; QT_END_NAMESPACE /* @@ -60,6 +61,8 @@ private: TransactionView *transactionView; + QProgressDialog *progressDialog; + public slots: /** Switch to overview (home) page */ void gotoOverviewPage(); @@ -97,6 +100,9 @@ public slots: /** Re-emit encryption status signal */ void updateEncryptionStatus(); + /** Show progress dialog e.g. for rescan */ + void showProgress(const QString &title, int nProgress); + signals: /** Signal that we want to show the main window */ void showNormalIfMinimized(); diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 41f2a57ec..9a24a99c1 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -212,6 +212,9 @@ Value importwallet(const Array& params, bool fHelp) while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200) pindex = pindex->pprev; + if (!pwalletMain->nTimeFirstKey || nTimeBegin < pwalletMain->nTimeFirstKey) + pwalletMain->nTimeFirstKey = nTimeBegin; + LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); pwalletMain->ScanForWalletTransactions(pindex); pwalletMain->MarkDirty(); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 564f0401f..070cf1cb2 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -204,6 +204,7 @@ Value setgenerate(const Array& params, bool fHelp) else // Not -regtest: start generate thread, return immediately { mapArgs["-gen"] = (fGenerate ? "1" : "0"); + mapArgs ["-genproclimit"] = itostr(nGenProcLimit); GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); } diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 3f8ad2002..8863ba400 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -12,7 +12,7 @@ BOOST_AUTO_TEST_SUITE(main_tests) BOOST_AUTO_TEST_CASE(subsidy_limit_test) { uint64_t nSum = 0; - for (int nHeight = 0; nHeight < 7000000; nHeight += 1000) { + for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) { uint64_t nSubsidy = GetBlockValue(nHeight, 0); BOOST_CHECK(nSubsidy <= 50 * COIN); nSum += nSubsidy * 1000; diff --git a/src/ui_interface.h b/src/ui_interface.h index 677d097fa..7b655ac95 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -91,6 +91,9 @@ public: * @note called with lock cs_mapAlerts held. */ boost::signals2::signal<void (const uint256 &hash, ChangeType status)> NotifyAlertChanged; + + /** A wallet has been loaded. */ + boost::signals2::signal<void (CWallet* wallet)> LoadWallet; }; extern CClientUIInterface uiInterface; diff --git a/src/wallet.cpp b/src/wallet.cpp index df1eb549a..775eb8f58 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -835,14 +835,19 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) CBlockIndex* pindex = pindexStart; { LOCK(cs_wallet); + + // no need to read and scan block, if block was created before + // our wallet birthday (as adjusted for block time variability) + while (pindex && nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) + pindex = chainActive.Next(pindex); + + ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup + double dProgressStart = Checkpoints::GuessVerificationProgress(pindex, false); + double dProgressTip = Checkpoints::GuessVerificationProgress(chainActive.Tip(), false); while (pindex) { - // no need to read and scan block, if block was created before - // our wallet birthday (as adjusted for block time variability) - if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) { - pindex = chainActive.Next(pindex); - continue; - } + if (pindex->nHeight % 100 == 0 && dProgressTip - dProgressStart > 0.0) + ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; ReadBlockFromDisk(block, pindex); @@ -857,6 +862,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(pindex)); } } + ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI } return ret; } @@ -1492,6 +1498,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) return nLoadWalletRet; fFirstRunRet = !vchDefaultKey.IsValid(); + uiInterface.LoadWallet(this); + return DB_LOAD_OK; } diff --git a/src/wallet.h b/src/wallet.h index ef02c90ed..5fd56d0af 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -391,6 +391,9 @@ public: */ boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged; + + /** Show progress e.g. for rescan */ + boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; }; /** A key allocated from the key pool. */ |