aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/devtools/security-check.py2
-rwxr-xr-xcontrib/gitian-build.py203
-rwxr-xr-xcontrib/gitian-build.sh413
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml16
-rw-r--r--contrib/gitian-descriptors/gitian-osx-signer.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml4
-rw-r--r--contrib/gitian-descriptors/gitian-win-signer.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml9
-rw-r--r--contrib/zmq/zmq_sub.py2
-rw-r--r--contrib/zmq/zmq_sub3.4.py2
-rw-r--r--depends/packages/packages.mk1
-rw-r--r--depends/packages/qt.mk4
-rw-r--r--doc/release-process.md2
-rw-r--r--src/Makefile.am1
-rw-r--r--src/bench/bech32.cpp1
-rw-r--r--src/bench/bench_bitcoin.cpp13
-rw-r--r--src/chainparamsbase.cpp1
-rw-r--r--src/httprpc.cpp2
-rw-r--r--src/init.cpp2
-rw-r--r--src/interfaces/handler.cpp2
-rw-r--r--src/net.cpp16
-rw-r--r--src/net.h11
-rw-r--r--src/net_processing.cpp23
-rw-r--r--src/rpc/blockchain.cpp289
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/util.h11
-rw-r--r--src/utilmemory.h19
-rw-r--r--src/validation.cpp12
-rw-r--r--src/validation.h14
-rw-r--r--src/wallet/wallet.cpp2
-rwxr-xr-xtest/functional/p2p_segwit.py3
-rwxr-xr-xtest/functional/rpc_scantxoutset.py48
-rwxr-xr-xtest/functional/rpc_users.py2
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/wallet_abandonconflict.py12
36 files changed, 671 insertions, 479 deletions
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index c9516ef83f..47195f73c8 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -97,7 +97,7 @@ def check_ELF_RELRO(executable):
raise IOError('Error opening file')
for line in stdout.splitlines():
tokens = line.split()
- if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2]):
+ if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2:]):
have_bindnow = True
return have_gnu_relro and have_bindnow
diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py
new file mode 100755
index 0000000000..1da9e43896
--- /dev/null
+++ b/contrib/gitian-build.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import subprocess
+import sys
+
+def setup():
+ global args, workdir
+ programs = ['ruby', 'git', 'apt-cacher-ng', 'make', 'wget']
+ if args.kvm:
+ programs += ['python-vm-builder', 'qemu-kvm', 'qemu-utils']
+ elif args.docker:
+ programs += ['docker.io']
+ else:
+ programs += ['lxc', 'debootstrap']
+ subprocess.check_call(['sudo', 'apt-get', 'install', '-qq'] + programs)
+ if not os.path.isdir('gitian.sigs'):
+ subprocess.check_call(['git', 'clone', 'https://github.com/bitcoin-core/gitian.sigs.git'])
+ if not os.path.isdir('bitcoin-detached-sigs'):
+ subprocess.check_call(['git', 'clone', 'https://github.com/bitcoin-core/bitcoin-detached-sigs.git'])
+ if not os.path.isdir('gitian-builder'):
+ subprocess.check_call(['git', 'clone', 'https://github.com/devrandom/gitian-builder.git'])
+ if not os.path.isdir('bitcoin'):
+ subprocess.check_call(['git', 'clone', 'https://github.com/bitcoin/bitcoin.git'])
+ os.chdir('gitian-builder')
+ make_image_prog = ['bin/make-base-vm', '--suite', 'bionic', '--arch', 'amd64']
+ if args.docker:
+ make_image_prog += ['--docker']
+ elif not args.kvm:
+ make_image_prog += ['--lxc']
+ subprocess.check_call(make_image_prog)
+ os.chdir(workdir)
+
+def build():
+ global args, workdir
+
+ os.makedirs('bitcoin-binaries/' + args.version, exist_ok=True)
+ print('\nBuilding Dependencies\n')
+ os.chdir('gitian-builder')
+ os.makedirs('inputs', exist_ok=True)
+
+ subprocess.check_call(['wget', '-N', '-P', 'inputs', 'http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz'])
+ subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch'])
+ subprocess.check_call(['make', '-C', '../bitcoin/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common'])
+
+ if args.linux:
+ print('\nCompiling ' + args.version + ' Linux')
+ subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml'])
+ subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-linux', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml'])
+ subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/'+args.version, shell=True)
+
+ if args.windows:
+ print('\nCompiling ' + args.version + ' Windows')
+ subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-win.yml'])
+ subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml'])
+ subprocess.check_call('mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz', shell=True)
+ subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/'+args.version, shell=True)
+
+ if args.macos:
+ print('\nCompiling ' + args.version + ' MacOS')
+ subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml'])
+ subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml'])
+ subprocess.check_call('mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz', shell=True)
+ subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/'+args.version, shell=True)
+
+ os.chdir(workdir)
+
+ if args.commit_files:
+ print('\nCommitting '+args.version+' Unsigned Sigs\n')
+ os.chdir('gitian.sigs')
+ subprocess.check_call(['git', 'add', args.version+'-linux/'+args.signer])
+ subprocess.check_call(['git', 'add', args.version+'-win-unsigned/'+args.signer])
+ subprocess.check_call(['git', 'add', args.version+'-osx-unsigned/'+args.signer])
+ subprocess.check_call(['git', 'commit', '-m', 'Add '+args.version+' unsigned sigs for '+args.signer])
+ os.chdir(workdir)
+
+def sign():
+ global args, workdir
+ os.chdir('gitian-builder')
+
+ if args.windows:
+ print('\nSigning ' + args.version + ' Windows')
+ subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
+ subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
+ subprocess.check_call('mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/'+args.version, shell=True)
+ subprocess.check_call('mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/'+args.version, shell=True)
+
+ if args.macos:
+ print('\nSigning ' + args.version + ' MacOS')
+ subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
+ subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
+ subprocess.check_call('mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/'+args.version+'/bitcoin-'+args.version+'-osx.dmg', shell=True)
+
+ os.chdir(workdir)
+
+ if args.commit_files:
+ print('\nCommitting '+args.version+' Signed Sigs\n')
+ os.chdir('gitian.sigs')
+ subprocess.check_call(['git', 'add', args.version+'-win-signed/'+args.signer])
+ subprocess.check_call(['git', 'add', args.version+'-osx-signed/'+args.signer])
+ subprocess.check_call(['git', 'commit', '-a', '-m', 'Add '+args.version+' signed binary sigs for '+args.signer])
+ os.chdir(workdir)
+
+def verify():
+ global args, workdir
+ os.chdir('gitian-builder')
+
+ print('\nVerifying v'+args.version+' Linux\n')
+ subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml'])
+ print('\nVerifying v'+args.version+' Windows\n')
+ subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml'])
+ print('\nVerifying v'+args.version+' MacOS\n')
+ subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml'])
+ print('\nVerifying v'+args.version+' Signed Windows\n')
+ subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
+ print('\nVerifying v'+args.version+' Signed MacOS\n')
+ subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
+
+ os.chdir(workdir)
+
+def main():
+ global args, workdir
+
+ parser = argparse.ArgumentParser(usage='%(prog)s [options] signer version')
+ parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch')
+ parser.add_argument('-u', '--url', dest='url', default='https://github.com/bitcoin/bitcoin', help='Specify the URL of the repository. Default is %(default)s')
+ parser.add_argument('-v', '--verify', action='store_true', dest='verify', help='Verify the Gitian build')
+ parser.add_argument('-b', '--build', action='store_true', dest='build', help='Do a Gitian build')
+ parser.add_argument('-s', '--sign', action='store_true', dest='sign', help='Make signed binaries for Windows and MacOS')
+ parser.add_argument('-B', '--buildsign', action='store_true', dest='buildsign', help='Build both signed and unsigned binaries')
+ parser.add_argument('-o', '--os', dest='os', default='lwm', help='Specify which Operating Systems the build is for. Default is %(default)s. l for Linux, w for Windows, m for MacOS')
+ parser.add_argument('-j', '--jobs', dest='jobs', default='2', help='Number of processes to use. Default %(default)s')
+ parser.add_argument('-m', '--memory', dest='memory', default='2000', help='Memory to allocate in MiB. Default %(default)s')
+ parser.add_argument('-k', '--kvm', action='store_true', dest='kvm', help='Use KVM instead of LXC')
+ parser.add_argument('-d', '--docker', action='store_true', dest='docker', help='Use Docker instead of LXC')
+ parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Uses LXC. If you want to use KVM, use the --kvm option. Only works on Debian-based systems (Ubuntu, Debian)')
+ parser.add_argument('-D', '--detach-sign', action='store_true', dest='detach_sign', help='Create the assert file for detached signing. Will not commit anything.')
+ parser.add_argument('-n', '--no-commit', action='store_false', dest='commit_files', help='Do not commit anything to git')
+ parser.add_argument('signer', help='GPG signer to sign each build assert file')
+ parser.add_argument('version', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified')
+
+ args = parser.parse_args()
+ workdir = os.getcwd()
+
+ args.linux = 'l' in args.os
+ args.windows = 'w' in args.os
+ args.macos = 'm' in args.os
+
+ if args.buildsign:
+ args.build=True
+ args.sign=True
+
+ if args.kvm and args.docker:
+ raise Exception('Error: cannot have both kvm and docker')
+
+ args.sign_prog = 'true' if args.detach_sign else 'gpg --detach-sign'
+
+ # Set enviroment variable USE_LXC or USE_DOCKER, let gitian-builder know that we use lxc or docker
+ if args.docker:
+ os.environ['USE_DOCKER'] = '1'
+ elif not args.kvm:
+ os.environ['USE_LXC'] = '1'
+
+ # Disable for MacOS if no SDK found
+ if args.macos and not os.path.isfile('gitian-builder/inputs/MacOSX10.11.sdk.tar.gz'):
+ print('Cannot build for MacOS, SDK does not exist. Will build for other OSes')
+ args.macos = False
+
+ script_name = os.path.basename(sys.argv[0])
+ # Signer and version shouldn't be empty
+ if args.signer == '':
+ print(script_name+': Missing signer.')
+ print('Try '+script_name+' --help for more information')
+ exit(1)
+ if args.version == '':
+ print(script_name+': Missing version.')
+ print('Try '+script_name+' --help for more information')
+ exit(1)
+
+ # Add leading 'v' for tags
+ args.commit = ('' if args.commit else 'v') + args.version
+ print(args.commit)
+
+ if args.setup:
+ setup()
+
+ os.chdir('bitcoin')
+ subprocess.check_call(['git', 'fetch'])
+ subprocess.check_call(['git', 'checkout', args.commit])
+ os.chdir(workdir)
+
+ if args.build:
+ build()
+
+ if args.sign:
+ sign()
+
+ if args.verify:
+ verify()
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh
deleted file mode 100755
index 4517b28c10..0000000000
--- a/contrib/gitian-build.sh
+++ /dev/null
@@ -1,413 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2016 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C
-# What to do
-sign=false
-verify=false
-build=false
-
-# Systems to build
-linux=true
-windows=true
-osx=true
-
-# Other Basic variables
-SIGNER=
-VERSION=
-commit=false
-url=https://github.com/bitcoin/bitcoin
-proc=2
-mem=2000
-lxc=true
-docker=false
-osslTarUrl=http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz
-osslPatchUrl=https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch
-scriptName=$(basename -- "$0")
-signProg="gpg --detach-sign"
-commitFiles=true
-
-# Help Message
-read -d '' usage <<- EOF
-Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version
-
-Run this script from the directory containing the bitcoin, gitian-builder, gitian.sigs, and bitcoin-detached-sigs.
-
-Arguments:
-signer GPG signer to sign each build assert file
-version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified
-
-Options:
--c|--commit Indicate that the version argument is for a commit or branch
--u|--url Specify the URL of the repository. Default is https://github.com/bitcoin/bitcoin
--v|--verify Verify the Gitian build
--b|--build Do a Gitian build
--s|--sign Make signed binaries for Windows and Mac OSX
--B|--buildsign Build both signed and unsigned binaries
--o|--os Specify which Operating Systems the build is for. Default is lwx. l for linux, w for windows, x for osx
--j Number of processes to use. Default 2
--m Memory to allocate in MiB. Default 2000
---kvm Use KVM instead of LXC
---docker Use Docker instead of LXC
---setup Set up the Gitian building environment. Uses LXC. If you want to use KVM, use the --kvm option. Only works on Debian-based systems (Ubuntu, Debian)
---detach-sign Create the assert file for detached signing. Will not commit anything.
---no-commit Do not commit anything to git
--h|--help Print this help message
-EOF
-
-# Get options and arguments
-while :; do
- case $1 in
- # Verify
- -v|--verify)
- verify=true
- ;;
- # Build
- -b|--build)
- build=true
- ;;
- # Sign binaries
- -s|--sign)
- sign=true
- ;;
- # Build then Sign
- -B|--buildsign)
- sign=true
- build=true
- ;;
- # PGP Signer
- -S|--signer)
- if [ -n "$2" ]
- then
- SIGNER="$2"
- shift
- else
- echo 'Error: "--signer" requires a non-empty argument.'
- exit 1
- fi
- ;;
- # Operating Systems
- -o|--os)
- if [ -n "$2" ]
- then
- linux=false
- windows=false
- osx=false
- if [[ "$2" = *"l"* ]]
- then
- linux=true
- fi
- if [[ "$2" = *"w"* ]]
- then
- windows=true
- fi
- if [[ "$2" = *"x"* ]]
- then
- osx=true
- fi
- shift
- else
- echo 'Error: "--os" requires an argument containing an l (for linux), w (for windows), or x (for Mac OSX)'
- exit 1
- fi
- ;;
- # Help message
- -h|--help)
- echo "$usage"
- exit 0
- ;;
- # Commit or branch
- -c|--commit)
- commit=true
- ;;
- # Number of Processes
- -j)
- if [ -n "$2" ]
- then
- proc=$2
- shift
- else
- echo 'Error: "-j" requires an argument'
- exit 1
- fi
- ;;
- # Memory to allocate
- -m)
- if [ -n "$2" ]
- then
- mem=$2
- shift
- else
- echo 'Error: "-m" requires an argument'
- exit 1
- fi
- ;;
- # URL
- -u)
- if [ -n "$2" ]
- then
- url=$2
- shift
- else
- echo 'Error: "-u" requires an argument'
- exit 1
- fi
- ;;
- # kvm
- --kvm)
- lxc=false
- ;;
- # docker
- --docker)
- if [[ $lxc = false ]]
- then
- echo 'Error: cannot have both kvm and docker'
- exit 1
- fi
- lxc=false
- docker=true
- ;;
- # Detach sign
- --detach-sign)
- signProg="true"
- commitFiles=false
- ;;
- # Commit files
- --no-commit)
- commitFiles=false
- ;;
- # Setup
- --setup)
- setup=true
- ;;
- *) # Default case: If no more options then break out of the loop.
- break
- esac
- shift
-done
-
-# Set up LXC
-if [[ $lxc = true ]]
-then
- export USE_LXC=1
-fi
-
-# Setup docker
-if [[ $docker = true ]]
-then
- export USE_DOCKER=1
-fi
-
-# Check for OSX SDK
-if [[ ! -e "gitian-builder/inputs/MacOSX10.11.sdk.tar.gz" && $osx == true ]]
-then
- echo "Cannot build for OSX, SDK does not exist. Will build for other OSes"
- osx=false
-fi
-
-# Get signer
-if [[ -n "$1" ]]
-then
- SIGNER="$1"
- shift
-fi
-
-# Get version
-if [[ -n "$1" ]]
-then
- VERSION=$1
- COMMIT=$VERSION
- shift
-fi
-
-# Check that a signer is specified
-if [[ "$SIGNER" == "" ]]
-then
- echo "$scriptName: Missing signer."
- echo "Try $scriptName --help for more information"
- exit 1
-fi
-
-# Check that a version is specified
-if [[ $VERSION == "" ]]
-then
- echo "$scriptName: Missing version."
- echo "Try $scriptName --help for more information"
- exit 1
-fi
-
-# Add a "v" if no -c
-if [[ $commit = false ]]
-then
- COMMIT="v${VERSION}"
-fi
-echo ${COMMIT}
-
-# Setup build environment
-if [[ $setup = true ]]
-then
- sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils
- git clone https://github.com/bitcoin-core/gitian.sigs.git
- git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git
- git clone https://github.com/devrandom/gitian-builder.git
- pushd ./gitian-builder
- if [[ -n "$USE_LXC" ]]
- then
- sudo apt-get install lxc
- bin/make-base-vm --suite trusty --arch amd64 --lxc
- elif [[ -n "$USE_DOCKER" ]]
- then
- sudo apt-get install docker-ce
- bin/make-base-vm --suite trusty --arch amd64 --docker
- else
- bin/make-base-vm --suite trusty --arch amd64
- fi
- popd
-fi
-
-# Set up build
-pushd ./bitcoin
-git fetch
-git checkout ${COMMIT}
-popd
-
-# Build
-if [[ $build = true ]]
-then
- # Make output folder
- mkdir -p ./bitcoin-binaries/${VERSION}
-
- # Build Dependencies
- echo ""
- echo "Building Dependencies"
- echo ""
- pushd ./gitian-builder
- mkdir -p inputs
- wget -N -P inputs $osslPatchUrl
- wget -N -P inputs $osslTarUrl
- make -C ../bitcoin/depends download SOURCES_PATH=`pwd`/cache/common
-
- # Linux
- if [[ $linux = true ]]
- then
- echo ""
- echo "Compiling ${VERSION} Linux"
- echo ""
- ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
- ./bin/gsign -p "$signProg" --signer "$SIGNER" --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
- mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/${VERSION}
- fi
- # Windows
- if [[ $windows = true ]]
- then
- echo ""
- echo "Compiling ${VERSION} Windows"
- echo ""
- ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
- ./bin/gsign -p "$signProg" --signer "$SIGNER" --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
- mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz
- mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/${VERSION}
- fi
- # Mac OSX
- if [[ $osx = true ]]
- then
- echo ""
- echo "Compiling ${VERSION} Mac OSX"
- echo ""
- ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
- ./bin/gsign -p "$signProg" --signer "$SIGNER" --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
- mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz
- mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/${VERSION}
- fi
- popd
-
- if [[ $commitFiles = true ]]
- then
- # Commit to gitian.sigs repo
- echo ""
- echo "Committing ${VERSION} Unsigned Sigs"
- echo ""
- pushd gitian.sigs
- git add ${VERSION}-linux/"${SIGNER}"
- git add ${VERSION}-win-unsigned/"${SIGNER}"
- git add ${VERSION}-osx-unsigned/"${SIGNER}"
- git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}"
- popd
- fi
-fi
-
-# Verify the build
-if [[ $verify = true ]]
-then
- # Linux
- pushd ./gitian-builder
- echo ""
- echo "Verifying v${VERSION} Linux"
- echo ""
- ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
- # Windows
- echo ""
- echo "Verifying v${VERSION} Windows"
- echo ""
- ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
- # Mac OSX
- echo ""
- echo "Verifying v${VERSION} Mac OSX"
- echo ""
- ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
- # Signed Windows
- echo ""
- echo "Verifying v${VERSION} Signed Windows"
- echo ""
- ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
- # Signed Mac OSX
- echo ""
- echo "Verifying v${VERSION} Signed Mac OSX"
- echo ""
- ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
- popd
-fi
-
-# Sign binaries
-if [[ $sign = true ]]
-then
-
- pushd ./gitian-builder
- # Sign Windows
- if [[ $windows = true ]]
- then
- echo ""
- echo "Signing ${VERSION} Windows"
- echo ""
- ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
- ./bin/gsign -p "$signProg" --signer "$SIGNER" --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
- mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/${VERSION}
- mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/${VERSION}
- fi
- # Sign Mac OSX
- if [[ $osx = true ]]
- then
- echo ""
- echo "Signing ${VERSION} Mac OSX"
- echo ""
- ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
- ./bin/gsign -p "$signProg" --signer "$SIGNER" --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
- mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/${VERSION}/bitcoin-${VERSION}-osx.dmg
- fi
- popd
-
- if [[ $commitFiles = true ]]
- then
- # Commit Sigs
- pushd gitian.sigs
- echo ""
- echo "Committing ${VERSION} Signed Sigs"
- echo ""
- git add ${VERSION}-win-signed/"${SIGNER}"
- git add ${VERSION}-osx-signed/"${SIGNER}"
- git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}"
- popd
- fi
-fi
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index f78eea73a3..1c8aca6f65 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -2,23 +2,23 @@
name: "bitcoin-linux-0.17"
enable_cache: true
suites:
-- "trusty"
+- "bionic"
architectures:
- "amd64"
packages:
- "curl"
- "g++-aarch64-linux-gnu"
-- "g++-4.8-aarch64-linux-gnu"
-- "gcc-4.8-aarch64-linux-gnu"
+- "g++-7-aarch64-linux-gnu"
+- "gcc-7-aarch64-linux-gnu"
- "binutils-aarch64-linux-gnu"
- "g++-arm-linux-gnueabihf"
-- "g++-4.8-arm-linux-gnueabihf"
-- "gcc-4.8-arm-linux-gnueabihf"
+- "g++-7-arm-linux-gnueabihf"
+- "gcc-7-arm-linux-gnueabihf"
- "binutils-arm-linux-gnueabihf"
-- "g++-4.8-multilib"
-- "gcc-4.8-multilib"
+- "g++-7-multilib"
+- "gcc-7-multilib"
- "binutils-gold"
-- "git-core"
+- "git"
- "pkg-config"
- "autoconf"
- "libtool"
diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml
index b5c863bb14..297a136fae 100644
--- a/contrib/gitian-descriptors/gitian-osx-signer.yml
+++ b/contrib/gitian-descriptors/gitian-osx-signer.yml
@@ -1,7 +1,7 @@
---
name: "bitcoin-dmg-signer"
suites:
-- "trusty"
+- "bionic"
architectures:
- "amd64"
packages:
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 2cc62d4ce7..7d4793b97d 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -2,14 +2,14 @@
name: "bitcoin-osx-0.17"
enable_cache: true
suites:
-- "trusty"
+- "bionic"
architectures:
- "amd64"
packages:
- "ca-certificates"
- "curl"
- "g++"
-- "git-core"
+- "git"
- "pkg-config"
- "autoconf"
- "librsvg2-bin"
diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml
index 3c1e0214a0..2f3ec3e8ff 100644
--- a/contrib/gitian-descriptors/gitian-win-signer.yml
+++ b/contrib/gitian-descriptors/gitian-win-signer.yml
@@ -1,7 +1,7 @@
---
name: "bitcoin-win-signer"
suites:
-- "trusty"
+- "bionic"
architectures:
- "amd64"
packages:
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index f6eb1815f6..9c588afcda 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -2,13 +2,13 @@
name: "bitcoin-win-0.17"
enable_cache: true
suites:
-- "trusty"
+- "bionic"
architectures:
- "amd64"
packages:
- "curl"
- "g++"
-- "git-core"
+- "git"
- "pkg-config"
- "autoconf"
- "libtool"
@@ -21,6 +21,7 @@ packages:
- "zip"
- "ca-certificates"
- "python"
+- "rename"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
@@ -29,7 +30,7 @@ script: |
WRAP_DIR=$HOME/wrapped
HOSTS="i686-w64-mingw32 x86_64-w64-mingw32"
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests"
- FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip objcopy"
+ FAKETIME_HOST_PROGS="ar ranlib nm windres strip objcopy"
FAKETIME_PROGS="date makensis zip"
HOST_CFLAGS="-O2 -g"
HOST_CXXFLAGS="-O2 -g"
@@ -84,7 +85,7 @@ script: |
done
for prog in gcc g++; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
- echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
+ echo "REAL=\`which -a ${i}-${prog}-posix | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog}
diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py
index 60768dc59a..fa9e669308 100644
--- a/contrib/zmq/zmq_sub.py
+++ b/contrib/zmq/zmq_sub.py
@@ -30,7 +30,7 @@ import signal
import struct
import sys
-if not (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
+if (sys.version_info.major, sys.version_info.minor) < (3, 5):
print("This example only works with Python 3.5 and greater")
sys.exit(1)
diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py
index 0df843c9a3..d05ecc2623 100644
--- a/contrib/zmq/zmq_sub3.4.py
+++ b/contrib/zmq/zmq_sub3.4.py
@@ -34,7 +34,7 @@ import signal
import struct
import sys
-if not (sys.version_info.major >= 3 and sys.version_info.minor >= 4):
+if (sys.version_info.major, sys.version_info.minor) < (3, 4):
print("This example only works with Python 3.4 and greater")
sys.exit(1)
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 551c9fa70b..69acb19b8f 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -5,6 +5,7 @@ qt_packages = qrencode protobuf zlib
qt_x86_64_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libX11 xextproto libXext xtrans
qt_i686_linux_packages:=$(qt_x86_64_linux_packages)
+qt_arm_linux_packages:=$(qt_x86_64_linux_packages)
qt_darwin_packages=qt
qt_mingw32_packages=qt
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index b4d7756b56..22cf4f515b 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -89,7 +89,7 @@ $(package)_config_opts_linux += -system-freetype
$(package)_config_opts_linux += -no-feature-sessionmanager
$(package)_config_opts_linux += -fontconfig
$(package)_config_opts_linux += -no-opengl
-$(package)_config_opts_arm_linux = -platform linux-g++ -xplatform $(host)
+$(package)_config_opts_arm_linux += -platform linux-g++ -xplatform bitcoin-linux-g++
$(package)_config_opts_i686_linux = -xplatform linux-g++-32
$(package)_config_opts_x86_64_linux = -xplatform linux-g++-64
$(package)_config_opts_mingw32 = -no-opengl -xplatform win32-g++ -device-option CROSS_COMPILE="$(host)-"
@@ -128,6 +128,8 @@ define $(package)_preprocess_cmds
cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\
cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\
cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \
+ cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \
+ sed -i s/arm-linux-gnueabi-/$(host)-/g qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \
patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch &&\
patch -p1 -i $($(package)_patch_dir)/fix_configure_mac.patch &&\
patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch &&\
diff --git a/doc/release-process.md b/doc/release-process.md
index 912b620794..f3fc4bdfdc 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -157,7 +157,7 @@ Commit your signature to gitian.sigs:
git add ${VERSION}-linux/"${SIGNER}"
git add ${VERSION}-win-unsigned/"${SIGNER}"
git add ${VERSION}-osx-unsigned/"${SIGNER}"
- git commit -a
+ git commit -m "Add ${VERSION} unsigned sigs for ${SIGNER}"
git push # Assuming you can push to the gitian.sigs tree
popd
diff --git a/src/Makefile.am b/src/Makefile.am
index 1dd202085a..2603dbae56 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -179,6 +179,7 @@ BITCOIN_CORE_H = \
ui_interface.h \
undo.h \
util.h \
+ utilmemory.h \
utilmoneystr.h \
utiltime.h \
validation.h \
diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp
index ff655bded0..8b80e17391 100644
--- a/src/bench/bech32.cpp
+++ b/src/bench/bech32.cpp
@@ -27,7 +27,6 @@ static void Bech32Encode(benchmark::State& state)
static void Bech32Decode(benchmark::State& state)
{
std::string addr = "bc1qkallence7tjawwvy0dwt4twc62qjgaw8f4vlhyd006d99f09";
- std::vector<unsigned char> vch;
while (state.KeepRunning()) {
bech32::Decode(addr);
}
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index f3302bfe5a..92befdd593 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -38,6 +38,14 @@ static void SetupBenchArgs()
gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
+static fs::path SetDataDir()
+{
+ fs::path ret = fs::temp_directory_path() / "bench_bitcoin" / fs::unique_path();
+ fs::create_directories(ret);
+ gArgs.ForceSetArg("-datadir", ret.string());
+ return ret;
+}
+
int main(int argc, char** argv)
{
SetupBenchArgs();
@@ -53,6 +61,9 @@ int main(int argc, char** argv)
return EXIT_SUCCESS;
}
+ // Set the datadir after parsing the bench options
+ const fs::path bench_datadir{SetDataDir()};
+
SHA256AutoDetect();
RandomInit();
ECC_Start();
@@ -80,6 +91,8 @@ int main(int argc, char** argv)
benchmark::BenchRunner::RunAll(*printer, evaluations, scaling_factor, regex_filter, is_list_only);
+ fs::remove_all(bench_datadir);
+
ECC_Stop();
return EXIT_SUCCESS;
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 787d8d8f6a..da9f3e3209 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -7,6 +7,7 @@
#include <tinyformat.h>
#include <util.h>
+#include <utilmemory.h>
#include <assert.h>
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index c49ad12283..97b152b11b 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -223,7 +223,7 @@ static bool InitRPCAuthentication()
return false;
}
} else {
- LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\n");
+ LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n");
strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
}
if (gArgs.GetArg("-rpcauth","") != "")
diff --git a/src/init.cpp b/src/init.cpp
index fe4fba8cdf..c7ea40817d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -501,7 +501,7 @@ void SetupServerArgs()
gArgs.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), false, OptionsCategory::RPC);
gArgs.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times", false, OptionsCategory::RPC);
- gArgs.AddArg("-rpcauth=<userpw>", "Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", false, OptionsCategory::RPC);
+ gArgs.AddArg("-rpcauth=<userpw>", "Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", false, OptionsCategory::RPC);
gArgs.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", false, OptionsCategory::RPC);
gArgs.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC);
gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", false, OptionsCategory::RPC);
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
index 8e45faa2a5..80f461f4d3 100644
--- a/src/interfaces/handler.cpp
+++ b/src/interfaces/handler.cpp
@@ -4,7 +4,7 @@
#include <interfaces/handler.h>
-#include <util.h>
+#include <utilmemory.h>
#include <boost/signals2/connection.hpp>
#include <utility>
diff --git a/src/net.cpp b/src/net.cpp
index 7070ba811c..34dc4aec5c 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2865,8 +2865,20 @@ bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
return found != nullptr && NodeFullyConnected(found) && func(found);
}
-int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
- return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
+int64_t CConnman::PoissonNextSendInbound(int64_t now, int average_interval_seconds)
+{
+ if (m_next_send_inv_to_incoming < now) {
+ // If this function were called from multiple threads simultaneously
+ // it would possible that both update the next send variable, and return a different result to their caller.
+ // This is not possible in practice as only the net processing thread invokes this function.
+ m_next_send_inv_to_incoming = PoissonNextSend(now, average_interval_seconds);
+ }
+ return m_next_send_inv_to_incoming;
+}
+
+int64_t PoissonNextSend(int64_t now, int average_interval_seconds)
+{
+ return now + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const
diff --git a/src/net.h b/src/net.h
index 697aa37a58..607b2fc53c 100644
--- a/src/net.h
+++ b/src/net.h
@@ -310,6 +310,13 @@ public:
unsigned int GetReceiveFloodSize() const;
void WakeMessageHandler();
+
+ /** Attempts to obfuscate tx time through exponentially distributed emitting.
+ Works assuming that a single interval is used.
+ Variable intervals will result in privacy decrease.
+ */
+ int64_t PoissonNextSendInbound(int64_t now, int average_interval_seconds);
+
private:
struct ListenSocket {
SOCKET socket;
@@ -434,6 +441,8 @@ private:
* This takes the place of a feeler connection */
std::atomic_bool m_try_another_outbound_peer;
+ std::atomic<int64_t> m_next_send_inv_to_incoming{0};
+
friend struct CConnmanTest;
};
extern std::unique_ptr<CConnman> g_connman;
@@ -863,6 +872,6 @@ public:
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
-int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
+int64_t PoissonNextSend(int64_t now, int average_interval_seconds);
#endif // BITCOIN_NET_H
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 0bc508980e..a0136675f3 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -78,6 +78,21 @@ void EraseOrphansFor(NodeId peer);
/** Increase a node's misbehavior score. */
void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="");
+/** Average delay between local address broadcasts in seconds. */
+static constexpr unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 60 * 60;
+/** Average delay between peer address broadcasts in seconds. */
+static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
+/** Average delay between trickled inventory transmissions in seconds.
+ * Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */
+static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
+/** Maximum number of inventory items to send per transmission.
+ * Limits the impact of low-fee transaction floods. */
+static constexpr unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
+/** Average delay between feefilter broadcasts in seconds. */
+static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
+/** Maximum feefilter broadcast delay after significant change. */
+static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
+
// Internal stuff
namespace {
/** Number of nodes with fSyncStarted. */
@@ -3515,8 +3530,12 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
bool fSendTrickle = pto->fWhitelisted;
if (pto->nNextInvSend < nNow) {
fSendTrickle = true;
- // Use half the delay for outbound peers, as there is less privacy concern for them.
- pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
+ if (pto->fInbound) {
+ pto->nNextInvSend = connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL);
+ } else {
+ // Use half the delay for outbound peers, as there is less privacy concern for them.
+ pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1);
+ }
}
// Time to send but the peer has requested we not relay transactions.
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index d9d803ac7d..012e3e3ac1 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -6,6 +6,8 @@
#include <rpc/blockchain.h>
#include <amount.h>
+#include <base58.h>
+#include <chain.h>
#include <chainparams.h>
#include <checkpoints.h>
#include <coins.h>
@@ -13,6 +15,7 @@
#include <validation.h>
#include <core_io.h>
#include <index/txindex.h>
+#include <key_io.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
@@ -27,6 +30,7 @@
#include <validationinterface.h>
#include <warnings.h>
+#include <assert.h>
#include <stdint.h>
#include <univalue.h>
@@ -1920,6 +1924,290 @@ static UniValue savemempool(const JSONRPCRequest& request)
return NullUniValue;
}
+//! Search for a given set of pubkey scripts
+bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>& should_abort, int64_t& count, CCoinsViewCursor* cursor, const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results) {
+ scan_progress = 0;
+ count = 0;
+ while (cursor->Valid()) {
+ COutPoint key;
+ Coin coin;
+ if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
+ if (++count % 8192 == 0) {
+ boost::this_thread::interruption_point();
+ if (should_abort) {
+ // allow to abort the scan via the abort reference
+ return false;
+ }
+ }
+ if (count % 256 == 0) {
+ // update progress reference every 256 item
+ uint32_t high = 0x100 * *key.hash.begin() + *(key.hash.begin() + 1);
+ scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
+ }
+ if (needles.count(coin.out.scriptPubKey)) {
+ out_results.emplace(key, coin);
+ }
+ cursor->Next();
+ }
+ scan_progress = 100;
+ return true;
+}
+
+/** RAII object to prevent concurrency issue when scanning the txout set */
+static std::mutex g_utxosetscan;
+static std::atomic<int> g_scan_progress;
+static std::atomic<bool> g_scan_in_progress;
+static std::atomic<bool> g_should_abort_scan;
+class CoinsViewScanReserver
+{
+private:
+ bool m_could_reserve;
+public:
+ explicit CoinsViewScanReserver() : m_could_reserve(false) {}
+
+ bool reserve() {
+ assert (!m_could_reserve);
+ std::lock_guard<std::mutex> lock(g_utxosetscan);
+ if (g_scan_in_progress) {
+ return false;
+ }
+ g_scan_in_progress = true;
+ m_could_reserve = true;
+ return true;
+ }
+
+ ~CoinsViewScanReserver() {
+ if (m_could_reserve) {
+ std::lock_guard<std::mutex> lock(g_utxosetscan);
+ g_scan_in_progress = false;
+ }
+ }
+};
+
+static const char *g_default_scantxoutset_script_types[] = { "P2PKH", "P2SH_P2WPKH", "P2WPKH" };
+
+enum class OutputScriptType {
+ UNKNOWN,
+ P2PK,
+ P2PKH,
+ P2SH_P2WPKH,
+ P2WPKH
+};
+
+static inline OutputScriptType GetOutputScriptTypeFromString(const std::string& outputtype)
+{
+ if (outputtype == "P2PK") return OutputScriptType::P2PK;
+ else if (outputtype == "P2PKH") return OutputScriptType::P2PKH;
+ else if (outputtype == "P2SH_P2WPKH") return OutputScriptType::P2SH_P2WPKH;
+ else if (outputtype == "P2WPKH") return OutputScriptType::P2WPKH;
+ else return OutputScriptType::UNKNOWN;
+}
+
+CTxDestination GetDestinationForKey(const CPubKey& key, OutputScriptType type)
+{
+ switch (type) {
+ case OutputScriptType::P2PKH: return key.GetID();
+ case OutputScriptType::P2SH_P2WPKH:
+ case OutputScriptType::P2WPKH: {
+ if (!key.IsCompressed()) return key.GetID();
+ CTxDestination witdest = WitnessV0KeyHash(key.GetID());
+ if (type == OutputScriptType::P2SH_P2WPKH) {
+ CScript witprog = GetScriptForDestination(witdest);
+ return CScriptID(witprog);
+ } else {
+ return witdest;
+ }
+ }
+ default: assert(false);
+ }
+}
+
+UniValue scantxoutset(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
+ throw std::runtime_error(
+ "scantxoutset <action> ( <scanobjects> )\n"
+ "\nScans the unspent transaction output set for possible entries that matches common scripts of given public keys.\n"
+ "Using addresses as scanobjects will _not_ detect unspent P2PK txouts\n"
+ "\nArguments:\n"
+ "1. \"action\" (string, required) The action to execute\n"
+ " \"start\" for starting a scan\n"
+ " \"abort\" for aborting the current scan (returns true when abort was successful)\n"
+ " \"status\" for progress report (in %) of the current scan\n"
+ "2. \"scanobjects\" (array, optional) Array of scan objects (only one object type per scan object allowed)\n"
+ " [\n"
+ " { \"address\" : \"<address>\" }, (string, optional) Bitcoin address\n"
+ " { \"script\" : \"<scriptPubKey>\" }, (string, optional) HEX encoded script (scriptPubKey)\n"
+ " { \"pubkey\" : (object, optional) Public key\n"
+ " {\n"
+ " \"pubkey\" : \"<pubkey\">, (string, required) HEX encoded public key\n"
+ " \"script_types\" : [ ... ], (array, optional) Array of script-types to derive from the pubkey (possible values: \"P2PK\", \"P2PKH\", \"P2SH-P2WPKH\", \"P2WPKH\")\n"
+ " }\n"
+ " },\n"
+ " ]\n"
+ "\nResult:\n"
+ "{\n"
+ " \"unspents\": [\n"
+ " {\n"
+ " \"txid\" : \"transactionid\", (string) The transaction id\n"
+ " \"vout\": n, (numeric) the vout value\n"
+ " \"scriptPubKey\" : \"script\", (string) the script key\n"
+ " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " of the unspent output\n"
+ " \"height\" : n, (numeric) Height of the unspent transaction output\n"
+ " }\n"
+ " ,...], \n"
+ " \"total_amount\" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n"
+ "]\n"
+ );
+
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR});
+
+ UniValue result(UniValue::VOBJ);
+ if (request.params[0].get_str() == "status") {
+ CoinsViewScanReserver reserver;
+ if (reserver.reserve()) {
+ // no scan in progress
+ return NullUniValue;
+ }
+ result.pushKV("progress", g_scan_progress);
+ return result;
+ } else if (request.params[0].get_str() == "abort") {
+ CoinsViewScanReserver reserver;
+ if (reserver.reserve()) {
+ // reserve was possible which means no scan was running
+ return false;
+ }
+ // set the abort flag
+ g_should_abort_scan = true;
+ return true;
+ } else if (request.params[0].get_str() == "start") {
+ CoinsViewScanReserver reserver;
+ if (!reserver.reserve()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
+ }
+ std::set<CScript> needles;
+ CAmount total_in = 0;
+
+ // loop through the scan objects
+ for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
+ if (!scanobject.isObject()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scan object");
+ }
+ UniValue address_uni = find_value(scanobject, "address");
+ UniValue pubkey_uni = find_value(scanobject, "pubkey");
+ UniValue script_uni = find_value(scanobject, "script");
+
+ // make sure only one object type is present
+ if (1 != !address_uni.isNull() + !pubkey_uni.isNull() + !script_uni.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Only one object type is allowed per scan object");
+ } else if (!address_uni.isNull() && !address_uni.isStr()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Scanobject \"address\" must contain a single string as value");
+ } else if (!pubkey_uni.isNull() && !pubkey_uni.isObject()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Scanobject \"pubkey\" must contain an object as value");
+ } else if (!script_uni.isNull() && !script_uni.isStr()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Scanobject \"script\" must contain a single string as value");
+ } else if (address_uni.isStr()) {
+ // type: address
+ // decode destination and derive the scriptPubKey
+ // add the script to the scan containers
+ CTxDestination dest = DecodeDestination(address_uni.get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
+ CScript script = GetScriptForDestination(dest);
+ assert(!script.empty());
+ needles.insert(script);
+ } else if (pubkey_uni.isObject()) {
+ // type: pubkey
+ // derive script(s) according to the script_type parameter
+ UniValue script_types_uni = find_value(pubkey_uni, "script_types");
+ UniValue pubkeydata_uni = find_value(pubkey_uni, "pubkey");
+
+ // check the script types and use the default if not provided
+ if (!script_types_uni.isNull() && !script_types_uni.isArray()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "script_types must be an array");
+ } else if (script_types_uni.isNull()) {
+ // use the default script types
+ script_types_uni = UniValue(UniValue::VARR);
+ for (const char *t : g_default_scantxoutset_script_types) {
+ script_types_uni.push_back(t);
+ }
+ }
+
+ // check the acctual pubkey
+ if (!pubkeydata_uni.isStr() || !IsHex(pubkeydata_uni.get_str())) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Public key must be hex encoded");
+ }
+ CPubKey pubkey(ParseHexV(pubkeydata_uni, "pubkey"));
+ if (!pubkey.IsFullyValid()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key");
+ }
+
+ // loop through the script types and derive the script
+ for (const UniValue& script_type_uni : script_types_uni.get_array().getValues()) {
+ OutputScriptType script_type = GetOutputScriptTypeFromString(script_type_uni.get_str());
+ if (script_type == OutputScriptType::UNKNOWN) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid script type");
+ CScript script;
+ if (script_type == OutputScriptType::P2PK) {
+ // support legacy P2PK scripts
+ script << ToByteVector(pubkey) << OP_CHECKSIG;
+ } else {
+ script = GetScriptForDestination(GetDestinationForKey(pubkey, script_type));
+ }
+ assert(!script.empty());
+ needles.insert(script);
+ }
+ } else if (script_uni.isStr()) {
+ // type: script
+ // check and add the script to the scan containers (needles array)
+ CScript script(ParseHexV(script_uni, "script"));
+ // TODO: check script: max length, has OP, is unspenable etc.
+ needles.insert(script);
+ }
+ }
+
+ // Scan the unspent transaction output set for inputs
+ UniValue unspents(UniValue::VARR);
+ std::vector<CTxOut> input_txos;
+ std::map<COutPoint, Coin> coins;
+ g_should_abort_scan = false;
+ g_scan_progress = 0;
+ int64_t count = 0;
+ std::unique_ptr<CCoinsViewCursor> pcursor;
+ {
+ LOCK(cs_main);
+ FlushStateToDisk();
+ pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
+ assert(pcursor);
+ }
+ bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins);
+ result.pushKV("success", res);
+ result.pushKV("searched_items", count);
+
+ for (const auto& it : coins) {
+ const COutPoint& outpoint = it.first;
+ const Coin& coin = it.second;
+ const CTxOut& txo = coin.out;
+ input_txos.push_back(txo);
+ total_in += txo.nValue;
+
+ UniValue unspent(UniValue::VOBJ);
+ unspent.pushKV("txid", outpoint.hash.GetHex());
+ unspent.pushKV("vout", (int32_t)outpoint.n);
+ unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey.begin(), txo.scriptPubKey.end()));
+ unspent.pushKV("amount", ValueFromAmount(txo.nValue));
+ unspent.pushKV("height", (int32_t)coin.nHeight);
+
+ unspents.push_back(unspent);
+ }
+ result.pushKV("unspents", unspents);
+ result.pushKV("total_amount", ValueFromAmount(total_in));
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
+ }
+ return result;
+}
+
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
@@ -1945,6 +2233,7 @@ static const CRPCCommand commands[] =
{ "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} },
{ "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
+ { "blockchain", "scantxoutset", &scantxoutset, {"action", "scanobjects"} },
/* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 0f35fd3770..ce608631ff 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -78,6 +78,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendmany", 4, "subtractfeefrom" },
{ "sendmany", 5 , "replaceable" },
{ "sendmany", 6 , "conf_target" },
+ { "scantxoutset", 1, "scanobjects" },
{ "addmultisigaddress", 0, "nrequired" },
{ "addmultisigaddress", 1, "keys" },
{ "createmultisig", 0, "nrequired" },
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 42e615ab0c..2a77e0e1ec 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -89,6 +89,7 @@ BOOST_AUTO_TEST_CASE(cnode_listen_port)
BOOST_AUTO_TEST_CASE(caddrdb_read)
{
+ SetDataDir("caddrdb_read");
CAddrManUncorrupted addrmanUncorrupted;
addrmanUncorrupted.MakeDeterministic();
@@ -134,6 +135,7 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
{
+ SetDataDir("caddrdb_read_corrupted");
CAddrManCorrupted addrmanCorrupted;
addrmanCorrupted.MakeDeterministic();
diff --git a/src/util.h b/src/util.h
index 8094d72d6b..f8bcc0192c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,11 +20,11 @@
#include <sync.h>
#include <tinyformat.h>
#include <utiltime.h>
+#include <utilmemory.h>
#include <atomic>
#include <exception>
#include <map>
-#include <memory>
#include <set>
#include <stdint.h>
#include <string>
@@ -346,13 +346,6 @@ template <typename Callable> void TraceThread(const char* name, Callable func)
std::string CopyrightHolders(const std::string& strPrefix);
-//! Substitute for C++14 std::make_unique.
-template <typename T, typename... Args>
-std::unique_ptr<T> MakeUnique(Args&&... args)
-{
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
-}
-
/**
* On platforms that support it, tell the kernel the calling thread is
* CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
diff --git a/src/utilmemory.h b/src/utilmemory.h
new file mode 100644
index 0000000000..e71fe92284
--- /dev/null
+++ b/src/utilmemory.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTILMEMORY_H
+#define BITCOIN_UTILMEMORY_H
+
+#include <memory>
+#include <utility>
+
+//! Substitute for C++14 std::make_unique.
+template <typename T, typename... Args>
+std::unique_ptr<T> MakeUnique(Args&&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+#endif
diff --git a/src/validation.cpp b/src/validation.cpp
index 811530d40e..a30f1fd0ce 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -806,13 +806,11 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// be increased is also an easy-to-reason about way to prevent
// DoS attacks via replacements.
//
- // The mining code doesn't (currently) take children into
- // account (CPFP) so we only consider the feerates of
- // transactions being directly replaced, not their indirect
- // descendants. While that does mean high feerate children are
- // ignored when deciding whether or not to replace, we do
- // require the replacement to pay more overall fees too,
- // mitigating most cases.
+ // We only consider the feerates of transactions being directly
+ // replaced, not their indirect descendants. While that does
+ // mean high feerate children are ignored when deciding whether
+ // or not to replace, we do require the replacement to pay more
+ // overall fees too, mitigating most cases.
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
if (newFeeRate <= oldFeeRate)
{
diff --git a/src/validation.h b/src/validation.h
index 07fe99c079..869f847cdb 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -104,20 +104,6 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
-/** Average delay between local address broadcasts in seconds. */
-static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 60 * 60;
-/** Average delay between peer address broadcasts in seconds. */
-static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
-/** Average delay between trickled inventory transmissions in seconds.
- * Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */
-static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5;
-/** Maximum number of inventory items to send per transmission.
- * Limits the impact of low-fee transaction floods. */
-static const unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL;
-/** Average delay between feefilter broadcasts in seconds. */
-static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60;
-/** Maximum feefilter broadcast delay after significant change. */
-static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60;
/** Block download timeout base, expressed in millionths of the block interval (i.e. 10 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 38f4de9633..067015c006 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1143,7 +1143,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
batch.WriteTx(wtx);
NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
- TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(hashTx, 0));
+ TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
if (!done.count(iter->second)) {
todo.insert(iter->second);
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 801c4b87a0..52f6482d56 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -47,6 +47,7 @@ from test_framework.script import (
CScript,
CScriptNum,
CScriptOp,
+ MAX_SCRIPT_ELEMENT_SIZE,
OP_0,
OP_1,
OP_16,
@@ -1129,8 +1130,6 @@ class SegWitTest(BitcoinTestFramework):
def test_max_witness_push_length(self):
"""Test that witness stack can only allow up to 520 byte pushes."""
- MAX_SCRIPT_ELEMENT_SIZE = 520
-
block = self.build_next_block()
witness_program = CScript([OP_DROP, OP_TRUE])
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
new file mode 100755
index 0000000000..ce5d4da9e7
--- /dev/null
+++ b/test/functional/rpc_scantxoutset.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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 the scantxoutset rpc call."""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+import shutil
+import os
+
+class ScantxoutsetTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+ def run_test(self):
+ self.log.info("Mining blocks...")
+ self.nodes[0].generate(110)
+
+ addr_P2SH_SEGWIT = self.nodes[0].getnewaddress("", "p2sh-segwit")
+ pubk1 = self.nodes[0].getaddressinfo(addr_P2SH_SEGWIT)['pubkey']
+ addr_LEGACY = self.nodes[0].getnewaddress("", "legacy")
+ pubk2 = self.nodes[0].getaddressinfo(addr_LEGACY)['pubkey']
+ addr_BECH32 = self.nodes[0].getnewaddress("", "bech32")
+ pubk3 = self.nodes[0].getaddressinfo(addr_BECH32)['pubkey']
+ self.nodes[0].sendtoaddress(addr_P2SH_SEGWIT, 1)
+ self.nodes[0].sendtoaddress(addr_LEGACY, 2)
+ self.nodes[0].sendtoaddress(addr_BECH32, 3)
+ self.nodes[0].generate(1)
+
+ self.log.info("Stop node, remove wallet, mine again some blocks...")
+ self.stop_node(0)
+ shutil.rmtree(os.path.join(self.nodes[0].datadir, "regtest", 'wallets'))
+ self.start_node(0)
+ self.nodes[0].generate(110)
+
+ self.restart_node(0, ['-nowallet'])
+ self.log.info("Test if we have found the non HD unspent outputs.")
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"pubkey": {"pubkey": pubk1}}, {"pubkey": {"pubkey": pubk2}}, {"pubkey": {"pubkey": pubk3}}])['total_amount'], 6)
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"address": addr_P2SH_SEGWIT}, {"address": addr_LEGACY}, {"address": addr_BECH32}])['total_amount'], 6)
+ assert_equal(self.nodes[0].scantxoutset("start", [ {"address": addr_P2SH_SEGWIT}, {"address": addr_LEGACY}, {"pubkey": {"pubkey": pubk3}} ])['total_amount'], 6)
+
+ self.log.info("Test invalid parameters.")
+ assert_raises_rpc_error(-8, 'Scanobject "pubkey" must contain an object as value', self.nodes[0].scantxoutset, "start", [ {"pubkey": pubk1}]) #missing pubkey object
+ assert_raises_rpc_error(-8, 'Scanobject "address" must contain a single string as value', self.nodes[0].scantxoutset, "start", [ {"address": {"address": addr_P2SH_SEGWIT}}]) #invalid object for address object
+
+if __name__ == '__main__':
+ ScantxoutsetTest().main()
diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py
index 1ef59da5ad..62d86467fc 100755
--- a/test/functional/rpc_users.py
+++ b/test/functional/rpc_users.py
@@ -59,7 +59,7 @@ class HTTPBasicsTest(BitcoinTestFramework):
#Old authpair
authpair = url.username + ':' + url.password
- #New authpair generated via share/rpcuser tool
+ #New authpair generated via share/rpcauth tool
password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM="
#Second authpair with different username
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 49833e5dd4..5d039d7bc4 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -142,6 +142,7 @@ BASE_SCRIPTS = [
'feature_uacomment.py',
'p2p_unrequested_blocks.py',
'feature_includeconf.py',
+ 'rpc_scantxoutset.py',
'feature_logging.py',
'p2p_node_network_limited.py',
'feature_blocksdir.py',
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index d5ef08d782..cf2120d4eb 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -70,9 +70,17 @@ class AbandonConflictTest(BitcoinTestFramework):
signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])
+ # Create a child tx spending ABC2
+ signed3_change = Decimal("24.999")
+ inputs = [ {"txid":txABC2, "vout":0} ]
+ outputs = { self.nodes[0].getnewaddress(): signed3_change }
+ signed3 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs))
+ # note tx is never directly referenced, only abandoned as a child of the above
+ self.nodes[0].sendrawtransaction(signed3["hex"])
+
# In mempool txs from self should increase balance from change
newbalance = self.nodes[0].getbalance()
- assert_equal(newbalance, balance - Decimal("30") + Decimal("24.9996"))
+ assert_equal(newbalance, balance - Decimal("30") + signed3_change)
balance = newbalance
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
@@ -87,7 +95,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Not in mempool txs from self should only reduce balance
# inputs are still spent, but change not received
newbalance = self.nodes[0].getbalance()
- assert_equal(newbalance, balance - Decimal("24.9996"))
+ assert_equal(newbalance, balance - signed3_change)
# Unconfirmed received funds that are not in mempool, also shouldn't show
# up in unconfirmed balance
unconfbalance = self.nodes[0].getunconfirmedbalance() + self.nodes[0].getbalance()