aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING1
-rw-r--r--Makefile.am1
-rw-r--r--doc/developer-notes.md20
-rw-r--r--doc/gitian-building.md482
-rw-r--r--doc/gitian-building/all_files_in_one_partition.pngbin3350 -> 0 bytes
-rw-r--r--doc/gitian-building/create_new_vm.pngbin119839 -> 0 bytes
-rw-r--r--doc/gitian-building/create_vm_file_location_size.pngbin111942 -> 0 bytes
-rw-r--r--doc/gitian-building/create_vm_hard_disk.pngbin123400 -> 0 bytes
-rw-r--r--doc/gitian-building/create_vm_hard_disk_file_type.pngbin170503 -> 0 bytes
-rw-r--r--doc/gitian-building/create_vm_memsize.pngbin22158 -> 0 bytes
-rw-r--r--doc/gitian-building/create_vm_storage_physical_hard_disk.pngbin181681 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_10_configure_clock.pngbin7892 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_11_partition_disks.pngbin9511 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_12_choose_disk.pngbin6613 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_14_finish.pngbin10794 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_15_write_changes.pngbin8790 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_16_choose_a_mirror.pngbin11134 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_18_proxy_settings.pngbin7582 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_19_software_selection.pngbin8767 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_1_boot_menu.pngbin110818 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_20_install_grub.pngbin9784 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_21_install_grub_bootloader.pngbin8878 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_22_finish_installation.pngbin6964 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_2_select_a_language.pngbin13131 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_3_select_location.pngbin10388 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_4_configure_keyboard.pngbin10224 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_5_configure_the_network.pngbin7612 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_6_domain_name.pngbin6526 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_6a_set_up_root_password.pngbin11876 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_7_set_up_user_fullname.pngbin8407 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_8_set_up_username.pngbin7058 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_install_9_user_password.pngbin6322 -> 0 bytes
-rw-r--r--doc/gitian-building/debian_root_login.pngbin7028 -> 0 bytes
-rw-r--r--doc/gitian-building/network_settings.pngbin72185 -> 0 bytes
-rw-r--r--doc/gitian-building/port_forwarding_rules.pngbin44052 -> 0 bytes
-rw-r--r--doc/gitian-building/select_startup_disk.pngbin72785 -> 0 bytes
-rw-r--r--doc/gitian-building/system_settings.pngbin76448 -> 0 bytes
-rw-r--r--src/bitcoin-cli.cpp119
-rw-r--r--src/bitcoin-tx.cpp8
-rw-r--r--src/init.cpp1
-rw-r--r--src/net.cpp64
-rw-r--r--src/netbase.cpp170
-rw-r--r--src/netbase.h5
-rw-r--r--src/qt/bitcoingui.cpp9
-rw-r--r--src/qt/guiutil.cpp26
-rw-r--r--src/qt/guiutil.h5
-rw-r--r--src/qt/rpcconsole.cpp11
-rw-r--r--src/qt/transactionview.cpp27
-rw-r--r--src/qt/transactionview.h4
-rw-r--r--src/rpc/blockchain.cpp3
-rw-r--r--src/rpc/mining.cpp15
-rw-r--r--src/rpc/net.cpp2
-rw-r--r--src/rpc/protocol.cpp21
-rw-r--r--src/rpc/protocol.h3
-rw-r--r--src/rpc/rawtransaction.cpp7
-rw-r--r--src/rpc/server.cpp7
-rw-r--r--src/rpc/server.h2
-rw-r--r--src/wallet/wallet.cpp9
-rw-r--r--src/wallet/walletdb.cpp4
-rwxr-xr-xtest/functional/bitcoin_cli.py23
-rwxr-xr-xtest/functional/blockchain.py31
-rwxr-xr-xtest/functional/deprecated_rpc.py23
-rwxr-xr-xtest/functional/p2p-versionbits-warning.py6
-rwxr-xr-xtest/functional/smartfees.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py5
-rwxr-xr-xtest/functional/test_runner.py1
-rw-r--r--test/util/data/bitcoin-util-test.json18
-rw-r--r--test/util/data/txcreatemultisig5.json26
68 files changed, 505 insertions, 656 deletions
diff --git a/COPYING b/COPYING
index c6203c0f76..45d51c3c78 100644
--- a/COPYING
+++ b/COPYING
@@ -1,6 +1,7 @@
The MIT License (MIT)
Copyright (c) 2009-2017 The Bitcoin Core developers
+Copyright (c) 2009-2017 Bitcoin Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile.am b/Makefile.am
index 8216b7d608..3b62a10603 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -249,6 +249,7 @@ EXTRA_DIST += \
test/util/data/txcreatemultisig3.json \
test/util/data/txcreatemultisig4.hex \
test/util/data/txcreatemultisig4.json \
+ test/util/data/txcreatemultisig5.json \
test/util/data/txcreateoutpubkey1.hex \
test/util/data/txcreateoutpubkey1.json \
test/util/data/txcreateoutpubkey2.hex \
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 8fdae25340..33c6ab9cb3 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -549,6 +549,26 @@ Git and GitHub tips
or `git fetch upstream-pull`. Afterwards, you can use `upstream-pull/NUMBER/head` in arguments to `git show`,
`git checkout` and anywhere a commit id would be acceptable to see the changes from pull request NUMBER.
+Scripted diffs
+--------------
+
+For reformatting and refactoring commits where the changes can be easily automated using a bash script, we use
+scripted-diff commits. The bash script is included in the commit message and our Travis CI job checks that
+the result of the script is identical to the commit. This aids reviewers since they can verify that the script
+does exactly what it's supposed to do. It is also helpful for rebasing (since the same script can just be re-run
+on the new master commit).
+
+To create a scripted-diff:
+
+- start the commit message with `scripted-diff:` (and then a description of the diff on the same line)
+- in the commit message include the bash script between lines containing just the following text:
+ - `-BEGIN VERIFY SCRIPT-`
+ - `-END VERIFY SCRIPT-`
+
+The scripted-diff is verified by the tool `contrib/devtools/commit-script-check.sh`
+
+Commit `bb81e173` is an example of a scripted-diff.
+
RPC interface guidelines
--------------------------
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index 636686b391..3a48f4a0b3 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -1,484 +1,4 @@
Gitian building
================
-*Setup instructions for a Gitian build of Bitcoin Core using a Debian VM or physical system.*
-
-Gitian is the deterministic build process that is used to build the Bitcoin
-Core executables. It provides a way to be reasonably sure that the
-executables are really built from the 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 this guide exists.
-It is preferred you follow these steps yourself instead of using someone else's
-VM image to avoid 'contaminating' the build.
-
-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 the Gitian image](#setting-up-the-gitian-image)
-- [Getting and building the inputs](#getting-and-building-the-inputs)
-- [Building Bitcoin Core](#building-bitcoin-core)
-- [Building an alternative repository](#building-an-alternative-repository)
-- [Signing externally](#signing-externally)
-- [Uploading signatures](#uploading-signatures)
-
-Preparing the Gitian builder host
----------------------------------
-
-The first step is to prepare the host environment that will be used to perform the Gitian builds.
-This guide explains how to set up the environment, and how to start the builds.
-
-Debian Linux was chosen as the host distribution because it has a lightweight install (in contrast to Ubuntu) and is readily available.
-Any kind of virtualization can be used, for example:
-- [VirtualBox](https://www.virtualbox.org/) (covered by this guide)
-- [KVM](http://www.linux-kvm.org/page/Main_Page)
-- [LXC](https://linuxcontainers.org/), see also [Gitian host docker container](https://github.com/gdm85/tenku/tree/master/docker/gitian-bitcoin-host/README.md).
-
-You can also install Gitian on actual hardware instead of using virtualization.
-
-Create a new VirtualBox VM
----------------------------
-In the VirtualBox GUI click "New" and choose the following parameters in the wizard:
-
-![](gitian-building/create_new_vm.png)
-
-- Type: Linux, Debian (64-bit)
-
-![](gitian-building/create_vm_memsize.png)
-
-- Memory Size: at least 3000MB, anything less and the build might not complete.
-
-![](gitian-building/create_vm_hard_disk.png)
-
-- Hard Disk: Create a virtual hard disk now
-
-![](gitian-building/create_vm_hard_disk_file_type.png)
-
-- Hard Disk file type: Use the default, VDI (VirtualBox Disk Image)
-
-![](gitian-building/create_vm_storage_physical_hard_disk.png)
-
-- Storage on physical hard disk: Dynamically Allocated
-
-![](gitian-building/create_vm_file_location_size.png)
-
-- File location and size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side
-- Click `Create`
-
-After creating the VM, we need to configure it.
-
-- Click the `Settings` button, then go to `System` tab and `Processor` sub-tab. Increase the number of processors to the number of cores on your machine if you want builds to be faster.
-
-![](gitian-building/system_settings.png)
-
-- Go to the `Network` tab. Adapter 1 should be attached to `NAT`.
-
-![](gitian-building/network_settings.png)
-
-- Click `Advanced`, then `Port Forwarding`. We want to set up a port through which we can reach the VM to get files in and out.
-- Create a new rule by clicking the plus icon.
-
-![](gitian-building/port_forwarding_rules.png)
-
-- 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.
-
-Get the [Debian 8.x net installer](http://cdimage.debian.org/mirror/cdimage/archive/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
-This DVD image can be [validated](https://www.debian.org/CD/verify) using a SHA256 hashing tool, for example on
-Unixy OSes by entering the following in a terminal:
-
- echo "ad4e8c27c561ad8248d5ebc1d36eb172f884057bfeb2c22ead823f59fa8c3dff debian-8.5.0-amd64-netinst.iso" | sha256sum -c
- # (must return OK)
-
-Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded ISO.
-
-![](gitian-building/select_startup_disk.png)
-
-Installing Debian
-------------------
-
-This section will explain 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.
-
-![](gitian-building/debian_install_1_boot_menu.png)
-
-**Note**: Navigating 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)
-
-![](gitian-building/debian_install_2_select_a_language.png)
-![](gitian-building/debian_install_3_select_location.png)
-![](gitian-building/debian_install_4_configure_keyboard.png)
-
-- The VM will detect network settings using DHCP, this should all proceed automatically
-- Configure the network:
- - Hostname `debian`.
- - Leave domain name empty.
-
-![](gitian-building/debian_install_5_configure_the_network.png)
-![](gitian-building/debian_install_6_domain_name.png)
-
-- Choose a root password and enter it twice (remember it for later)
-
-![](gitian-building/debian_install_6a_set_up_root_password.png)
-
-- Name the new user `debian` (the full name doesn't matter, you can leave it empty)
-- Set the account username as `debian`
-
-![](gitian-building/debian_install_7_set_up_user_fullname.png)
-![](gitian-building/debian_install_8_set_up_username.png)
-
-- Choose a user password and enter it twice (remember it for later)
-
-![](gitian-building/debian_install_9_user_password.png)
-
-- 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)
-
-![](gitian-building/debian_install_10_configure_clock.png)
-
-- Disk setup
- - Partitioning method: Guided - Use the entire disk
-
-![](gitian-building/debian_install_11_partition_disks.png)
-
- - Select disk to partition: SCSI1 (0,0,0)
-
-![](gitian-building/debian_install_12_choose_disk.png)
-
- - Partition Disks -> *All files in one partition*
-
-![](gitian-building/all_files_in_one_partition.png)
-
- - Finish partitioning and write changes to disk -> *Yes* (`Tab`, `Enter` to select the `Yes` button)
-
-![](gitian-building/debian_install_14_finish.png)
-![](gitian-building/debian_install_15_write_changes.png)
-
-- The base system will be installed, this will take a minute or so
-- Choose a mirror (any will do)
-
-![](gitian-building/debian_install_16_choose_a_mirror.png)
-
-- Enter proxy information (unless you are on an intranet, leave this empty)
-
-![](gitian-building/debian_install_18_proxy_settings.png)
-
-- 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'
-
-![](gitian-building/debian_install_19_software_selection.png)
-
-- Install the GRUB boot loader to the master boot record? -> Yes
-
-![](gitian-building/debian_install_20_install_grub.png)
-
-- Device for boot loader installation -> ata-VBOX_HARDDISK
-
-![](gitian-building/debian_install_21_install_grub_bootloader.png)
-
-- Installation Complete -> *Continue*
-- After installation, the VM will reboot and you will have a working Debian VM. Congratulations!
-
-![](gitian-building/debian_install_22_finish_installation.png)
-
-
-After Installation
--------------------
-The next step in the guide involves logging in as root via SSH.
-SSH login for root users is disabled by default, so we'll enable that now.
-
-Login to the VM using username `root` and the root password you chose earlier.
-You'll be presented with a screen similar to this.
-
-![](gitian-building/debian_root_login.png)
-
-Type:
-
-```
-sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
-```
-and press enter. Then,
-```
-/etc/init.d/ssh restart
-```
-and enter to restart SSH. Logout by typing 'logout' and pressing 'enter'.
-
-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](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html) and [WinSCP](http://winscp.net/eng/index.php).
-
-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.
- RSA key fingerprint is ae:f5:c8:9f:17:c6:c7:1b:c2:1b:12:31:1d:bb:d0:c7.
- Are you sure you want to continue connecting (yes/no)? yes
- Warning: Permanently added '[localhost]:22222' (RSA) to the list of known hosts.
- root@localhost's password: (enter root password configured during install)
-
- The programs included with the Debian GNU/Linux system are free software;
- the exact distribution terms for each program are described in the
- individual files in /usr/share/doc/*/copyright.
-
- Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
- permitted by applicable law.
- root@debian:~#
-
-Replace `root` with `debian` to log in as user.
-
-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 make ubuntu-archive-keyring curl
-adduser debian sudo
-```
-
-Then set up LXC and the rest with the following, which is a complex jumble of settings and workarounds:
-
-```bash
-# the version of lxc-start in Debian needs to run as root, so make sure
-# that the build script can execute it without providing a password
-echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-start" > /etc/sudoers.d/gitian-lxc
-echo "%sudo ALL=NOPASSWD: /usr/bin/lxc-execute" >> /etc/sudoers.d/gitian-lxc
-# 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 'iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE' >> /etc/rc.local
-echo 'echo 1 > /proc/sys/net/ipv4/ip_forward' >> /etc/rc.local
-echo 'exit 0' >> /etc/rc.local
-# make sure that USE_LXC is always set when logging in as debian,
-# and configure LXC IP addresses
-echo 'export USE_LXC=1' >> /home/debian/.profile
-echo 'export GITIAN_HOST_IP=10.0.3.2' >> /home/debian/.profile
-echo 'export LXC_GUEST_IP=10.0.3.5' >> /home/debian/.profile
-reboot
-```
-
-At the end the VM is rebooted to make sure that the changes take effect. The steps in this
-section only need to be performed once.
-
-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+bzr494.orig.tar.gz
-echo "76cbf8c52c391160b2641e7120dbade5afded713afaa6032f733a261f13e6a8e vm-builder_0.12.4+bzr494.orig.tar.gz" | sha256sum -c
-# (verification -- must return OK)
-tar -zxvf vm-builder_0.12.4+bzr494.orig.tar.gz
-cd vm-builder-0.12.4+bzr494
-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
-git clone https://github.com/bitcoin-core/gitian.sigs.git
-```
-
-Setting up the Gitian image
--------------------------
-
-Gitian needs a virtual image of the operating system to build in.
-Currently this is Ubuntu Trusty x86_64.
-This image will be copied and used every time that a build is started to
-make sure that the build is deterministic.
-Creating the image 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 amd64 --suite trusty
-```
-
-There will be a lot of warnings printed during the build of the image. 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
---------------------------------
-
-At this point you have two options, you can either use the automated script (found in [contrib/gitian-build.sh](/contrib/gitian-build.sh)) or you could manually do everything by following this guide. If you're using the automated script, then run it with the "--setup" command. Afterwards, run it with the "--build" command (example: "contrib/gitian-build.sh -b signer 0.13.0"). Otherwise ignore this.
-
-Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-create-inputs-first-time-or-when-dependency-versions-change)
-in the bitcoin repository under 'Fetch and create inputs' to install sources which require
-manual intervention. Also optionally follow the next step: 'Seed the Gitian sources cache
-and offline git repositories' which will fetch the remaining files required for building
-offline.
-
-Building Bitcoin Core
-----------------
-
-To build Bitcoin Core (for Linux, OS X and Windows) just follow the steps under 'perform
-Gitian builds' in [doc/release-process.md](release-process.md#perform-gitian-builds) in the bitcoin repository.
-
-This may take some time as it will build all the dependencies needed for each descriptor.
-These dependencies will be cached after a successful build to avoid rebuilding them when possible.
-
-At any time you can check the package installation and build progress with
-
-```bash
-tail -f var/install.log
-tail -f var/build.log
-```
-
-Output from `gbuild` will look something like
-
- Initialized empty Git repository in /home/debian/gitian-builder/inputs/bitcoin/.git/
- remote: Counting objects: 57959, done.
- remote: Total 57959 (delta 0), reused 0 (delta 0), pack-reused 57958
- Receiving objects: 100% (57959/57959), 53.76 MiB | 484.00 KiB/s, done.
- Resolving deltas: 100% (41590/41590), done.
- From https://github.com/bitcoin/bitcoin
- ... (new tags, new branch etc)
- --- Building for trusty amd64 ---
- 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)
-
-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
-./bin/gbuild --commit bitcoin=${COMMIT} --url bitcoin=${URL} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
-```
-
-Building fully offline
------------------------
-
-For building fully offline including attaching signatures to unsigned builds, the detached-sigs repository
-and the bitcoin git repository with the desired tag must both be available locally, and then gbuild must be
-told where to find them. It also requires an apt-cacher-ng which is fully-populated but set to offline mode, or
-manually disabling gitian-builder's use of apt-get to update the VM build environment.
-
-To configure apt-cacher-ng as an offline cacher, you will need to first populate its cache with the relevant
-files. You must additionally patch target-bin/bootstrap-fixup to set its apt sources to something other than
-plain archive.ubuntu.com: us.archive.ubuntu.com works.
-
-So, if you use LXC:
-
-```bash
-export PATH="$PATH":/path/to/gitian-builder/libexec
-export USE_LXC=1
-cd /path/to/gitian-builder
-./libexec/make-clean-vm --suite trusty --arch amd64
-
-LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root apt-get update
-LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root \
- -e DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -y install \
- $( sed -ne '/^packages:/,/[^-] .*/ {/^- .*/{s/"//g;s/- //;p}}' ../bitcoin/contrib/gitian-descriptors/*|sort|uniq )
-LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root apt-get -q -y purge grub
-LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root -e DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade
-```
-
-And then set offline mode for apt-cacher-ng:
-
-```
-/etc/apt-cacher-ng/acng.conf
-[...]
-Offlinemode: 1
-[...]
-
-service apt-cacher-ng restart
-```
-
-Then when building, override the remote URLs that gbuild would otherwise pull from the Gitian descriptors::
-```bash
-
-cd /some/root/path/
-git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git
-
-BTCPATH=/some/root/path/bitcoin
-SIGPATH=/some/root/path/bitcoin-detached-sigs
-
-./bin/gbuild --url bitcoin=${BTCPATH},signature=${SIGPATH} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
-```
-
-Signing externally
--------------------
-
-If you want to do the PGP signing on another device, that's also possible; just define `SIGNER` as mentioned
-and follow the steps in the build process as normal.
-
- 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}-linux/${SIGNER}/bitcoin-linux-build.assert
- gpg --detach-sign ${VERSION}-win/${SIGNER}/bitcoin-win-build.assert
- gpg --detach-sign ${VERSION}-osx-unsigned/${SIGNER}/bitcoin-osx-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-core/gitian.sigs](https://github.com/bitcoin-core/gitian.sigs/) repository, or if that's not possible create a pull
-request. You can also mail the files to Wladimir (laanwj@gmail.com) and he will commit them.
+This file was moved to [the Bitcoin Core documentation repository](https://github.com/bitcoin-core/docs/blob/master/gitian-building.md) at [https://github.com/bitcoin-core/docs](https://github.com/bitcoin-core/docs).
diff --git a/doc/gitian-building/all_files_in_one_partition.png b/doc/gitian-building/all_files_in_one_partition.png
deleted file mode 100644
index 8cbb0d8adc..0000000000
--- a/doc/gitian-building/all_files_in_one_partition.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/create_new_vm.png b/doc/gitian-building/create_new_vm.png
deleted file mode 100644
index dd22428e17..0000000000
--- a/doc/gitian-building/create_new_vm.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/create_vm_file_location_size.png b/doc/gitian-building/create_vm_file_location_size.png
deleted file mode 100644
index 5f77206b6f..0000000000
--- a/doc/gitian-building/create_vm_file_location_size.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/create_vm_hard_disk.png b/doc/gitian-building/create_vm_hard_disk.png
deleted file mode 100644
index 8e29816fab..0000000000
--- a/doc/gitian-building/create_vm_hard_disk.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/create_vm_hard_disk_file_type.png b/doc/gitian-building/create_vm_hard_disk_file_type.png
deleted file mode 100644
index a157211cf5..0000000000
--- a/doc/gitian-building/create_vm_hard_disk_file_type.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/create_vm_memsize.png b/doc/gitian-building/create_vm_memsize.png
deleted file mode 100644
index 6f42cda73f..0000000000
--- a/doc/gitian-building/create_vm_memsize.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/create_vm_storage_physical_hard_disk.png b/doc/gitian-building/create_vm_storage_physical_hard_disk.png
deleted file mode 100644
index cee16a6c63..0000000000
--- a/doc/gitian-building/create_vm_storage_physical_hard_disk.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_10_configure_clock.png b/doc/gitian-building/debian_install_10_configure_clock.png
deleted file mode 100644
index 7cda038ae4..0000000000
--- a/doc/gitian-building/debian_install_10_configure_clock.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_11_partition_disks.png b/doc/gitian-building/debian_install_11_partition_disks.png
deleted file mode 100644
index 2a648c517f..0000000000
--- a/doc/gitian-building/debian_install_11_partition_disks.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_12_choose_disk.png b/doc/gitian-building/debian_install_12_choose_disk.png
deleted file mode 100644
index 0f3acc498e..0000000000
--- a/doc/gitian-building/debian_install_12_choose_disk.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_14_finish.png b/doc/gitian-building/debian_install_14_finish.png
deleted file mode 100644
index c8ef0b37ad..0000000000
--- a/doc/gitian-building/debian_install_14_finish.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_15_write_changes.png b/doc/gitian-building/debian_install_15_write_changes.png
deleted file mode 100644
index d8de00dec6..0000000000
--- a/doc/gitian-building/debian_install_15_write_changes.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_16_choose_a_mirror.png b/doc/gitian-building/debian_install_16_choose_a_mirror.png
deleted file mode 100644
index 0bd985b38c..0000000000
--- a/doc/gitian-building/debian_install_16_choose_a_mirror.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_18_proxy_settings.png b/doc/gitian-building/debian_install_18_proxy_settings.png
deleted file mode 100644
index 2c19919f64..0000000000
--- a/doc/gitian-building/debian_install_18_proxy_settings.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_19_software_selection.png b/doc/gitian-building/debian_install_19_software_selection.png
deleted file mode 100644
index 5430456b14..0000000000
--- a/doc/gitian-building/debian_install_19_software_selection.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_1_boot_menu.png b/doc/gitian-building/debian_install_1_boot_menu.png
deleted file mode 100644
index 216502e1c6..0000000000
--- a/doc/gitian-building/debian_install_1_boot_menu.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_20_install_grub.png b/doc/gitian-building/debian_install_20_install_grub.png
deleted file mode 100644
index d853c15871..0000000000
--- a/doc/gitian-building/debian_install_20_install_grub.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_21_install_grub_bootloader.png b/doc/gitian-building/debian_install_21_install_grub_bootloader.png
deleted file mode 100644
index 493ab806a6..0000000000
--- a/doc/gitian-building/debian_install_21_install_grub_bootloader.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_22_finish_installation.png b/doc/gitian-building/debian_install_22_finish_installation.png
deleted file mode 100644
index 7c4445585b..0000000000
--- a/doc/gitian-building/debian_install_22_finish_installation.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_2_select_a_language.png b/doc/gitian-building/debian_install_2_select_a_language.png
deleted file mode 100644
index 0228ae2c01..0000000000
--- a/doc/gitian-building/debian_install_2_select_a_language.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_3_select_location.png b/doc/gitian-building/debian_install_3_select_location.png
deleted file mode 100644
index 7b18fba975..0000000000
--- a/doc/gitian-building/debian_install_3_select_location.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_4_configure_keyboard.png b/doc/gitian-building/debian_install_4_configure_keyboard.png
deleted file mode 100644
index 8e46117de4..0000000000
--- a/doc/gitian-building/debian_install_4_configure_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_5_configure_the_network.png b/doc/gitian-building/debian_install_5_configure_the_network.png
deleted file mode 100644
index 8e3720f243..0000000000
--- a/doc/gitian-building/debian_install_5_configure_the_network.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_6_domain_name.png b/doc/gitian-building/debian_install_6_domain_name.png
deleted file mode 100644
index 7a986d92f4..0000000000
--- a/doc/gitian-building/debian_install_6_domain_name.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index dcade11967..0000000000
--- a/doc/gitian-building/debian_install_6a_set_up_root_password.png
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index 6763c6e08a..0000000000
--- a/doc/gitian-building/debian_install_7_set_up_user_fullname.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_8_set_up_username.png b/doc/gitian-building/debian_install_8_set_up_username.png
deleted file mode 100644
index bb04de96d2..0000000000
--- a/doc/gitian-building/debian_install_8_set_up_username.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_install_9_user_password.png b/doc/gitian-building/debian_install_9_user_password.png
deleted file mode 100644
index 981f1181d7..0000000000
--- a/doc/gitian-building/debian_install_9_user_password.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/debian_root_login.png b/doc/gitian-building/debian_root_login.png
deleted file mode 100644
index 14cdd5ba5b..0000000000
--- a/doc/gitian-building/debian_root_login.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/network_settings.png b/doc/gitian-building/network_settings.png
deleted file mode 100644
index 9e714fd154..0000000000
--- a/doc/gitian-building/network_settings.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/port_forwarding_rules.png b/doc/gitian-building/port_forwarding_rules.png
deleted file mode 100644
index 9e1fa2af20..0000000000
--- a/doc/gitian-building/port_forwarding_rules.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/select_startup_disk.png b/doc/gitian-building/select_startup_disk.png
deleted file mode 100644
index 59bc093e2c..0000000000
--- a/doc/gitian-building/select_startup_disk.png
+++ /dev/null
Binary files differ
diff --git a/doc/gitian-building/system_settings.png b/doc/gitian-building/system_settings.png
deleted file mode 100644
index a5720ef3a3..0000000000
--- a/doc/gitian-building/system_settings.png
+++ /dev/null
Binary files differ
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 3c94c99b3e..e21a269221 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -37,6 +37,7 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
+ strUsage += HelpMessageOpt("-getinfo", _("Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)"));
AppendParamsHelpMessages(strUsage);
strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED));
strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
@@ -191,7 +192,96 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
-static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
+/** Class that handles the conversion from a command-line to a JSON-RPC request,
+ * as well as converting back to a JSON object that can be shown as result.
+ */
+class BaseRequestHandler
+{
+public:
+ virtual UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) = 0;
+ virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
+};
+
+/** Process getinfo requests */
+class GetinfoRequestHandler: public BaseRequestHandler
+{
+public:
+ const int ID_NETWORKINFO = 0;
+ const int ID_BLOCKCHAININFO = 1;
+ const int ID_WALLETINFO = 2;
+
+ /** Create a simulated `getinfo` request. */
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ UniValue result(UniValue::VARR);
+ result.push_back(JSONRPCRequestObj("getnetworkinfo", NullUniValue, ID_NETWORKINFO));
+ result.push_back(JSONRPCRequestObj("getblockchaininfo", NullUniValue, ID_BLOCKCHAININFO));
+ result.push_back(JSONRPCRequestObj("getwalletinfo", NullUniValue, ID_WALLETINFO));
+ return result;
+ }
+
+ /** Collect values from the batch and form a simulated `getinfo` reply. */
+ UniValue ProcessReply(const UniValue &batch_in) override
+ {
+ UniValue result(UniValue::VOBJ);
+ std::vector<UniValue> batch = JSONRPCProcessBatchReply(batch_in, 3);
+ // Errors in getnetworkinfo() and getblockchaininfo() are fatal, pass them on
+ // getwalletinfo() is allowed to fail in case there is no wallet.
+ if (!batch[ID_NETWORKINFO]["error"].isNull()) {
+ return batch[ID_NETWORKINFO];
+ }
+ if (!batch[ID_BLOCKCHAININFO]["error"].isNull()) {
+ return batch[ID_BLOCKCHAININFO];
+ }
+ result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
+ result.pushKV("protocolversion", batch[ID_NETWORKINFO]["result"]["protocolversion"]);
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ }
+ result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
+ result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
+ result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
+ result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
+ result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
+ result.pushKV("testnet", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"].get_str() == "test"));
+ if (!batch[ID_WALLETINFO].isNull()) {
+ result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
+ result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
+ result.pushKV("keypoololdest", batch[ID_WALLETINFO]["result"]["keypoololdest"]);
+ result.pushKV("keypoolsize", batch[ID_WALLETINFO]["result"]["keypoolsize"]);
+ if (!batch[ID_WALLETINFO]["result"]["unlocked_until"].isNull()) {
+ result.pushKV("unlocked_until", batch[ID_WALLETINFO]["result"]["unlocked_until"]);
+ }
+ result.pushKV("paytxfee", batch[ID_WALLETINFO]["result"]["paytxfee"]);
+ }
+ result.pushKV("relayfee", batch[ID_NETWORKINFO]["result"]["relayfee"]);
+ result.pushKV("warnings", batch[ID_NETWORKINFO]["result"]["warnings"]);
+ return JSONRPCReplyObj(result, NullUniValue, 1);
+ }
+};
+
+/** Process default single requests */
+class DefaultRequestHandler: public BaseRequestHandler {
+public:
+ UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
+ {
+ UniValue params;
+ if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
+ params = RPCConvertNamedValues(method, args);
+ } else {
+ params = RPCConvertValues(method, args);
+ }
+ return JSONRPCRequestObj(method, params, 1);
+ }
+
+ UniValue ProcessReply(const UniValue &reply) override
+ {
+ return reply.get_obj();
+ }
+};
+
+static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, const std::vector<std::string>& args)
{
std::string host;
// In preference order, we choose the following for the port:
@@ -238,7 +328,7 @@ static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
// Attach request data
- std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
+ std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
@@ -277,7 +367,7 @@ static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body))
throw std::runtime_error("couldn't parse reply from server");
- const UniValue& reply = valReply.get_obj();
+ const UniValue reply = rh->ProcessReply(valReply);
if (reply.empty())
throw std::runtime_error("expected reply to have result, error and id properties");
@@ -309,24 +399,25 @@ int CommandLineRPC(int argc, char *argv[])
args.push_back(line);
}
}
- if (args.size() < 1) {
- throw std::runtime_error("too few parameters (need at least command)");
- }
- std::string strMethod = args[0];
- args.erase(args.begin()); // Remove trailing method name from arguments vector
-
- UniValue params;
- if(gArgs.GetBoolArg("-named", DEFAULT_NAMED)) {
- params = RPCConvertNamedValues(strMethod, args);
+ std::unique_ptr<BaseRequestHandler> rh;
+ std::string method;
+ if (gArgs.GetBoolArg("-getinfo", false)) {
+ rh.reset(new GetinfoRequestHandler());
+ method = "";
} else {
- params = RPCConvertValues(strMethod, args);
+ rh.reset(new DefaultRequestHandler());
+ if (args.size() < 1) {
+ throw std::runtime_error("too few parameters (need at least command)");
+ }
+ method = args[0];
+ args.erase(args.begin()); // Remove trailing method name from arguments vector
}
// Execute and handle connection failures with -rpcwait
const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
do {
try {
- const UniValue reply = CallRPC(strMethod, params);
+ const UniValue reply = CallRPC(rh.get(), method, args);
// Parse reply
const UniValue& result = find_value(reply, "result");
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index d8d7934bf6..e4f44435ba 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -310,6 +310,9 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
}
if (bSegWit) {
+ if (!pubkey.IsCompressed()) {
+ throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
+ }
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
@@ -375,6 +378,11 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
if (bSegWit) {
+ for (CPubKey& pubkey : pubkeys) {
+ if (!pubkey.IsCompressed()) {
+ throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
+ }
+ }
// Call GetScriptForWitness() to build a P2WSH scriptPubKey
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
diff --git a/src/init.cpp b/src/init.cpp
index e80170b24d..55670c7dc6 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -430,6 +430,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u)", defaultChainParams->DefaultConsistencyChecks()));
strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED));
strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", DEFAULT_DISABLE_SAFEMODE));
+ strUsage += HelpMessageOpt("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used");
strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", DEFAULT_TESTSAFEMODE));
strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
diff --git a/src/net.cpp b/src/net.cpp
index c3f16a8f1f..ea3840a708 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -385,19 +385,16 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
pszDest ? pszDest : addrConnect.ToString(),
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0);
- // Connect
- SOCKET hSocket;
- bool proxyConnectionFailed = false;
- if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :
- ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed))
- {
- if (!IsSelectableSocket(hSocket)) {
- LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
- CloseSocket(hSocket);
- return nullptr;
- }
-
- if (pszDest && addrConnect.IsValid()) {
+ // Resolve
+ const int default_port = Params().GetDefaultPort();
+ if (pszDest) {
+ std::vector<CService> resolved;
+ if (Lookup(pszDest, resolved, default_port, fNameLookup && !HaveNameProxy(), 256) && !resolved.empty()) {
+ addrConnect = CAddress(resolved[GetRand(resolved.size())], NODE_NONE);
+ if (!addrConnect.IsValid()) {
+ LogPrint(BCLog::NET, "Resolver returned invalid address %s for %s", addrConnect.ToString(), pszDest);
+ return nullptr;
+ }
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created, and return the existing CNode instead.
// Also store the name we used to connect in that CNode, so that future FindNode() calls to that
@@ -407,13 +404,40 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (pnode)
{
pnode->MaybeSetAddrName(std::string(pszDest));
- CloseSocket(hSocket);
LogPrintf("Failed to open new connection, already connected\n");
return nullptr;
}
}
+ }
- addrman.Attempt(addrConnect, fCountFailure);
+ // Connect
+ bool connected = false;
+ SOCKET hSocket;
+ proxyType proxy;
+ if (addrConnect.IsValid()) {
+ bool proxyConnectionFailed = false;
+
+ if (GetProxy(addrConnect.GetNetwork(), proxy))
+ connected = ConnectThroughProxy(proxy, addrConnect.ToStringIP(), addrConnect.GetPort(), hSocket, nConnectTimeout, &proxyConnectionFailed);
+ else // no proxy needed (none set for target network)
+ connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout);
+ if (!proxyConnectionFailed) {
+ // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
+ // the proxy, mark this as an attempt.
+ addrman.Attempt(addrConnect, fCountFailure);
+ }
+ } else if (pszDest && GetNameProxy(proxy)) {
+ std::string host;
+ int port = default_port;
+ SplitHostPort(std::string(pszDest), port, host);
+ connected = ConnectThroughProxy(proxy, host, port, hSocket, nConnectTimeout, nullptr);
+ }
+ if (connected) {
+ if (!IsSelectableSocket(hSocket)) {
+ LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
+ CloseSocket(hSocket);
+ return nullptr;
+ }
// Add node
NodeId id = GetNewNodeId();
@@ -424,10 +448,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
pnode->AddRef();
return pnode;
- } else if (!proxyConnectionFailed) {
- // If connecting to the node failed, and failure is not caused by a problem connecting to
- // the proxy, mark this as an attempt.
- addrman.Attempt(addrConnect, fCountFailure);
}
return nullptr;
@@ -1912,11 +1932,9 @@ void CConnman::ThreadOpenAddedConnections()
// the addednodeinfo state might change.
break;
}
- // If strAddedNode is an IP/port, decode it immediately, so
- // OpenNetworkConnection can detect existing connections to that IP/port.
tried = true;
- CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort()));
- OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true);
+ CAddress addr(CService(), NODE_NONE);
+ OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), false, false, true);
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
return;
}
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 05f9f6961c..5a560bc95a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -184,6 +184,48 @@ struct timeval MillisToTimeval(int64_t nTimeout)
return timeout;
}
+/** SOCKS version */
+enum SOCKSVersion: uint8_t {
+ SOCKS4 = 0x04,
+ SOCKS5 = 0x05
+};
+
+/** Values defined for METHOD in RFC1928 */
+enum SOCKS5Method: uint8_t {
+ NOAUTH = 0x00, //! No authentication required
+ GSSAPI = 0x01, //! GSSAPI
+ USER_PASS = 0x02, //! Username/password
+ NO_ACCEPTABLE = 0xff, //! No acceptable methods
+};
+
+/** Values defined for CMD in RFC1928 */
+enum SOCKS5Command: uint8_t {
+ CONNECT = 0x01,
+ BIND = 0x02,
+ UDP_ASSOCIATE = 0x03
+};
+
+/** Values defined for REP in RFC1928 */
+enum SOCKS5Reply: uint8_t {
+ SUCCEEDED = 0x00, //! Succeeded
+ GENFAILURE = 0x01, //! General failure
+ NOTALLOWED = 0x02, //! Connection not allowed by ruleset
+ NETUNREACHABLE = 0x03, //! Network unreachable
+ HOSTUNREACHABLE = 0x04, //! Network unreachable
+ CONNREFUSED = 0x05, //! Connection refused
+ TTLEXPIRED = 0x06, //! TTL expired
+ CMDUNSUPPORTED = 0x07, //! Command not supported
+ ATYPEUNSUPPORTED = 0x08, //! Address type not supported
+};
+
+/** Values defined for ATYPE in RFC1928 */
+enum SOCKS5Atyp: uint8_t {
+ IPV4 = 0x01,
+ DOMAINNAME = 0x03,
+ IPV6 = 0x04,
+};
+
+/** Status codes that can be returned by InterruptibleRecv */
enum class IntrRecvError {
OK,
Timeout,
@@ -203,7 +245,7 @@ enum class IntrRecvError {
*
* @note This function requires that hSocket is in non-blocking mode.
*/
-static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, const SOCKET& hSocket)
+static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const SOCKET& hSocket)
{
int64_t curTime = GetTimeMillis();
int64_t endTime = curTime + timeout;
@@ -211,7 +253,7 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons
// to break off in case of an interruption.
const int64_t maxWait = 1000;
while (len > 0 && curTime < endTime) {
- ssize_t ret = recv(hSocket, data, len, 0); // Optimistically try the recv first
+ ssize_t ret = recv(hSocket, (char*)data, len, 0); // Optimistically try the recv first
if (ret > 0) {
len -= ret;
data += ret;
@@ -242,24 +284,35 @@ static IntrRecvError InterruptibleRecv(char* data, size_t len, int timeout, cons
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
}
+/** Credentials for proxy authentication */
struct ProxyCredentials
{
std::string username;
std::string password;
};
-std::string Socks5ErrorString(int err)
+/** Convert SOCKS5 reply to a an error message */
+std::string Socks5ErrorString(uint8_t err)
{
switch(err) {
- case 0x01: return "general failure";
- case 0x02: return "connection not allowed";
- case 0x03: return "network unreachable";
- case 0x04: return "host unreachable";
- case 0x05: return "connection refused";
- case 0x06: return "TTL expired";
- case 0x07: return "protocol error";
- case 0x08: return "address type not supported";
- default: return "unknown";
+ case SOCKS5Reply::GENFAILURE:
+ return "general failure";
+ case SOCKS5Reply::NOTALLOWED:
+ return "connection not allowed";
+ case SOCKS5Reply::NETUNREACHABLE:
+ return "network unreachable";
+ case SOCKS5Reply::HOSTUNREACHABLE:
+ return "host unreachable";
+ case SOCKS5Reply::CONNREFUSED:
+ return "connection refused";
+ case SOCKS5Reply::TTLEXPIRED:
+ return "TTL expired";
+ case SOCKS5Reply::CMDUNSUPPORTED:
+ return "protocol error";
+ case SOCKS5Reply::ATYPEUNSUPPORTED:
+ return "address type not supported";
+ default:
+ return "unknown";
}
}
@@ -274,34 +327,34 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
}
// Accepted authentication methods
std::vector<uint8_t> vSocks5Init;
- vSocks5Init.push_back(0x05);
+ vSocks5Init.push_back(SOCKSVersion::SOCKS5);
if (auth) {
- vSocks5Init.push_back(0x02); // # METHODS
- vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
- vSocks5Init.push_back(0x02); // X'02' USERNAME/PASSWORD (RFC1929)
+ vSocks5Init.push_back(0x02); // Number of methods
+ vSocks5Init.push_back(SOCKS5Method::NOAUTH);
+ vSocks5Init.push_back(SOCKS5Method::USER_PASS);
} else {
- vSocks5Init.push_back(0x01); // # METHODS
- vSocks5Init.push_back(0x00); // X'00' NO AUTHENTICATION REQUIRED
+ vSocks5Init.push_back(0x01); // Number of methods
+ vSocks5Init.push_back(SOCKS5Method::NOAUTH);
}
ssize_t ret = send(hSocket, (const char*)vSocks5Init.data(), vSocks5Init.size(), MSG_NOSIGNAL);
if (ret != (ssize_t)vSocks5Init.size()) {
CloseSocket(hSocket);
return error("Error sending to proxy");
}
- char pchRet1[2];
+ uint8_t pchRet1[2];
if ((recvr = InterruptibleRecv(pchRet1, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n", strDest, port);
return false;
}
- if (pchRet1[0] != 0x05) {
+ if (pchRet1[0] != SOCKSVersion::SOCKS5) {
CloseSocket(hSocket);
return error("Proxy failed to initialize");
}
- if (pchRet1[1] == 0x02 && auth) {
+ if (pchRet1[1] == SOCKS5Method::USER_PASS && auth) {
// Perform username/password authentication (as described in RFC1929)
std::vector<uint8_t> vAuth;
- vAuth.push_back(0x01);
+ vAuth.push_back(0x01); // Current (and only) version of user/pass subnegotiation
if (auth->username.size() > 255 || auth->password.size() > 255)
return error("Proxy username or password too long");
vAuth.push_back(auth->username.size());
@@ -314,7 +367,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error sending authentication to proxy");
}
LogPrint(BCLog::PROXY, "SOCKS5 sending proxy authentication %s:%s\n", auth->username, auth->password);
- char pchRetA[2];
+ uint8_t pchRetA[2];
if ((recvr = InterruptibleRecv(pchRetA, 2, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
return error("Error reading proxy authentication response");
@@ -323,17 +376,17 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Proxy authentication unsuccessful");
}
- } else if (pchRet1[1] == 0x00) {
+ } else if (pchRet1[1] == SOCKS5Method::NOAUTH) {
// Perform no authentication
} else {
CloseSocket(hSocket);
return error("Proxy requested wrong authentication method %02x", pchRet1[1]);
}
std::vector<uint8_t> vSocks5;
- vSocks5.push_back(0x05); // VER protocol version
- vSocks5.push_back(0x01); // CMD CONNECT
- vSocks5.push_back(0x00); // RSV Reserved
- vSocks5.push_back(0x03); // ATYP DOMAINNAME
+ vSocks5.push_back(SOCKSVersion::SOCKS5); // VER protocol version
+ vSocks5.push_back(SOCKS5Command::CONNECT); // CMD CONNECT
+ vSocks5.push_back(0x00); // RSV Reserved must be 0
+ vSocks5.push_back(SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
vSocks5.push_back(strDest.size()); // Length<=255 is checked at beginning of function
vSocks5.insert(vSocks5.end(), strDest.begin(), strDest.end());
vSocks5.push_back((port >> 8) & 0xFF);
@@ -343,7 +396,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
CloseSocket(hSocket);
return error("Error sending to proxy");
}
- char pchRet2[4];
+ uint8_t pchRet2[4];
if ((recvr = InterruptibleRecv(pchRet2, 4, SOCKS5_RECV_TIMEOUT, hSocket)) != IntrRecvError::OK) {
CloseSocket(hSocket);
if (recvr == IntrRecvError::Timeout) {
@@ -355,26 +408,26 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return error("Error while reading proxy response");
}
}
- if (pchRet2[0] != 0x05) {
+ if (pchRet2[0] != SOCKSVersion::SOCKS5) {
CloseSocket(hSocket);
return error("Proxy failed to accept request");
}
- if (pchRet2[1] != 0x00) {
+ if (pchRet2[1] != SOCKS5Reply::SUCCEEDED) {
// Failures to connect to a peer that are not proxy errors
CloseSocket(hSocket);
LogPrintf("Socks5() connect to %s:%d failed: %s\n", strDest, port, Socks5ErrorString(pchRet2[1]));
return false;
}
- if (pchRet2[2] != 0x00) {
+ if (pchRet2[2] != 0x00) { // Reserved field must be 0
CloseSocket(hSocket);
return error("Error: malformed proxy response");
}
- char pchRet3[256];
+ uint8_t pchRet3[256];
switch (pchRet2[3])
{
- case 0x01: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case 0x04: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
- case 0x03:
+ case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv(pchRet3, 4, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv(pchRet3, 16, SOCKS5_RECV_TIMEOUT, hSocket); break;
+ case SOCKS5Atyp::DOMAINNAME:
{
recvr = InterruptibleRecv(pchRet3, 1, SOCKS5_RECV_TIMEOUT, hSocket);
if (recvr != IntrRecvError::OK) {
@@ -399,7 +452,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
return true;
}
-bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
+bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout)
{
hSocketRet = INVALID_SOCKET;
@@ -534,7 +587,7 @@ bool IsProxy(const CNetAddr &addr) {
return false;
}
-static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
{
SOCKET hSocket = INVALID_SOCKET;
// first connect to proxy server
@@ -558,47 +611,6 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
hSocketRet = hSocket;
return true;
}
-
-bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
-{
- proxyType proxy;
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
-
- if (GetProxy(addrDest.GetNetwork(), proxy))
- return ConnectThroughProxy(proxy, addrDest.ToStringIP(), addrDest.GetPort(), hSocketRet, nTimeout, outProxyConnectionFailed);
- else // no proxy needed (none set for target network)
- return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
-}
-
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
-{
- std::string strDest;
- int port = portDefault;
-
- if (outProxyConnectionFailed)
- *outProxyConnectionFailed = false;
-
- SplitHostPort(std::string(pszDest), port, strDest);
-
- proxyType proxy;
- GetNameProxy(proxy);
-
- std::vector<CService> addrResolved;
- if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
- if (addrResolved.size() > 0) {
- addr = addrResolved[GetRand(addrResolved.size())];
- return ConnectSocket(addr, hSocketRet, nTimeout);
- }
- }
-
- addr = CService();
-
- if (!HaveNameProxy())
- return false;
- return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
-}
-
bool LookupSubNet(const char* pszName, CSubNet& ret)
{
std::string strSubnet(pszName);
diff --git a/src/netbase.h b/src/netbase.h
index 6572f0a12e..e7d7bcb375 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -44,14 +44,15 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(const proxyType &addrProxy);
bool HaveNameProxy();
+bool GetNameProxy(proxyType &nameProxyOut);
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup);
bool LookupHost(const char *pszName, CNetAddr& addr, bool fAllowLookup);
bool Lookup(const char *pszName, CService& addr, int portDefault, bool fAllowLookup);
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault, bool fAllowLookup, unsigned int nMaxSolutions);
CService LookupNumeric(const char *pszName, int portDefault = 0);
bool LookupSubNet(const char *pszName, CSubNet& subnet);
-bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed = nullptr);
-bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed = nullptr);
+bool ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRet, int nTimeout);
+bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDest, int port, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed);
/** Return readable error string for a network error code */
std::string NetworkErrorString(int err);
/** Close socket and set hSocket to INVALID_SOCKET */
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index be2d21daee..dc55141900 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -123,7 +123,11 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *
spinnerFrame(0),
platformStyle(_platformStyle)
{
- GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
+ QSettings settings;
+ if (!restoreGeometry(settings.value("MainWindowGeometry").toByteArray())) {
+ // Restore failed (perhaps missing setting), center the window
+ move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ }
QString windowTitle = tr(PACKAGE_NAME) + " - ";
#ifdef ENABLE_WALLET
@@ -261,7 +265,8 @@ BitcoinGUI::~BitcoinGUI()
// Unsubscribe from notifications from core
unsubscribeFromCoreSignals();
- GUIUtil::saveWindowGeometry("nWindow", this);
+ QSettings settings;
+ settings.setValue("MainWindowGeometry", saveGeometry());
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon->hide();
#ifdef Q_OS_MAC
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index c3f98f764b..b916df69aa 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -862,32 +862,6 @@ bool SetStartOnSystemStartup(bool fAutoStart) { return false; }
#endif
-void saveWindowGeometry(const QString& strSetting, QWidget *parent)
-{
- QSettings settings;
- settings.setValue(strSetting + "Pos", parent->pos());
- settings.setValue(strSetting + "Size", parent->size());
-}
-
-void restoreWindowGeometry(const QString& strSetting, const QSize& defaultSize, QWidget *parent)
-{
- QSettings settings;
- QPoint pos = settings.value(strSetting + "Pos").toPoint();
- QSize size = settings.value(strSetting + "Size", defaultSize).toSize();
-
- parent->resize(size);
- parent->move(pos);
-
- if ((!pos.x() && !pos.y()) || (QApplication::desktop()->screenNumber(parent) == -1))
- {
- QRect screen = QApplication::desktop()->screenGeometry();
- QPoint defaultPos((screen.width() - defaultSize.width()) / 2,
- (screen.height() - defaultSize.height()) / 2);
- parent->resize(defaultSize);
- parent->move(defaultPos);
- }
-}
-
void setClipboard(const QString& str)
{
QApplication::clipboard()->setText(str, QClipboard::Clipboard);
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index d6aa8c4ea6..d10818d0c8 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -179,11 +179,6 @@ namespace GUIUtil
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);
- /** Save window size and position */
- void saveWindowGeometry(const QString& strSetting, QWidget *parent);
- /** Restore window size and position */
- void restoreWindowGeometry(const QString& strSetting, const QSize &defaultSizeIn, QWidget *parent);
-
/* Convert QString to OS specific boost path through UTF-8 */
fs::path qstringToBoostPath(const QString &path);
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 3590a98efa..d895fc1663 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -28,6 +28,7 @@
#include <wallet/wallet.h>
#endif
+#include <QDesktopWidget>
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
@@ -428,7 +429,11 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
consoleFontSize(0)
{
ui->setupUi(this);
- GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
+ QSettings settings;
+ if (!restoreGeometry(settings.value("RPCConsoleWindowGeometry").toByteArray())) {
+ // Restore failed (perhaps missing setting), center the window
+ move(QApplication::desktop()->availableGeometry().center() - frameGeometry().center());
+ }
ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(tr(PACKAGE_NAME)));
@@ -466,14 +471,14 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
- QSettings settings;
consoleFontSize = settings.value(fontSizeSettingsKey, QFontInfo(QFont()).pointSize()).toInt();
clear();
}
RPCConsole::~RPCConsole()
{
- GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
+ QSettings settings;
+ settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 53c38da9db..39dfdb587c 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -33,6 +33,7 @@
#include <QScrollBar>
#include <QSignalMapper>
#include <QTableView>
+#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
@@ -112,6 +113,17 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
+ // Delay before filtering transactions in ms
+ static const int input_filter_delay = 200;
+
+ QTimer* amount_typing_delay = new QTimer(this);
+ amount_typing_delay->setSingleShot(true);
+ amount_typing_delay->setInterval(input_filter_delay);
+
+ QTimer* prefix_typing_delay = new QTimer(this);
+ prefix_typing_delay->setSingleShot(true);
+ prefix_typing_delay->setInterval(input_filter_delay);
+
QVBoxLayout *vlayout = new QVBoxLayout(this);
vlayout->setContentsMargins(0,0,0,0);
vlayout->setSpacing(0);
@@ -173,8 +185,10 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int)));
- connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
- connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
+ connect(amountWidget, SIGNAL(textChanged(QString)), amount_typing_delay, SLOT(start()));
+ connect(amount_typing_delay, SIGNAL(timeout()), this, SLOT(changedAmount()));
+ connect(addressWidget, SIGNAL(textChanged(QString)), prefix_typing_delay, SLOT(start()));
+ connect(prefix_typing_delay, SIGNAL(timeout()), this, SLOT(changedPrefix()));
connect(view, SIGNAL(doubleClicked(QModelIndex)), this, SIGNAL(doubleClicked(QModelIndex)));
connect(view, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextualMenu(QPoint)));
@@ -312,20 +326,19 @@ void TransactionView::chooseWatchonly(int idx)
(TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt());
}
-void TransactionView::changedPrefix(const QString &prefix)
+void TransactionView::changedPrefix()
{
if(!transactionProxyModel)
return;
- transactionProxyModel->setAddressPrefix(prefix);
+ transactionProxyModel->setAddressPrefix(addressWidget->text());
}
-void TransactionView::changedAmount(const QString &amount)
+void TransactionView::changedAmount()
{
if(!transactionProxyModel)
return;
CAmount amount_parsed = 0;
- if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed))
- {
+ if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) {
transactionProxyModel->setMinAmount(amount_parsed);
}
else
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 52e57cae4c..5b4cfd4a88 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -112,8 +112,8 @@ public Q_SLOTS:
void chooseDate(int idx);
void chooseType(int idx);
void chooseWatchonly(int idx);
- void changedPrefix(const QString &prefix);
- void changedAmount(const QString &amount);
+ void changedAmount();
+ void changedPrefix();
void exportClicked();
void focusTransaction(const QModelIndex&);
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 46f4f16321..8c0268e264 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -24,6 +24,7 @@
#include "util.h"
#include "utilstrencodings.h"
#include "hash.h"
+#include "warnings.h"
#include <stdint.h>
@@ -1162,6 +1163,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
" }\n"
" }\n"
" }\n"
+ " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -1201,6 +1203,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
obj.push_back(Pair("pruneheight", block->nHeight));
}
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
return obj;
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f0ffa07e12..f79439f038 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -199,10 +199,11 @@ UniValue getmininginfo(const JSONRPCRequest& request)
" \"currentblockweight\": nnn, (numeric) The last block weight\n"
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
- " \"errors\": \"...\" (string) Current errors\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mempool\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"warnings\": \"...\" (string) any network and blockchain warnings\n"
+ " \"errors\": \"...\" (string) DEPRECATED. Same as warnings. Only shown when bitcoind is started with -deprecatedrpc=getmininginfo\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmininginfo", "")
@@ -217,10 +218,14 @@ UniValue getmininginfo(const JSONRPCRequest& request)
obj.push_back(Pair("currentblockweight", (uint64_t)nLastBlockWeight));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
+ if (IsDeprecatedRPCEnabled("getmininginfo")) {
+ obj.push_back(Pair("errors", GetWarnings("statusbar")));
+ } else {
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
+ }
return obj;
}
@@ -789,6 +794,12 @@ UniValue estimatefee(const JSONRPCRequest& request)
+ HelpExampleCli("estimatefee", "6")
);
+ if (!IsDeprecatedRPCEnabled("estimatefee")) {
+ throw JSONRPCError(RPC_METHOD_DEPRECATED, "estimatefee is deprecated and will be fully removed in v0.17. "
+ "To use estimatefee in v0.16, restart bitcoind with -deprecatedrpc=estimatefee.\n"
+ "Projects should transition to using estimatesmartfee before upgrading to v0.17");
+ }
+
RPCTypeCheck(request.params, {UniValue::VNUM});
int nBlocks = request.params[0].get_int();
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 7faf216047..0184448213 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -447,7 +447,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
" ]\n"
- " \"warnings\": \"...\" (string) any network warnings\n"
+ " \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index dc6bcec382..1f4ae75b18 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -19,7 +19,7 @@
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
* but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
* unspecified (HTTP errors and contents of 'error').
- *
+ *
* 1.0 spec: http://json-rpc.org/wiki/specification
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
@@ -135,3 +135,22 @@ void DeleteAuthCookie()
}
}
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
+{
+ if (!in.isArray()) {
+ throw std::runtime_error("Batch must be an array");
+ }
+ std::vector<UniValue> batch(num);
+ for (size_t i=0; i<in.size(); ++i) {
+ const UniValue &rec = in[i];
+ if (!rec.isObject()) {
+ throw std::runtime_error("Batch member must be object");
+ }
+ size_t id = rec["id"].get_int();
+ if (id >= num) {
+ throw std::runtime_error("Batch member id larger than size");
+ }
+ batch[id] = rec;
+ }
+ return batch;
+}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 5c9c64f67d..cb668f3db9 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -57,6 +57,7 @@ enum RPCErrorCode
RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
RPC_IN_WARMUP = -28, //!< Client still warming up
+ RPC_METHOD_DEPRECATED = -32, //!< RPC method is deprecated
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -97,5 +98,7 @@ bool GenerateAuthCookie(std::string *cookie_out);
bool GetAuthCookie(std::string *cookie_out);
/** Delete RPC authentication cookie from disk */
void DeleteAuthCookie();
+/** Parse JSON-RPC batch reply into a vector */
+std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
#endif // BITCOIN_RPCPROTOCOL_H
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index a0322f67b4..b2fc6a357a 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -873,7 +873,12 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
- TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
+ // Unable to sign input and verification failed (possible attempt to partially sign).
+ TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
+ } else {
+ TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ }
}
}
bool fComplete = vErrors.empty();
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 428ab3b9b0..a73b697e01 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -382,6 +382,13 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
+bool IsDeprecatedRPCEnabled(const std::string& method)
+{
+ const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");
+
+ return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();
+}
+
static UniValue JSONRPCExecOne(const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 777acbcb94..31d6304271 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -171,6 +171,8 @@ public:
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
};
+bool IsDeprecatedRPCEnabled(const std::string& method);
+
extern CRPCTable tableRPC;
/**
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 594b82a09e..6760d6ff84 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -934,6 +934,15 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
wtx.fFromMe = wtxIn.fFromMe;
fUpdated = true;
}
+ // If we have a witness-stripped version of this transaction, and we
+ // see a new version with a witness, then we must be upgrading a pre-segwit
+ // wallet. Store the new version of the transaction with the witness,
+ // as the stripped-version must be invalid.
+ // TODO: Store all versions of the transaction, instead of just one.
+ if (wtxIn.tx->HasWitness() && !wtx.tx->HasWitness()) {
+ wtx.SetTx(wtxIn.tx);
+ fUpdated = true;
+ }
}
//// debug print
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 52370a8eb5..b7f873c1e4 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -41,9 +41,9 @@ bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& s
return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
}
-bool CWalletDB::ErasePurpose(const std::string& strPurpose)
+bool CWalletDB::ErasePurpose(const std::string& strAddress)
{
- return EraseIC(std::make_pair(std::string("purpose"), strPurpose));
+ return EraseIC(std::make_pair(std::string("purpose"), strAddress));
}
bool CWalletDB::WriteTx(const CWalletTx& wtx)
diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py
index ffed5b0d33..996cbb8a12 100755
--- a/test/functional/bitcoin_cli.py
+++ b/test/functional/bitcoin_cli.py
@@ -35,5 +35,28 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_equal(["foo", "bar"], self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=password + "\nfoo\nbar").echo())
assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo)
+ self.log.info("Compare responses from `bitcoin-cli -getinfo` and the RPCs data is retrieved from.")
+ cli_get_info = self.nodes[0].cli('-getinfo').help()
+ wallet_info = self.nodes[0].getwalletinfo()
+ network_info = self.nodes[0].getnetworkinfo()
+ blockchain_info = self.nodes[0].getblockchaininfo()
+
+ assert_equal(cli_get_info['version'], network_info['version'])
+ assert_equal(cli_get_info['protocolversion'], network_info['protocolversion'])
+ assert_equal(cli_get_info['walletversion'], wallet_info['walletversion'])
+ assert_equal(cli_get_info['balance'], wallet_info['balance'])
+ assert_equal(cli_get_info['blocks'], blockchain_info['blocks'])
+ assert_equal(cli_get_info['timeoffset'], network_info['timeoffset'])
+ assert_equal(cli_get_info['connections'], network_info['connections'])
+ assert_equal(cli_get_info['proxy'], network_info['networks'][0]['proxy'])
+ assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty'])
+ assert_equal(cli_get_info['testnet'], blockchain_info['chain'] == "test")
+ assert_equal(cli_get_info['balance'], wallet_info['balance'])
+ assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest'])
+ assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
+ assert_equal(cli_get_info['paytxfee'], wallet_info['paytxfee'])
+ assert_equal(cli_get_info['relayfee'], network_info['relayfee'])
+ # unlocked_until is not tested because the wallet is not encrypted
+
if __name__ == '__main__':
TestBitcoinCli().main()
diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py
index 50be9262e4..c5967aa10b 100755
--- a/test/functional/blockchain.py
+++ b/test/functional/blockchain.py
@@ -33,9 +33,10 @@ from test_framework.util import (
class BlockchainTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-stopatheight=207']]
+ self.extra_args = [['-stopatheight=207', '-prune=1']]
def run_test(self):
+ self._test_getblockchaininfo()
self._test_getchaintxstats()
self._test_gettxoutsetinfo()
self._test_getblockheader()
@@ -44,6 +45,34 @@ class BlockchainTest(BitcoinTestFramework):
self._test_stopatheight()
assert self.nodes[0].verifychain(4, 0)
+ def _test_getblockchaininfo(self):
+ self.log.info("Test getblockchaininfo")
+
+ keys = [
+ 'bestblockhash',
+ 'bip9_softforks',
+ 'blocks',
+ 'chain',
+ 'chainwork',
+ 'difficulty',
+ 'headers',
+ 'mediantime',
+ 'pruned',
+ 'softforks',
+ 'verificationprogress',
+ 'warnings',
+ ]
+ res = self.nodes[0].getblockchaininfo()
+ # result should have pruneheight and default keys if pruning is enabled
+ assert_equal(sorted(res.keys()), sorted(['pruneheight'] + keys))
+ # pruneheight should be greater or equal to 0
+ assert res['pruneheight'] >= 0
+
+ self.restart_node(0, ['-stopatheight=207'])
+ res = self.nodes[0].getblockchaininfo()
+ # should have exact keys
+ assert_equal(sorted(res.keys()), keys)
+
def _test_getchaintxstats(self):
chaintxstats = self.nodes[0].getchaintxstats(1)
# 200 txs plus genesis tx
diff --git a/test/functional/deprecated_rpc.py b/test/functional/deprecated_rpc.py
new file mode 100755
index 0000000000..ec500ccbf9
--- /dev/null
+++ b/test/functional/deprecated_rpc.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test deprecation of RPC calls."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_raises_jsonrpc
+
+class DeprecatedRpcTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+ self.extra_args = [[], ["-deprecatedrpc=estimatefee"]]
+
+ def run_test(self):
+ self.log.info("estimatefee: Shows deprecated message")
+ assert_raises_jsonrpc(-32, 'estimatefee is deprecated', self.nodes[0].estimatefee, 1)
+
+ self.log.info("Using -deprecatedrpc=estimatefee bypasses the error")
+ self.nodes[1].estimatefee(1)
+
+if __name__ == '__main__':
+ DeprecatedRpcTest().main()
diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py
index 0848fcde64..f9bef2580a 100755
--- a/test/functional/p2p-versionbits-warning.py
+++ b/test/functional/p2p-versionbits-warning.py
@@ -87,7 +87,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1)
# Check that we're not getting any versionbit-related errors in
# get*info()
- assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["errors"]))
+ assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["warnings"]))
assert(not VB_PATTERN.match(self.nodes[0].getnetworkinfo()["warnings"]))
# 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling
@@ -98,7 +98,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# have gotten a different alert due to more than 51/100 blocks
# being of unexpected version.
# Check that get*info() shows some kind of error.
- assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["errors"])
+ assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["warnings"])
assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getnetworkinfo()["warnings"])
# Mine a period worth of expected blocks so the generic block-version warning
@@ -113,7 +113,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# Connecting one block should be enough to generate an error.
self.nodes[0].generate(1)
- assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"])
+ assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["warnings"])
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"])
self.stop_nodes()
self.test_versionbits_in_alert_file()
diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py
index 76632fc578..986f4546a8 100755
--- a/test/functional/smartfees.py
+++ b/test/functional/smartfees.py
@@ -151,7 +151,7 @@ class EstimateFeeTest(BitcoinTestFramework):
which we will use to generate our transactions.
"""
self.add_nodes(3, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"],
- ["-blockmaxsize=17000", "-maxorphantx=1000"],
+ ["-blockmaxsize=17000", "-maxorphantx=1000", "-deprecatedrpc=estimatefee"],
["-blockmaxsize=8000", "-maxorphantx=1000"]])
# Use node0 to mine blocks for input splitting
# Node1 mines small blocks but that are bigger than the expected transaction rate.
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index a53eb51799..381513ab9e 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -273,6 +273,11 @@ class BitcoinTestFramework(object):
# Wait for nodes to stop
node.wait_until_stopped()
+ def restart_node(self, i, extra_args=None):
+ """Stop and start a test node"""
+ self.stop_node(i)
+ self.start_node(i, extra_args)
+
def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None):
with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr:
try:
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 8dbe6247ee..5c8740d7cd 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -98,6 +98,7 @@ BASE_SCRIPTS= [
'disconnect_ban.py',
'decodescript.py',
'blockchain.py',
+ 'deprecated_rpc.py',
'disablewallet.py',
'net.py',
'keypool.py',
diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json
index b61a4f7f8f..89b28bba6c 100644
--- a/test/util/data/bitcoin-util-test.json
+++ b/test/util/data/bitcoin-util-test.json
@@ -263,6 +263,13 @@
},
{ "exec": "./bitcoin-tx",
"args":
+ ["-json", "-create", "outpubkey=0:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:WS", "nversion=1"],
+ "return_code": 1,
+ "error_txt": "error: Uncompressed pubkeys are not useable for SegWit outputs",
+ "description": "Creates a new transaction with a single pay-to-pub-key output, wrapped in P2SH (output as json)"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
["-create",
"in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
"outdata=4:badhexdata"],
@@ -388,5 +395,16 @@
"args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485:WS", "nversion=1"],
"output_cmp": "txcreatemultisig4.json",
"description": "Creates a new transaction with a single 2-of-3 multisig in a P2WSH output, wrapped in P2SH (output in json)"
+ },
+ { "exec": "./bitcoin-tx",
+ "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:S"],
+ "output_cmp": "txcreatemultisig5.json",
+ "description": "Uncompressed pubkeys should work just fine for non-witness outputs"
+ },
+ { "exec": "./bitcoin-tx",
+ "args": ["-json", "-create", "outmultisig=1:2:3:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397:021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d:047d1368ba7ae01c94bc32293efd70bd7e3be7aa7912d07d0b1c659c1008d179b8642f5fb90f47580feb29f045e216ff5a4716d3a0fed36da414d332046303c44a:WS"],
+ "return_code": 1,
+ "error_txt": "error: Uncompressed pubkeys are not useable for SegWit outputs",
+ "description": "Ensure adding witness outputs with uncompressed pubkeys fails"
}
]
diff --git a/test/util/data/txcreatemultisig5.json b/test/util/data/txcreatemultisig5.json
new file mode 100644
index 0000000000..20e9bb077b
--- /dev/null
+++ b/test/util/data/txcreatemultisig5.json
@@ -0,0 +1,26 @@
+{
+ "txid": "813cf75e1f08debd242ef7c8192b7d478fb651355209369499a0de779ba7eb2f",
+ "hash": "813cf75e1f08debd242ef7c8192b7d478fb651355209369499a0de779ba7eb2f",
+ "version": 2,
+ "size": 42,
+ "vsize": 42,
+ "locktime": 0,
+ "vin": [
+ ],
+ "vout": [
+ {
+ "value": 1.00000000,
+ "n": 0,
+ "scriptPubKey": {
+ "asm": "OP_HASH160 a4051c02398868af83f28f083208fae99a769263 OP_EQUAL",
+ "hex": "a914a4051c02398868af83f28f083208fae99a76926387",
+ "reqSigs": 1,
+ "type": "scripthash",
+ "addresses": [
+ "3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos"
+ ]
+ }
+ }
+ ],
+ "hex": "02000000000100e1f5050000000017a914a4051c02398868af83f28f083208fae99a7692638700000000"
+}