aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--configure.ac9
-rwxr-xr-xcontrib/devtools/github-merge.py45
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml9
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh2
-rw-r--r--contrib/verify-commits/trusted-sha512-root-commit2
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh126
-rwxr-xr-xcontrib/windeploy/detached-sig-create.sh34
-rw-r--r--contrib/windeploy/win-codesign.cert99
-rw-r--r--depends/packages/zlib.mk4
-rw-r--r--doc/README.md2
-rw-r--r--doc/gitian-building.md2
-rw-r--r--doc/release-process.md33
-rwxr-xr-xqa/rpc-tests/bip65-cltv.py8
-rwxr-xr-xqa/rpc-tests/bip68-sequence.py46
-rwxr-xr-xqa/rpc-tests/bipdersig.py8
-rwxr-xr-xqa/rpc-tests/blockchain.py6
-rwxr-xr-xqa/rpc-tests/bumpfee.py2
-rwxr-xr-xqa/rpc-tests/disablewallet.py17
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py4
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py4
-rwxr-xr-xqa/rpc-tests/keypool.py18
-rwxr-xr-xqa/rpc-tests/listtransactions.py4
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py2
-rwxr-xr-xqa/rpc-tests/mempool_packages.py29
-rwxr-xr-xqa/rpc-tests/mempool_reorg.py16
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py2
-rwxr-xr-xqa/rpc-tests/nulldummy.py31
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py8
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py10
-rwxr-xr-xqa/rpc-tests/pruning.py22
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py105
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py6
-rwxr-xr-xqa/rpc-tests/segwit.py191
-rwxr-xr-xqa/rpc-tests/smartfees.py67
-rwxr-xr-xqa/rpc-tests/wallet.py20
-rw-r--r--src/Makefile.bench.include3
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/bench/coin_selection.cpp2
-rw-r--r--src/bench/prevector_destructor.cpp36
-rw-r--r--src/checkqueue.h22
-rw-r--r--src/compat.h11
-rw-r--r--src/miner.cpp4
-rw-r--r--src/miner.h2
-rw-r--r--src/net.cpp23
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/pow.cpp5
-rw-r--r--src/prevector.h17
-rw-r--r--src/qt/forms/sendcoinsdialog.ui22
-rw-r--r--src/qt/sendcoinsdialog.cpp7
-rw-r--r--src/qt/walletmodel.cpp6
-rw-r--r--src/rpc/mining.cpp18
-rw-r--r--src/test/checkqueue_tests.cpp442
-rw-r--r--src/tinyformat.h9
-rw-r--r--src/util.h20
-rw-r--r--src/validation.cpp8
-rw-r--r--src/versionbits.cpp2
-rw-r--r--src/wallet/rpcwallet.cpp10
-rw-r--r--src/wallet/test/wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp19
-rw-r--r--src/wallet/wallet.h18
61 files changed, 1198 insertions, 508 deletions
diff --git a/.travis.yml b/.travis.yml
index f2f1d0f358..ba250ec83b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -53,7 +53,7 @@ before_script:
# Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
- if [ "$RUN_TESTS" = "true" -a "${DEP_OPTS#*NO_QT=1}" = "$DEP_OPTS" ]; then export DISPLAY=:99.0; /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi
script:
- - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi
+ - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi
- if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then git fetch --unshallow; fi
- if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then contrib/verify-commits/verify-commits.sh; fi
- export TRAVIS_COMMIT_LOG=`git log --format=fuller -1`
diff --git a/configure.ac b/configure.ac
index d25bebeb1a..220fc62f8e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -558,6 +558,15 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
[ AC_MSG_RESULT(no)]
)
+dnl Check for MSG_DONTWAIT
+AC_MSG_CHECKING(for MSG_DONTWAIT)
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]],
+ [[ int f = MSG_DONTWAIT; ]])],
+ [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ],
+ [ AC_MSG_RESULT(no)]
+)
+
+
AC_MSG_CHECKING([for visibility attribute])
AC_LINK_IFELSE([AC_LANG_SOURCE([
int foo_def( void ) __attribute__((visibility("default")));
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index f1b6a12fd0..3fee39143d 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -78,24 +78,53 @@ def get_symlink_files():
ret.append(f.decode('utf-8').split("\t")[1])
return ret
-def tree_sha512sum():
- files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', '--name-only', 'HEAD']).splitlines())
+def tree_sha512sum(commit='HEAD'):
+ # request metadata for entire tree, recursively
+ files = []
+ blob_by_name = {}
+ for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines():
+ name_sep = line.index(b'\t')
+ metadata = line[:name_sep].split() # perms, 'blob', blobid
+ assert(metadata[1] == b'blob')
+ name = line[name_sep+1:]
+ files.append(name)
+ blob_by_name[name] = metadata[2]
+
+ files.sort()
+ # open connection to git-cat-file in batch mode to request data for all blobs
+ # this is much faster than launching it per file
+ p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
overall = hashlib.sha512()
for f in files:
+ blob = blob_by_name[f]
+ # request blob
+ p.stdin.write(blob + b'\n')
+ p.stdin.flush()
+ # read header: blob, "blob", size
+ reply = p.stdout.readline().split()
+ assert(reply[0] == blob and reply[1] == b'blob')
+ size = int(reply[2])
+ # hash the blob data
intern = hashlib.sha512()
- fi = open(f, 'rb')
- while True:
- piece = fi.read(65536)
- if piece:
+ ptr = 0
+ while ptr < size:
+ bs = min(65536, size - ptr)
+ piece = p.stdout.read(bs)
+ if len(piece) == bs:
intern.update(piece)
else:
- break
- fi.close()
+ raise IOError('Premature EOF reading git cat-file output')
+ ptr += bs
dig = intern.hexdigest()
+ assert(p.stdout.read(1) == b'\n') # ignore LF that follows blob data
+ # update overall hash with file hash
overall.update(dig.encode("utf-8"))
overall.update(" ".encode("utf-8"))
overall.update(f)
overall.update("\n".encode("utf-8"))
+ p.stdin.close()
+ if p.wait():
+ raise IOError('Non-zero return value executing git cat-file')
return overall.hexdigest()
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 6fead7c208..3388977e0d 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -146,6 +146,7 @@ script: |
make ${MAKEOPTS} -C src check-security
make deploy
make install DESTDIR=${INSTALLPATH}
+ rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe
cp -f bitcoin-*setup*.exe $OUTDIR/
cd installed
mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/
@@ -159,9 +160,11 @@ script: |
cd ../../
rm -rf distsrc-${i}
done
- cd $OUTDIR
- rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe
- find . -name "*-setup-unsigned.exe" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz
+ cp -rf contrib/windeploy $BUILD_DIR
+ cd $BUILD_DIR/windeploy
+ mkdir unsigned
+ cp $OUTDIR/bitcoin-*setup-unsigned.exe unsigned/
+ find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz
mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip
mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip
mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index 5022ea88bc..7f017bb4f1 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -10,7 +10,7 @@ BUNDLE="${ROOTDIR}/Bitcoin-Qt.app"
CODESIGN=codesign
TEMPDIR=sign.temp
TEMPLIST=${TEMPDIR}/signatures.txt
-OUT=signature.tar.gz
+OUT=signature-osx.tar.gz
OUTROOT=osx
if [ ! -n "$1" ]; then
diff --git a/contrib/verify-commits/trusted-sha512-root-commit b/contrib/verify-commits/trusted-sha512-root-commit
index c28f50ff78..7d41f90ad7 100644
--- a/contrib/verify-commits/trusted-sha512-root-commit
+++ b/contrib/verify-commits/trusted-sha512-root-commit
@@ -1 +1 @@
-f7ec7cfd38b543ba81ac7bed5b77f9a19739460b
+309bf16257b2395ce502017be627186b749ee749
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
index 40c9341445..74b7f38375 100755
--- a/contrib/verify-commits/verify-commits.sh
+++ b/contrib/verify-commits/verify-commits.sh
@@ -3,9 +3,6 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-# Not technically POSIX-compliant due to use of "local", but almost every
-# shell anyone uses today supports it, so its probably fine
-
DIR=$(dirname "$0")
[ "/${DIR#/}" != "$DIR" ] && DIR=$(dirname "$(pwd)/$0")
@@ -16,14 +13,36 @@ VERIFIED_SHA512_ROOT=$(cat "${DIR}/trusted-sha512-root-commit")
REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits")
HAVE_FAILED=false
-IS_SIGNED () {
- if [ $1 = $VERIFIED_ROOT ]; then
- return 0;
+
+HAVE_GNU_SHA512=1
+[ ! -x "$(which sha512sum)" ] && HAVE_GNU_SHA512=0
+
+if [ x"$1" = "x" ]; then
+ CURRENT_COMMIT="HEAD"
+else
+ CURRENT_COMMIT="$1"
+fi
+
+if [ "${CURRENT_COMMIT#* }" != "$CURRENT_COMMIT" ]; then
+ echo "Commit must not contain spaces?" > /dev/stderr
+ exit 1
+fi
+
+VERIFY_TREE=0
+if [ x"$2" = "x--tree-checks" ]; then
+ VERIFY_TREE=1
+fi
+
+NO_SHA1=1
+PREV_COMMIT=""
+
+while true; do
+ if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then
+ echo "There is a valid path from "$CURRENT_COMMIT" to $VERIFIED_ROOT where all commits are signed!"
+ exit 0;
fi
- VERIFY_TREE=$2
- NO_SHA1=$3
- if [ $1 = $VERIFIED_SHA512_ROOT ]; then
+ if [ "$CURRENT_COMMIT" = $VERIFIED_SHA512_ROOT ]; then
if [ "$VERIFY_TREE" = "1" ]; then
echo "All Tree-SHA512s matched up to $VERIFIED_SHA512_ROOT" > /dev/stderr
fi
@@ -37,92 +56,77 @@ IS_SIGNED () {
export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=1
fi
- if [ "${REVSIG_ALLOWED#*$1}" != "$REVSIG_ALLOWED" ]; then
+ if [ "${REVSIG_ALLOWED#*$CURRENT_COMMIT}" != "$REVSIG_ALLOWED" ]; then
export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=1
else
export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=0
fi
- if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit $1 > /dev/null; then
- return 1;
+ if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit "$CURRENT_COMMIT" > /dev/null; then
+ if [ "$PREV_COMMIT" != "" ]; then
+ echo "No parent of $PREV_COMMIT was signed with a trusted key!" > /dev/stderr
+ echo "Parents are:" > /dev/stderr
+ PARENTS=$(git show -s --format=format:%P $PREV_COMMIT)
+ for PARENT in $PARENTS; do
+ git show -s $PARENT > /dev/stderr
+ done
+ else
+ echo "$CURRENT_COMMIT was not signed with a trusted key!" > /dev/stderr
+ fi
+ exit 1
fi
- # We set $4 to 1 on the first call, always verifying the top of the tree
- if [ "$VERIFY_TREE" = 1 -o "$4" = "1" ]; then
+ # We always verify the top of the tree
+ if [ "$VERIFY_TREE" = 1 -o "$PREV_COMMIT" = "" ]; then
IFS_CACHE="$IFS"
IFS='
'
- for LINE in $(git ls-tree --full-tree -r $1); do
+ for LINE in $(git ls-tree --full-tree -r "$CURRENT_COMMIT"); do
case "$LINE" in
"12"*)
echo "Repo contains symlinks" > /dev/stderr
IFS="$IFS_CACHE"
- return 1
+ exit 1
;;
esac
done
IFS="$IFS_CACHE"
FILE_HASHES=""
- for FILE in $(git ls-tree --full-tree -r --name-only $1 | LC_ALL=C sort); do
- HASH=$(git cat-file blob $1:"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } )
+ for FILE in $(git ls-tree --full-tree -r --name-only "$CURRENT_COMMIT" | LC_ALL=C sort); do
+ if [ "$HAVE_GNU_SHA512" = 1 ]; then
+ HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } )
+ else
+ HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST OTHER; echo $FIRST; } )
+ fi
[ "$FILE_HASHES" != "" ] && FILE_HASHES="$FILE_HASHES"'
'
FILE_HASHES="$FILE_HASHES$HASH $FILE"
done
+
+ if [ "$HAVE_GNU_SHA512" = 1 ]; then
+ TREE_HASH="$(echo "$FILE_HASHES" | sha512sum)"
+ else
+ TREE_HASH="$(echo "$FILE_HASHES" | shasum -a 512)"
+ fi
HASH_MATCHES=0
- MSG="$(git show -s --format=format:%B $1 | tail -n1)"
+ MSG="$(git show -s --format=format:%B "$CURRENT_COMMIT" | tail -n1)"
case "$MSG -" in
- "Tree-SHA512: $(echo "$FILE_HASHES" | sha512sum)")
+ "Tree-SHA512: $TREE_HASH")
HASH_MATCHES=1;;
esac
if [ "$HASH_MATCHES" = "0" ]; then
- echo "Tree-SHA512 did not match for commit $1" > /dev/stderr
- HAVE_FAILED=true
- return 1
+ echo "Tree-SHA512 did not match for commit $CURRENT_COMMIT" > /dev/stderr
+ exit 1
fi
fi
- local PARENTS
- PARENTS=$(git show -s --format=format:%P $1)
+ PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT")
for PARENT in $PARENTS; do
- if IS_SIGNED $PARENT $VERIFY_TREE $NO_SHA1 0; then
- return 0;
- fi
+ PREV_COMMIT="$CURRENT_COMMIT"
+ CURRENT_COMMIT="$PARENT"
break
done
- if ! "$HAVE_FAILED"; then
- echo "No parent of $1 was signed with a trusted key!" > /dev/stderr
- echo "Parents are:" > /dev/stderr
- for PARENT in $PARENTS; do
- git show -s $PARENT > /dev/stderr
- done
- HAVE_FAILED=true
- fi
- return 1;
-}
-
-if [ x"$1" = "x" ]; then
- TEST_COMMIT="HEAD"
-else
- TEST_COMMIT="$1"
-fi
-
-DO_CHECKOUT_TEST=0
-if [ x"$2" = "x--tree-checks" ]; then
- DO_CHECKOUT_TEST=1
-fi
-
-IS_SIGNED "$TEST_COMMIT" "$DO_CHECKOUT_TEST" 1 1
-RES=$?
-if [ "$RES" = 1 ]; then
- if ! "$HAVE_FAILED"; then
- echo "$TEST_COMMIT was not signed with a trusted key!"
- fi
-else
- echo "There is a valid path from $TEST_COMMIT to $VERIFIED_ROOT where all commits are signed!"
-fi
-
-exit $RES
+done
diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh
new file mode 100755
index 0000000000..bf4978d143
--- /dev/null
+++ b/contrib/windeploy/detached-sig-create.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+if [ -z "$OSSLSIGNCODE" ]; then
+ OSSLSIGNCODE=osslsigncode
+fi
+
+if [ ! -n "$1" ]; then
+ echo "usage: $0 <osslcodesign args>"
+ echo "example: $0 -key codesign.key"
+ exit 1
+fi
+
+OUT=signature-win.tar.gz
+SRCDIR=unsigned
+WORKDIR=./.tmp
+OUTDIR="${WORKDIR}/out"
+OUTSUBDIR="${OUTDIR}/win"
+TIMESERVER=http://timestamp.comodoca.com
+CERTFILE="win-codesign.cert"
+
+mkdir -p "${OUTSUBDIR}"
+basename -a `ls -1 "${SRCDIR}"/*-unsigned.exe` | while read UNSIGNED; do
+ echo Signing "${UNSIGNED}"
+ "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"
+ "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}"
+done
+
+rm -f "${OUT}"
+tar -C "${OUTDIR}" -czf "${OUT}" .
+rm -rf "${WORKDIR}"
+echo "Created ${OUT}"
diff --git a/contrib/windeploy/win-codesign.cert b/contrib/windeploy/win-codesign.cert
new file mode 100644
index 0000000000..200b30a3f0
--- /dev/null
+++ b/contrib/windeploy/win-codesign.cert
@@ -0,0 +1,99 @@
+-----BEGIN CERTIFICATE-----
+MIIFTTCCBDWgAwIBAgIRALlW05RLwG2hMQMX5d/o5J8wDQYJKoZIhvcNAQELBQAw
+fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxIzAhBgNV
+BAMTGkNPTU9ETyBSU0EgQ29kZSBTaWduaW5nIENBMB4XDTE2MDIwMzAwMDAwMFoX
+DTE5MDMwNTIzNTk1OVowgbUxCzAJBgNVBAYTAlVTMQ4wDAYDVQQRDAU5ODEwNDEL
+MAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAkMB1N0ZSAzMDAx
+FzAVBgNVBAkMDjcxIENvbHVtYmlhIFN0MSUwIwYDVQQKDBxUaGUgQml0Y29pbiBG
+b3VuZGF0aW9uLCBJbmMuMSUwIwYDVQQDDBxUaGUgQml0Y29pbiBGb3VuZGF0aW9u
+LCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw37Vrv9Gbku0
++kuV0t89TuyxtAcmT7QE4GcwESKKjmkxfzD9a0qlhqk8GfQ+fw4DHNN+nLKNv7xB
+bk6aS7J2v2DcXkOjrP99P9jqgTkp7MC04VtG3OqVRGB+gum0pptRovYZUQXIdkY7
+GJOok/NDagwKiiUe2V2meZ7UctsZNvYeilQdTgKIIhrMB9NowCOhT8ocVL4Ki55/
+l7hukJn3fueCM3fHTwY2/1gaGsOHoCkFRsD7vokjAVpiY+8rUgvHjb0gxgojiVGd
+6a6/F5XJwKJacvUyN4Hfc2K5lRMQjTTmo4aWNWIa0iJ3TK9BHpdSLJBqerMPvmnM
+kkapS+ZTNQIDAQABo4IBjTCCAYkwHwYDVR0jBBgwFoAUKZFg/4pN+uv5pmq4z/nm
+S71JzhIwHQYDVR0OBBYEFONpQ+cV82URVe+V8G57377KxxexMA4GA1UdDwEB/wQE
+AwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG
++EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDAjArMCkGCCsGAQUF
+BwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBDBgNVHR8EPDA6MDig
+NqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDb2RlU2lnbmlu
+Z0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQu
+Y29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWduaW5nQ0EuY3J0MCQGCCsGAQUF
+BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB
+AGnBSi9K/9rgTAyKFKrfGWSfNOwAghmsnsvpZSQ7QyoGWBFKSgCs/70kErl18oHA
+g7Y8loQB1yukZmJaCa3OvGud7smn45TCh0TMf4EpP20Wxf4rMQTxwAatasHL3+vi
+I+Nl5bsRZ09kWjvayqLII5upjS/yq0JfpmyGl5k2C/fIpztq0iOLvqWlXcL4+51r
+cMUAfX6E6EaZQm//ikp+w2+7MEXTKguOuV3gwsrTy0DsvkZl4YDgx/FA4ImzXopv
+d+3KJPLvO+OSBqUD3JPwXHnuJqGAbLBFyyCa/feGUjLlR8cxcNWLWdp4qxtoIUPG
+3wTsC9YgrglS0F7FKMXlNRY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF4DCCA8igAwIBAgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5
+MDAwMDAwWhcNMjgwNTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS
+R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
+T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p
+bmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR
+3elnMRHrzB79MR2zuWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvth
+e4YJs+P9omidHCydv3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3
+e9V5kAoUGFEs5v7BEvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQ
+c5hc9IVKaw+A3V7Wvf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPi
+XzjbxghdR7ODQfAuADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmL
+Agaff9ULAgMBAAGjggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs
+2TIy1DAdBgNVHQ4EFgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQD
+AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYD
+VR0gBAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29t
+b2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEG
+CCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5j
+b20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
+Y3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4M
+bU2x8U6ST6/COCwEzMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQci
+GlEcOtTh6Qm/5iR0rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHf
+WGshqknUfDdOvf+2dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HI
+TfK7ZU2o94VFB696aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46
+BLqioXwfy2M6FafUFRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gb
+qjSm/Iz13X9ljIwxVzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm
+5LLY5TjCqO3GgZw1a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQ
+Fhv/K53b0CDKieoofjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5s
+L6iPDAZQ+4wns3bJ9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55
+ZmjoIs2475iFTZYRPAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6
+Q++6Z2H/fUnguzB9XIDj5hY5S6c=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
+hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
+BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
+MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
+EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
+Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
+6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
+pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
+9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
+/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
+Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
+qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
+SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
+u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
+Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
+crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
+/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
+wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
+4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
+2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
+FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
+CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
+boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
+jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
+S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
+QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
+0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
+NVOFBkpdn627G190
+-----END CERTIFICATE-----
diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk
index 7ff5d00bbd..589490800f 100644
--- a/depends/packages/zlib.mk
+++ b/depends/packages/zlib.mk
@@ -7,8 +7,10 @@ $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca11
define $(package)_set_vars
$(package)_build_opts= CC="$($(package)_cc)"
$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
-$(package)_build_opts+=AR="$($(package)_ar)"
$(package)_build_opts+=RANLIB="$($(package)_ranlib)"
+$(package)_build_opts+=AR="$($(package)_ar)"
+$(package)_build_opts_darwin+=AR="$($(package)_libtool)"
+$(package)_build_opts_darwin+=ARFLAGS="-o"
endef
define $(package)_config_cmds
diff --git a/doc/README.md b/doc/README.md
index 09f32bc09e..5c00ab9150 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -3,7 +3,7 @@ Bitcoin Core 0.14.99
Setup
---------------------
-Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions (which is currently several GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
+Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions (which is currently more than 100 GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more.
To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/releases/).
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index 442d2d605f..c2f55b5796 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -336,7 +336,7 @@ There will be a lot of warnings printed during the build of the image. These can
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-building.sh -b signer 0.13.0"). Otherwise ignore this.
+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
diff --git a/doc/release-process.md b/doc/release-process.md
index 399ed25c91..91ef9e2280 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -175,7 +175,38 @@ Commit your signature to gitian.sigs:
git push # Assuming you can push to the gitian.sigs tree
popd
-Wait for Windows/OS X detached signatures:
+Codesigner only: Create Windows/OS X detached signatures:
+- Only one person handles codesigning. Everyone else should skip to the next step.
+- Only once the Windows/OS X builds each have 3 matching signatures may they be signed with their respective release keys.
+
+Codesigner only: Sign the osx binary:
+
+ transfer bitcoin-osx-unsigned.tar.gz to osx for signing
+ tar xf bitcoin-osx-unsigned.tar.gz
+ ./detached-sig-create.sh -s "Key ID"
+ Enter the keychain password and authorize the signature
+ Move signature-osx.tar.gz back to the gitian host
+
+Codesigner only: Sign the windows binaries:
+
+ tar xf bitcoin-win-unsigned.tar.gz
+ ./detached-sig-create.sh -key /path/to/codesign.key
+ Enter the passphrase for the key when prompted
+ signature-win.tar.gz will be created
+
+Codesigner only: Commit the detached codesign payloads:
+
+ cd ~/bitcoin-detached-sigs
+ checkout the appropriate branch for this release series
+ rm -rf *
+ tar xf signature-osx.tar.gz
+ tar xf signature-win.tar.gz
+ git add -a
+ git commit -m "point to ${VERSION}"
+ git tag -s v${VERSION} HEAD
+ git push the current branch and new tag
+
+Non-codesigners: wait for Windows/OS X detached signatures:
- Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys.
- Detached signatures will then be committed to the [bitcoin-detached-sigs](https://github.com/bitcoin-core/bitcoin-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries.
diff --git a/qa/rpc-tests/bip65-cltv.py b/qa/rpc-tests/bip65-cltv.py
index c9d02a98f3..7f13bb9952 100755
--- a/qa/rpc-tests/bip65-cltv.py
+++ b/qa/rpc-tests/bip65-cltv.py
@@ -69,12 +69,8 @@ class BIP65Test(BitcoinTestFramework):
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Failed to mine a version=4 block")
- # Mine 1 old-version blocks
- try:
- self.nodes[1].generate(1)
- raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks")
- except JSONRPCException:
- pass
+ # Mine 1 old-version blocks. This should fail
+ assert_raises_jsonrpc(-1,"CreateNewBlock: TestBlockValidity failed: bad-version(0x00000003)", self.nodes[1].generate, 1)
self.sync_all()
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Accepted a version=3 block after 950 version=4 blocks")
diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py
index ffd461ccb0..3ed6ebe044 100755
--- a/qa/rpc-tests/bip68-sequence.py
+++ b/qa/rpc-tests/bip68-sequence.py
@@ -90,12 +90,7 @@ class BIP68Test(BitcoinTestFramework):
tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))]
tx2.rehash()
- try:
- self.nodes[0].sendrawtransaction(ToHex(tx2))
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))
# Setting the version back down to 1 should disable the sequence lock,
# so this should be accepted.
@@ -190,14 +185,12 @@ class BIP68Test(BitcoinTestFramework):
tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a'])))
rawtx = self.nodes[0].signrawtransaction(ToHex(tx))["hex"]
- try:
- self.nodes[0].sendrawtransaction(rawtx)
- except JSONRPCException as exp:
- assert(not should_pass and using_sequence_locks)
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
+ if (using_sequence_locks and not should_pass):
+ # This transaction should be rejected
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx)
else:
- assert(should_pass or not using_sequence_locks)
- # Recalculate utxos if we successfully sent the transaction
+ # This raw transaction should be accepted
+ self.nodes[0].sendrawtransaction(rawtx)
utxos = self.nodes[0].listunspent()
# Test that sequence locks on unconfirmed inputs must have nSequence
@@ -239,14 +232,13 @@ class BIP68Test(BitcoinTestFramework):
tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee*COIN), CScript([b'a']))]
tx.rehash()
- try:
- node.sendrawtransaction(ToHex(tx))
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- assert(orig_tx.hash in node.getrawmempool())
+ if (orig_tx.hash in node.getrawmempool()):
+ # sendrawtransaction should fail if the tx is in the mempool
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx))
else:
- # orig_tx must not be in mempool
- assert(orig_tx.hash not in node.getrawmempool())
+ # sendrawtransaction should succeed if the tx is not in the mempool
+ node.sendrawtransaction(ToHex(tx))
+
return tx
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
@@ -295,12 +287,7 @@ class BIP68Test(BitcoinTestFramework):
tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN)
raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))["hex"]
- try:
- self.nodes[0].sendrawtransaction(raw_tx5)
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5)
# Test mempool-BIP68 consistency after reorg
#
@@ -373,12 +360,7 @@ class BIP68Test(BitcoinTestFramework):
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
tx3.rehash()
- try:
- self.nodes[0].sendrawtransaction(ToHex(tx3))
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], NOT_FINAL_ERROR)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))
# make a block that violates bip68; ensure that the tip updates
tip = int(self.nodes[0].getbestblockhash(), 16)
diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py
index fa54bc2749..371cc41bb7 100755
--- a/qa/rpc-tests/bipdersig.py
+++ b/qa/rpc-tests/bipdersig.py
@@ -68,12 +68,8 @@ class BIP66Test(BitcoinTestFramework):
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Failed to mine a version=3 block")
- # Mine 1 old-version blocks
- try:
- self.nodes[1].generate(1)
- raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks")
- except JSONRPCException:
- pass
+ # Mine 1 old-version blocks. This should fail
+ assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed: bad-version(0x00000002)", self.nodes[1].generate, 1)
self.sync_all()
if (self.nodes[0].getblockcount() != cnt + 1051):
raise AssertionError("Accepted a version=2 block after 950 version=3 blocks")
diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py
index 67b5826840..596aed50ec 100755
--- a/qa/rpc-tests/blockchain.py
+++ b/qa/rpc-tests/blockchain.py
@@ -14,10 +14,9 @@ Tests correspond to code in rpc/blockchain.cpp.
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.authproxy import JSONRPCException
from test_framework.util import (
assert_equal,
- assert_raises,
+ assert_raises_jsonrpc,
assert_is_hex_string,
assert_is_hash_string,
start_nodes,
@@ -58,8 +57,7 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getblockheader(self):
node = self.nodes[0]
- assert_raises(
- JSONRPCException, lambda: node.getblockheader('nonsense'))
+ assert_raises_jsonrpc(-5, "Block not found", node.getblockheader, "nonsense")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(199)
diff --git a/qa/rpc-tests/bumpfee.py b/qa/rpc-tests/bumpfee.py
index 69db197e7a..8f75e9ed4d 100755
--- a/qa/rpc-tests/bumpfee.py
+++ b/qa/rpc-tests/bumpfee.py
@@ -102,7 +102,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
segwit_out = rbf_node.validateaddress(rbf_node.getnewaddress())
rbf_node.addwitnessaddress(segwit_out["address"])
segwitid = send_to_witness(
- version=0,
+ use_p2wsh=False,
node=rbf_node,
utxo=segwit_in,
pubkey=segwit_out["pubkey"],
diff --git a/qa/rpc-tests/disablewallet.py b/qa/rpc-tests/disablewallet.py
index ff7121659b..2f729e19bf 100755
--- a/qa/rpc-tests/disablewallet.py
+++ b/qa/rpc-tests/disablewallet.py
@@ -30,19 +30,10 @@ class DisableWalletTest (BitcoinTestFramework):
x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
assert(x['isvalid'] == True)
- # Checking mining to an address without a wallet
- try:
- self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
- except JSONRPCException as e:
- assert("Invalid address" not in e.error['message'])
- assert("ProcessNewBlock, block not accepted" not in e.error['message'])
- assert("Couldn't create new block" not in e.error['message'])
-
- try:
- self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
- raise AssertionError("Must not mine to invalid address!")
- except JSONRPCException as e:
- assert("Invalid address" in e.error['message'])
+ # Checking mining to an address without a wallet. Generating to a valid address should succeed
+ # but generating to an invalid address will fail.
+ self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
+ assert_raises_jsonrpc(-5, "Invalid address", self.nodes[0].generatetoaddress, 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
if __name__ == '__main__':
DisableWalletTest ().main ()
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py
index dc17bbd7b3..bbe1dda5f7 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -61,7 +61,9 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
thr = LongpollThread(self.nodes[0])
thr.start()
# generate a random transaction and submit it
- (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), Decimal("0.0"), Decimal("0.001"), 20)
+ min_relay_fee = self.nodes[0].getnetworkinfo()["relayfee"]
+ # min_relay_fee is fee per 1000 bytes, which should be more than enough.
+ (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), min_relay_fee, Decimal("0.001"), 20)
# after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned
thr.join(60 + 20)
assert(not thr.is_alive())
diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py
index 3b17dfcfb5..67745f77d1 100755
--- a/qa/rpc-tests/getblocktemplate_proposals.py
+++ b/qa/rpc-tests/getblocktemplate_proposals.py
@@ -105,7 +105,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
# Test 3: Truncated final tx
lastbyte = txlist[-1].pop()
- assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a')
+ assert_raises_jsonrpc(-22, "Block decode failed", assert_template, node, tmpl, txlist, 'n/a')
txlist[-1].append(lastbyte)
# Test 4: Add an invalid tx to the end (duplicate of gen tx)
@@ -126,7 +126,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework):
# Test 7: Bad tx count
txlist.append(b'')
- assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a')
+ assert_raises_jsonrpc(-22, 'Block decode failed', assert_template, node, tmpl, txlist, 'n/a')
txlist.pop()
# Test 8: Bad bits
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index 4b9936a1fd..cee58563f0 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -28,11 +28,7 @@ class KeyPoolTest(BitcoinTestFramework):
assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid'])
assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid'])
- try:
- addr = nodes[0].getnewaddress()
- raise AssertionError('Keypool should be exhausted after one address')
- except JSONRPCException as e:
- assert(e.error['code']==-12)
+ assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
# put three new keys in the keypool
nodes[0].walletpassphrase('test', 12000)
@@ -48,11 +44,7 @@ class KeyPoolTest(BitcoinTestFramework):
# assert that four unique addresses were returned
assert(len(addr) == 4)
# the next one should fail
- try:
- addr = nodes[0].getrawchangeaddress()
- raise AssertionError('Keypool should be exhausted after three addresses')
- except JSONRPCException as e:
- assert(e.error['code']==-12)
+ assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].getrawchangeaddress)
# refill keypool with three new addresses
nodes[0].walletpassphrase('test', 1)
@@ -66,11 +58,7 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].generate(1)
nodes[0].generate(1)
nodes[0].generate(1)
- try:
- nodes[0].generate(1)
- raise AssertionError('Keypool should be exhausted after three addesses')
- except JSONRPCException as e:
- assert(e.error['code']==-12)
+ assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].generate, 1)
def __init__(self):
super().__init__()
diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py
index 92fb96c809..68d14093ce 100755
--- a/qa/rpc-tests/listtransactions.py
+++ b/qa/rpc-tests/listtransactions.py
@@ -126,7 +126,11 @@ class ListTransactionsTest(BitcoinTestFramework):
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable":"no"})
# Tx2 will build off txid_1, still not opting in to RBF.
+ utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1)
+ assert_equal(utxo_to_use["safe"], True)
utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1)
+ utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1)
+ assert_equal(utxo_to_use["safe"], False)
# Create tx2 using createrawtransaction
inputs = [{"txid":utxo_to_use["txid"], "vout":utxo_to_use["vout"]}]
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
index 564337d060..2c3766125a 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -87,6 +87,8 @@ class MaxBlocksInFlightTest(BitcoinTestFramework):
def run_test(self):
test = TestManager()
+ # pass log handler through to the test manager object
+ test.log = self.log
test.add_new_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test))
NetworkThread().start() # Start up network handling in another thread
test.run()
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 915d174052..17e3a9a967 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -112,10 +112,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000)
# Adding one more transaction on to the chain should fail.
- try:
- self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)
- except JSONRPCException as e:
- self.log.info("too-long-ancestor-chain successfully rejected")
+ assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1)
# Check that prioritising a tx before it's added to the mempool works
# First clear the mempool by mining a block.
@@ -155,19 +152,19 @@ class MempoolPackagesTest(BitcoinTestFramework):
for i in range(10):
transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value})
- for i in range(MAX_DESCENDANTS):
+ # Sign and send up to MAX_DESCENDANT transactions chained off the parent tx
+ for i in range(MAX_DESCENDANTS - 1):
utxo = transaction_package.pop(0)
- try:
- (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
- for j in range(10):
- transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
- if i == MAX_DESCENDANTS - 2:
- mempool = self.nodes[0].getrawmempool(True)
- assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)
- except JSONRPCException as e:
- self.log.info(e.error['message'])
- assert_equal(i, MAX_DESCENDANTS - 1)
- self.log.info("tx that would create too large descendant package successfully rejected")
+ (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
+ for j in range(10):
+ transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value})
+
+ mempool = self.nodes[0].getrawmempool(True)
+ assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS)
+
+ # Sending one more chained transaction will fail
+ utxo = transaction_package.pop(0)
+ assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10)
# TODO: check that node1's mempool is as expected
diff --git a/qa/rpc-tests/mempool_reorg.py b/qa/rpc-tests/mempool_reorg.py
index 585e4147b2..812b54ffcb 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/qa/rpc-tests/mempool_reorg.py
@@ -30,9 +30,10 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
self.sync_all()
def run_test(self):
- start_count = self.nodes[0].getblockcount()
+ # Start with a 200 block chain
+ assert_equal(self.nodes[0].getblockcount(), 200)
- # Mine three blocks. After this, nodes[0] blocks
+ # Mine four blocks. After this, nodes[0] blocks
# 101, 102, and 103 are spend-able.
new_blocks = self.nodes[1].generate(4)
self.sync_all()
@@ -52,19 +53,21 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 49.99)
spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 49.99)
- # Create a block-height-locked transaction which will be invalid after reorg
+ # Create a transaction which is time-locked to two blocks in the future
timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99})
# Set the time lock
timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1)
timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000"
timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"]
- assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)
+ # This will raise an exception because the timelock transaction is too immature to spend
+ assert_raises_jsonrpc(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx)
# Broadcast and mine spend_102 and 103:
spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
self.nodes[0].generate(1)
- assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)
+ # Time-locked transaction is still too immature to spend
+ assert_raises_jsonrpc(-26,'non-final', self.nodes[0].sendrawtransaction, timelock_tx)
# Create 102_1 and 103_1:
spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98)
@@ -73,6 +76,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
# Broadcast and mine 103_1:
spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
last_block = self.nodes[0].generate(1)
+ # Time-locked transaction can now be spent
timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)
# ... now put spend_101 and spend_102_1 in memory pools:
@@ -85,6 +89,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
for node in self.nodes:
node.invalidateblock(last_block[0])
+ # Time-locked transaction is now too immature and has been removed from the mempool
+ # spend_103_1 has been re-orged out of the chain and is back in the mempool
assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id})
# Use invalidateblock to re-org back and make all those coinbase spends
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
index 4818ad8bda..f562a93d86 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -45,7 +45,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])
# coinbase at height 102 should be too immature to spend
- assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1])
+ assert_raises_jsonrpc(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1])
# mempool should have just spend_101:
assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])
diff --git a/qa/rpc-tests/nulldummy.py b/qa/rpc-tests/nulldummy.py
index 4b215a70b0..7b19fbfd82 100755
--- a/qa/rpc-tests/nulldummy.py
+++ b/qa/rpc-tests/nulldummy.py
@@ -66,38 +66,38 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.log.info("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]")
test1txs = [self.create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, 49)]
- txid1 = self.tx_submit(self.nodes[0], test1txs[0])
+ txid1 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[0].serialize_with_witness()), True)
test1txs.append(self.create_transaction(self.nodes[0], txid1, self.ms_address, 48))
- txid2 = self.tx_submit(self.nodes[0], test1txs[1])
+ txid2 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[1].serialize_with_witness()), True)
test1txs.append(self.create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, 49))
- txid3 = self.tx_submit(self.nodes[0], test1txs[2])
+ txid3 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[2].serialize_with_witness()), True)
self.block_submit(self.nodes[0], test1txs, False, True)
self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 47)
trueDummy(test2tx)
- txid4 = self.tx_submit(self.nodes[0], test2tx, NULLDUMMY_ERROR)
+ assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True)
self.log.info("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]")
self.block_submit(self.nodes[0], [test2tx], False, True)
- self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
- test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 46)
+ self.log.info ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
+ test4tx = self.create_transaction(self.nodes[0], test2tx.hash, self.address, 46)
test6txs=[CTransaction(test4tx)]
trueDummy(test4tx)
- self.tx_submit(self.nodes[0], test4tx, NULLDUMMY_ERROR)
+ assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True)
self.block_submit(self.nodes[0], [test4tx])
- self.log.info("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation")
+ print ("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation")
test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48)
test6txs.append(CTransaction(test5tx))
test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01'
- self.tx_submit(self.nodes[0], test5tx, NULLDUMMY_ERROR)
+ assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True)
self.block_submit(self.nodes[0], [test5tx], True)
self.log.info("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]")
for i in test6txs:
- self.tx_submit(self.nodes[0], i)
+ self.nodes[0].sendrawtransaction(bytes_to_hex_str(i.serialize_with_witness()), True)
self.block_submit(self.nodes[0], test6txs, True, True)
@@ -112,17 +112,6 @@ class NULLDUMMYTest(BitcoinTestFramework):
return tx
- def tx_submit(self, node, tx, msg = ""):
- tx.rehash()
- try:
- node.sendrawtransaction(bytes_to_hex_str(tx.serialize_with_witness()), True)
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], msg)
- else:
- assert_equal('', msg)
- return tx.hash
-
-
def block_submit(self, node, txs, witness = False, accept = False):
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)
block.nVersion = 4
diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py
index 0f844883b1..dcf2b9a7de 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/qa/rpc-tests/p2p-segwit.py
@@ -1698,9 +1698,11 @@ class SegWitTest(BitcoinTestFramework):
for node in [self.nodes[0], self.nodes[2]]:
gbt_results = node.getblocktemplate()
block_version = gbt_results['version']
- # If we're not indicating segwit support, we should not be signalling
- # for segwit activation, nor should we get a witness commitment.
- assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
+ # If we're not indicating segwit support, we will still be
+ # signalling for segwit activation.
+ assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0])
+ # If we don't specify the segwit rule, then we won't get a default
+ # commitment.
assert('default_witness_commitment' not in gbt_results)
# Workaround:
diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py
index 10f596b2cb..0b04ad17ab 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/qa/rpc-tests/prioritise_transaction.py
@@ -107,13 +107,9 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"]
- try:
- self.nodes[0].sendrawtransaction(tx_hex)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- assert(tx_id not in self.nodes[0].getrawmempool())
- else:
- assert(False)
+ # This will raise an exception due to min relay fee not being met
+ assert_raises_jsonrpc(-26, "66: min relay fee not met", self.nodes[0].sendrawtransaction, tx_hex)
+ assert(tx_id not in self.nodes[0].getrawmempool())
# This is a less than 1000-byte transaction, so just set the fee
# to be the minimum for a 1000 byte transaction and check that it is
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index c6a82b5fea..cc84c8c085 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -80,7 +80,7 @@ class PruneTest(BitcoinTestFramework):
if not os.path.isfile(self.prunedir+"blk00000.dat"):
raise AssertionError("blk00000.dat is missing, pruning too early")
self.log.info("Success")
- self.log.info("Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir))
+ self.log.info("Though we're already using more than 550MiB, current usage: %d" % calc_usage(self.prunedir))
self.log.info("Mining 25 more blocks should cause the first block file to be pruned")
# Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this
for i in range(25):
@@ -94,7 +94,7 @@ class PruneTest(BitcoinTestFramework):
self.log.info("Success")
usage = calc_usage(self.prunedir)
- self.log.info("Usage should be below target:", usage)
+ self.log.info("Usage should be below target: %d" % usage)
if (usage > 550):
raise AssertionError("Pruning target not being met")
@@ -124,7 +124,7 @@ class PruneTest(BitcoinTestFramework):
connect_nodes(self.nodes[2], 0)
sync_blocks(self.nodes[0:3])
- self.log.info("Usage can be over target because of high stale rate:", calc_usage(self.prunedir))
+ self.log.info("Usage can be over target because of high stale rate: %d" % calc_usage(self.prunedir))
def reorg_test(self):
# Node 1 will mine a 300 block chain starting 287 blocks back from Node 0 and Node 2's tip
@@ -135,11 +135,11 @@ class PruneTest(BitcoinTestFramework):
self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
height = self.nodes[1].getblockcount()
- self.log.info("Current block height:", height)
+ self.log.info("Current block height: %d" % height)
invalidheight = height-287
badhash = self.nodes[1].getblockhash(invalidheight)
- self.log.info("Invalidating block at height:",invalidheight,badhash)
+ self.log.info("Invalidating block %s at height %d" % (badhash,invalidheight))
self.nodes[1].invalidateblock(badhash)
# We've now switched to our previously mined-24 block fork on node 1, but thats not what we want
@@ -151,7 +151,7 @@ class PruneTest(BitcoinTestFramework):
curhash = self.nodes[1].getblockhash(invalidheight - 1)
assert(self.nodes[1].getblockcount() == invalidheight - 1)
- self.log.info("New best height", self.nodes[1].getblockcount())
+ self.log.info("New best height: %d" % self.nodes[1].getblockcount())
# Reboot node1 to clear those giant tx's from mempool
self.stop_node(1)
@@ -165,8 +165,8 @@ class PruneTest(BitcoinTestFramework):
connect_nodes(self.nodes[2], 1)
sync_blocks(self.nodes[0:3], timeout=120)
- self.log.info("Verify height on node 2:",self.nodes[2].getblockcount())
- self.log.info("Usage possibly still high bc of stale blocks in block files:", calc_usage(self.prunedir))
+ self.log.info("Verify height on node 2: %d" % self.nodes[2].getblockcount())
+ self.log.info("Usage possibly still high bc of stale blocks in block files: %d" % calc_usage(self.prunedir))
self.log.info("Mine 220 more blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)")
for i in range(22):
@@ -176,7 +176,7 @@ class PruneTest(BitcoinTestFramework):
sync_blocks(self.nodes[0:3], timeout=300)
usage = calc_usage(self.prunedir)
- self.log.info("Usage should be below target:", usage)
+ self.log.info("Usage should be below target: %d" % usage)
if (usage > 550):
raise AssertionError("Pruning target not being met")
@@ -185,7 +185,7 @@ class PruneTest(BitcoinTestFramework):
def reorg_back(self):
# Verify that a block on the old main chain fork has been pruned away
assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash)
- self.log.info("Will need to redownload block",self.forkheight)
+ self.log.info("Will need to redownload block %d" % self.forkheight)
# Verify that we have enough history to reorg back to the fork point
# Although this is more than 288 blocks, because this chain was written more recently
@@ -209,7 +209,7 @@ class PruneTest(BitcoinTestFramework):
# At this point node 2 is within 288 blocks of the fork point so it will preserve its ability to reorg
if self.nodes[2].getblockcount() < self.mainchainheight:
blocks_to_mine = first_reorg_height + 1 - self.mainchainheight
- self.log.info("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed:", blocks_to_mine)
+ self.log.info("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed: %d" % blocks_to_mine)
self.nodes[0].invalidateblock(curchainhash)
assert(self.nodes[0].getblockcount() == self.mainchainheight)
assert(self.nodes[0].getbestblockhash() == self.mainchainhash2)
diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index 8e2abea6a5..163c304eba 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -125,12 +125,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b.vout = [CTxOut(1*COIN, CScript([b'b']))]
tx1b_hex = txToHex(tx1b)
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False)
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
# Extra 0.1 BTC fee
tx1b = CTransaction()
@@ -172,12 +168,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vout = [CTxOut(initial_nValue - 30*COIN, CScript([1]))]
dbl_tx_hex = txToHex(dbl_tx)
- try:
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False) # transaction mistakenly accepted!
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
# Accepted with sufficient fee
dbl_tx = CTransaction()
@@ -237,12 +229,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))]
dbl_tx_hex = txToHex(dbl_tx)
- try:
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False)
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
# 1 BTC fee is enough
dbl_tx = CTransaction()
@@ -269,13 +257,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))]
dbl_tx_hex = txToHex(dbl_tx)
- try:
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- assert_equal("too many potential replacements" in exp.error['message'], True)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
for tx in tree_txs:
tx.rehash()
@@ -298,12 +281,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))]
tx1b_hex = txToHex(tx1b)
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- else:
- assert(False)
+ # This will raise an exception due to insufficient fee
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
def test_spends_of_conflicting_outputs(self):
"""Replacements that spend conflicting tx outputs are rejected"""
@@ -325,12 +304,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2.vout = tx1a.vout
tx2_hex = txToHex(tx2)
- try:
- tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True)
# Spend tx1a's output to test the indirect case.
tx1b = CTransaction()
@@ -346,12 +321,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2.vout = tx1a.vout
tx2_hex = txToHex(tx2)
- try:
- tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True)
def test_new_unconfirmed_inputs(self):
"""Replacements that add new unconfirmed inputs are rejected"""
@@ -369,12 +340,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2.vout = tx1.vout
tx2_hex = txToHex(tx2)
- try:
- tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, True)
def test_too_many_replacements(self):
"""Replacements that evict too many transactions are rejected"""
@@ -419,13 +386,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]
double_tx_hex = txToHex(double_tx)
- try:
- self.nodes[0].sendrawtransaction(double_tx_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- assert_equal("too many potential replacements" in exp.error['message'], True)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, True)
# If we remove an input, it should pass
double_tx = CTransaction()
@@ -451,13 +413,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
tx1b_hex = txToHex(tx1b)
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- self.log.info(tx1b_txid)
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, True)
tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
@@ -474,12 +431,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))]
tx2b_hex = txToHex(tx2b)
- try:
- tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, True)
# Now create a new transaction that spends from tx1a and tx2a
# opt-in on one of the inputs
@@ -531,12 +484,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b_hex = txToHex(tx1b)
# Verify tx1b cannot replace tx1a.
- try:
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
# Use prioritisetransaction to set tx1a's fee to 0.
self.nodes[0].prioritisetransaction(tx1a_txid, int(-0.1*COIN))
@@ -563,12 +511,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2b_hex = txToHex(tx2b)
# Verify tx2b cannot replace tx2a.
- try:
- tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26)
- else:
- assert(False)
+ assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True)
# Now prioritise tx2b to have a higher modified fee
self.nodes[0].prioritisetransaction(tx2b.hash, int(0.1*COIN))
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index 220bf4ddd0..8720a345ce 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -92,11 +92,7 @@ class RPCBindTest(BitcoinTestFramework):
# Check that with invalid rpcallowip, we are denied
self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport)
- try:
- self.run_allowip_test(['1.1.1.1'], non_loopback_ip, defaultport)
- assert(not 'Connection not denied by rpcallowip as expected')
- except JSONRPCException:
- pass
+ assert_raises_jsonrpc(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], non_loopback_ip, defaultport)
if __name__ == '__main__':
RPCBindTest().main()
diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py
index f480e5c3f9..5b1fba8eec 100755
--- a/qa/rpc-tests/segwit.py
+++ b/qa/rpc-tests/segwit.py
@@ -6,11 +6,11 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-from test_framework.mininode import sha256, ripemd160, CTransaction, CTxIn, COutPoint, CTxOut
+from test_framework.mininode import sha256, ripemd160, CTransaction, CTxIn, COutPoint, CTxOut, COIN
from test_framework.address import script_to_p2sh, key_to_p2pkh
-from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG
+from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, hash160, OP_TRUE
from io import BytesIO
-from test_framework.mininode import FromHex
+from test_framework.mininode import ToHex, FromHex, COIN
NODE_0 = 0
NODE_1 = 1
@@ -18,47 +18,49 @@ NODE_2 = 2
WIT_V0 = 0
WIT_V1 = 1
-def witness_script(version, pubkey):
- if (version == 0):
- pubkeyhash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pubkey))))
- pkscript = "0014" + pubkeyhash
- elif (version == 1):
- # 1-of-1 multisig
- scripthash = bytes_to_hex_str(sha256(hex_str_to_bytes("5121" + pubkey + "51ae")))
- pkscript = "0020" + scripthash
+# Create a scriptPubKey corresponding to either a P2WPKH output for the
+# given pubkey, or a P2WSH output of a 1-of-1 multisig for the given
+# pubkey. Returns the hex encoding of the scriptPubKey.
+def witness_script(use_p2wsh, pubkey):
+ if (use_p2wsh == False):
+ # P2WPKH instead
+ pubkeyhash = hash160(hex_str_to_bytes(pubkey))
+ pkscript = CScript([OP_0, pubkeyhash])
else:
- assert("Wrong version" == "0 or 1")
- return pkscript
-
-def addlength(script):
- scriptlen = format(len(script)//2, 'x')
- assert(len(scriptlen) == 2)
- return scriptlen + script
-
-def create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount):
- pkscript = witness_script(version, pubkey)
+ # 1-of-1 multisig
+ witness_program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
+ scripthash = sha256(witness_program)
+ pkscript = CScript([OP_0, scripthash])
+ return bytes_to_hex_str(pkscript)
+
+# Return a transaction (in hex) that spends the given utxo to a segwit output,
+# optionally wrapping the segwit output using P2SH.
+def create_witnessprogram(use_p2wsh, utxo, pubkey, encode_p2sh, amount):
+ pkscript = hex_str_to_bytes(witness_script(use_p2wsh, pubkey))
if (encode_p2sh):
- p2sh_hash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pkscript))))
- pkscript = "a914"+p2sh_hash+"87"
- inputs = []
- outputs = {}
- inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]} )
- DUMMY_P2SH = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP"
- outputs[DUMMY_P2SH] = amount
- tx_to_witness = node.createrawtransaction(inputs,outputs)
- #replace dummy output with our own
- tx_to_witness = tx_to_witness[0:110] + addlength(pkscript) + tx_to_witness[-8:]
- return tx_to_witness
-
-def send_to_witness(version, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
- tx_to_witness = create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount)
+ p2sh_hash = hash160(pkscript)
+ pkscript = CScript([OP_HASH160, p2sh_hash, OP_EQUAL])
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), b""))
+ tx.vout.append(CTxOut(int(amount*COIN), pkscript))
+ return ToHex(tx)
+
+# Create a transaction spending a given utxo to a segwit output corresponding
+# to the given pubkey: use_p2wsh determines whether to use P2WPKH or P2WSH;
+# encode_p2sh determines whether to wrap in P2SH.
+# sign=True will have the given node sign the transaction.
+# insert_redeem_script will be added to the scriptSig, if given.
+def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""):
+ tx_to_witness = create_witnessprogram(use_p2wsh, utxo, pubkey, encode_p2sh, amount)
if (sign):
signed = node.signrawtransaction(tx_to_witness)
assert("errors" not in signed or len(["errors"]) == 0)
return node.sendrawtransaction(signed["hex"])
else:
if (insert_redeem_script):
- tx_to_witness = tx_to_witness[0:82] + addlength(insert_redeem_script) + tx_to_witness[84:]
+ tx = FromHex(CTransaction(), tx_to_witness)
+ tx.vin[0].scriptSig += CScript([hex_str_to_bytes(insert_redeem_script)])
+ tx_to_witness = ToHex(tx)
return node.sendrawtransaction(tx_to_witness)
@@ -103,22 +105,12 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(len(node.getblock(block[0])["tx"]), 1)
sync_blocks(self.nodes)
- def fail_accept(self, node, txid, sign, redeem_script=""):
- try:
- send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- except JSONRPCException as exp:
- assert(exp.error["code"] == -26)
- else:
- raise AssertionError("Tx should not have been accepted")
+ def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
+ assert_raises_jsonrpc(-26, error_msg, send_to_witness, 1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
def fail_mine(self, node, txid, sign, redeem_script=""):
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
- try:
- node.generate(1)
- except JSONRPCException as exp:
- assert(exp.error["code"] == -1)
- else:
- raise AssertionError("Created valid block when TestBlockValidity should have failed")
+ assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed", node.generate, 1)
sync_blocks(self.nodes)
def run_test(self):
@@ -175,18 +167,18 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify default node can't accept any witness format txs before fork")
# unsigned, no scriptsig
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], False)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False)
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False)
# unsigned with redeem script
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False, addlength(witness_script(0, self.pubkey[0])))
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False, addlength(witness_script(1, self.pubkey[0])))
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0]))
+ self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
# signed
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True)
- self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True)
+ self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True)
self.log.info("Verify witness txs are skipped for mining before the fork")
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424
@@ -201,12 +193,12 @@ class SegWitTest(BitcoinTestFramework):
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429
self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
- self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False)
- self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False)
+ self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False)
+ self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False)
self.log.info("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork")
- self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, addlength(witness_script(0, self.pubkey[2]))) #block 430
- self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, addlength(witness_script(1, self.pubkey[2]))) #block 431
+ self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, witness_script(False, self.pubkey[2])) #block 430
+ self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, witness_script(True, self.pubkey[2])) #block 431
self.log.info("Verify previous witness txs skipped for mining can now be mined")
assert_equal(len(self.nodes[2].getrawmempool()), 4)
@@ -230,8 +222,8 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify witness txs without witness data are invalid after the fork")
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False)
self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False)
- self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, addlength(witness_script(0, self.pubkey[2])))
- self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, addlength(witness_script(1, self.pubkey[2])))
+ self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, witness_script(False, self.pubkey[2]))
+ self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, witness_script(True, self.pubkey[2]))
self.log.info("Verify default node can now use witness txs")
self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432
@@ -248,9 +240,54 @@ class SegWitTest(BitcoinTestFramework):
assert(tmpl['transactions'][0]['txid'] == txid)
assert(tmpl['transactions'][0]['sigops'] == 8)
- self.log.info("Non-segwit miners are not able to use GBT response after activation.")
- send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.998"))
- assert_raises_jsonrpc(-8, "Support for 'segwit' rule requires explicit client support", self.nodes[0].getblocktemplate, {})
+ self.nodes[0].generate(1) # Mine a block to clear the gbt cache
+
+ self.log.info("Non-segwit miners are able to use GBT response after activation.")
+ # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
+ # tx2 (segwit input, paying to a non-segwit output) ->
+ # tx3 (non-segwit input, paying to a non-segwit output).
+ # tx1 is allowed to appear in the block, but no others.
+ txid1 = send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996"))
+ hex_tx = self.nodes[0].gettransaction(txid)['hex']
+ tx = FromHex(CTransaction(), hex_tx)
+ assert(tx.wit.is_null()) # This should not be a segwit input
+ assert(txid1 in self.nodes[0].getrawmempool())
+
+ # Now create tx2, which will spend from txid1.
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
+ tx.vout.append(CTxOut(int(49.99*COIN), CScript([OP_TRUE])))
+ tx2_hex = self.nodes[0].signrawtransaction(ToHex(tx))['hex']
+ txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
+ tx = FromHex(CTransaction(), tx2_hex)
+ assert(not tx.wit.is_null())
+
+ # Now create tx3, which will spend from txid2
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
+ tx.vout.append(CTxOut(int(49.95*COIN), CScript([OP_TRUE]))) # Huge fee
+ tx.calc_sha256()
+ txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))
+ assert(tx.wit.is_null())
+ assert(txid3 in self.nodes[0].getrawmempool())
+
+ # Now try calling getblocktemplate() without segwit support.
+ template = self.nodes[0].getblocktemplate()
+
+ # Check that tx1 is the only transaction of the 3 in the template.
+ template_txids = [ t['txid'] for t in template['transactions'] ]
+ assert(txid2 not in template_txids and txid3 not in template_txids)
+ assert(txid1 in template_txids)
+
+ # Check that running with segwit support results in all 3 being included.
+ template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
+ template_txids = [ t['txid'] for t in template['transactions'] ]
+ assert(txid1 in template_txids)
+ assert(txid2 in template_txids)
+ assert(txid3 in template_txids)
+
+ # Mine a block to clear the gbt cache again.
+ self.nodes[0].generate(1)
self.log.info("Verify behaviour of importaddress, addwitnessaddress and listunspent")
@@ -410,10 +447,13 @@ class SegWitTest(BitcoinTestFramework):
importlist.append(bytes_to_hex_str(p2wshop1))
for i in importlist:
+ # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
+ # exceptions and continue.
try:
self.nodes[0].importaddress(i,"",False,True)
except JSONRPCException as exp:
assert_equal(exp.error["message"], "The wallet already contains the private key for this address or script")
+ assert_equal(exp.error["code"], -4)
self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only
self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey
@@ -428,12 +468,7 @@ class SegWitTest(BitcoinTestFramework):
# note that no witness address should be returned by unsolvable addresses
# the multisig_without_privkey_address will fail because its keys were not added with importpubkey
for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address + [multisig_without_privkey_address]:
- try:
- self.nodes[0].addwitnessaddress(i)
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], "Public key or redeemscript not known to wallet, or the key is uncompressed")
- else:
- assert(False)
+ assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i)
for i in compressed_spendable_address + compressed_solvable_address:
witaddress = self.nodes[0].addwitnessaddress(i)
@@ -512,12 +547,8 @@ class SegWitTest(BitcoinTestFramework):
# note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress
# premature_witaddress are not accepted until the script is added with addwitnessaddress first
for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress + [compressed_solvable_address[1]]:
- try:
- self.nodes[0].addwitnessaddress(i)
- except JSONRPCException as exp:
- assert_equal(exp.error["message"], "Public key or redeemscript not known to wallet, or the key is uncompressed")
- else:
- assert(False)
+ # This will raise an exception
+ assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i)
# after importaddress it should pass addwitnessaddress
v = self.nodes[0].validateaddress(compressed_solvable_address[1])
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index f7d692083c..49f2df5c37 100755
--- a/qa/rpc-tests/smartfees.py
+++ b/qa/rpc-tests/smartfees.py
@@ -7,15 +7,21 @@
from collections import OrderedDict
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+from test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_EQUAL, hash160, OP_TRUE
+from test_framework.mininode import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, FromHex, COIN
# Construct 2 trivial P2SH's and the ScriptSigs that spend them
# So we can create many many transactions without needing to spend
# time signing.
-P2SH_1 = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP"
-P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP"
+redeem_script_1 = CScript([OP_1, OP_DROP])
+redeem_script_2 = CScript([OP_2, OP_DROP])
+P2SH_1 = CScript([OP_HASH160, hash160(redeem_script_1), OP_EQUAL])
+P2SH_2 = CScript([OP_HASH160, hash160(redeem_script_2), OP_EQUAL])
+
# Associated ScriptSig's to spend satisfy P2SH_1 and P2SH_2
-# 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP"
-SCRIPT_SIG = ["0451025175", "0451025275"]
+SCRIPT_SIG = [CScript([OP_TRUE, redeem_script_1]), CScript([OP_TRUE, redeem_script_2])]
+
+global log
def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment):
"""
@@ -33,39 +39,30 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
rand_fee = float(fee_increment)*(1.1892**random.randint(0,28))
# Total fee ranges from min_fee to min_fee + 127*fee_increment
fee = min_fee - fee_increment + satoshi_round(rand_fee)
- inputs = []
+ tx = CTransaction()
total_in = Decimal("0.00000000")
while total_in <= (amount + fee) and len(conflist) > 0:
t = conflist.pop(0)
total_in += t["amount"]
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} )
+ tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b""))
if total_in <= amount + fee:
while total_in <= (amount + fee) and len(unconflist) > 0:
t = unconflist.pop(0)
total_in += t["amount"]
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} )
+ tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b""))
if total_in <= amount + fee:
raise RuntimeError("Insufficient funds: need %d, have %d"%(amount+fee, total_in))
- outputs = {}
- outputs = OrderedDict([(P2SH_1, total_in - amount - fee),
- (P2SH_2, amount)])
- rawtx = from_node.createrawtransaction(inputs, outputs)
- # createrawtransaction constructs a transaction that is ready to be signed.
- # These transactions don't need to be signed, but we still have to insert the ScriptSig
- # that will satisfy the ScriptPubKey.
- completetx = rawtx[0:10]
- inputnum = 0
- for inp in inputs:
- completetx += rawtx[10+82*inputnum:82+82*inputnum]
- completetx += SCRIPT_SIG[inp["vout"]]
- completetx += rawtx[84+82*inputnum:92+82*inputnum]
- inputnum += 1
- completetx += rawtx[10+82*inputnum:]
- txid = from_node.sendrawtransaction(completetx, True)
+ tx.vout.append(CTxOut(int((total_in - amount - fee)*COIN), P2SH_1))
+ tx.vout.append(CTxOut(int(amount*COIN), P2SH_2))
+ # These transactions don't need to be signed, but we still have to insert
+ # the ScriptSig that will satisfy the ScriptPubKey.
+ for inp in tx.vin:
+ inp.scriptSig = SCRIPT_SIG[inp.prevout.n]
+ txid = from_node.sendrawtransaction(ToHex(tx), True)
unconflist.append({ "txid" : txid, "vout" : 0 , "amount" : total_in - amount - fee})
unconflist.append({ "txid" : txid, "vout" : 1 , "amount" : amount})
- return (completetx, fee)
+ return (ToHex(tx), fee)
def split_inputs(from_node, txins, txouts, initial_split = False):
"""
@@ -76,18 +73,21 @@ def split_inputs(from_node, txins, txouts, initial_split = False):
a high coin age when the notion of priority still existed.
"""
prevtxout = txins.pop()
- inputs = []
- inputs.append({ "txid" : prevtxout["txid"], "vout" : prevtxout["vout"] })
+ tx = CTransaction()
+ tx.vin.append(CTxIn(COutPoint(int(prevtxout["txid"], 16), prevtxout["vout"]), b""))
+
half_change = satoshi_round(prevtxout["amount"]/2)
rem_change = prevtxout["amount"] - half_change - Decimal("0.00001000")
- outputs = OrderedDict([(P2SH_1, half_change), (P2SH_2, rem_change)])
- rawtx = from_node.createrawtransaction(inputs, outputs)
+ tx.vout.append(CTxOut(int(half_change*COIN), P2SH_1))
+ tx.vout.append(CTxOut(int(rem_change*COIN), P2SH_2))
+
# If this is the initial split we actually need to sign the transaction
- # Otherwise we just need to insert the property ScriptSig
+ # Otherwise we just need to insert the proper ScriptSig
if (initial_split) :
- completetx = from_node.signrawtransaction(rawtx)["hex"]
+ completetx = from_node.signrawtransaction(ToHex(tx))["hex"]
else :
- completetx = rawtx[0:82] + SCRIPT_SIG[prevtxout["vout"]] + rawtx[84:]
+ tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout["vout"]]
+ completetx = ToHex(tx)
txid = from_node.sendrawtransaction(completetx, True)
txouts.append({ "txid" : txid, "vout" : 0 , "amount" : half_change})
txouts.append({ "txid" : txid, "vout" : 1 , "amount" : rem_change})
@@ -99,7 +99,7 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
"""
all_estimates = [ node.estimatefee(i) for i in range(1,26) ]
if print_estimates:
- self.log.info([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]])
+ log.info([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]])
delta = 1.0e-6 # account for rounding error
last_e = max(fees_seen)
for e in [x for x in all_estimates if x >= 0]:
@@ -234,6 +234,9 @@ class EstimateFeeTest(BitcoinTestFramework):
self.memutxo = newmem
def run_test(self):
+ # Make log handler available to helper functions
+ global log
+ log = self.log
self.fees_per_kb = []
self.memutxo = []
self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 00fe37563b..80f74fa108 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -71,7 +71,7 @@ class WalletTest (BitcoinTestFramework):
unspent_0 = self.nodes[2].listunspent()[0]
unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
self.nodes[2].lockunspent(False, [unspent_0])
- assert_raises_message(JSONRPCException, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
+ assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
assert_equal([unspent_0], self.nodes[2].listlockunspent())
self.nodes[2].lockunspent(True, [unspent_0])
assert_equal(len(self.nodes[2].listlockunspent()), 0)
@@ -251,19 +251,11 @@ class WalletTest (BitcoinTestFramework):
txObj = self.nodes[0].gettransaction(txId)
assert_equal(txObj['amount'], Decimal('-0.0001'))
- try:
- txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4")
- except JSONRPCException as e:
- assert("Invalid amount" in e.error['message'])
- else:
- raise AssertionError("Must not parse invalid amounts")
+ # This will raise an exception because the amount type is wrong
+ assert_raises_jsonrpc(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4")
-
- try:
- self.nodes[0].generate("2")
- raise AssertionError("Must not accept strings as numeric")
- except JSONRPCException as e:
- assert("not an integer" in e.error['message'])
+ # This will raise an exception since generate does not accept a string
+ assert_raises_jsonrpc(-1, "not an integer", self.nodes[0].generate, "2")
# Import address and private key to check correct behavior of spendable unspents
# 1. Send some coins to generate new UTXO
@@ -394,7 +386,7 @@ class WalletTest (BitcoinTestFramework):
node0_balance = self.nodes[0].getbalance()
# With walletrejectlongchains we will not create the tx and store it in our wallet.
- assert_raises_message(JSONRPCException, "mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))
+ assert_raises_jsonrpc(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))
# Verify nothing new in wallet
assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999)))
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 8c699c2f8c..3bcecab596 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -25,7 +25,8 @@ bench_bench_bitcoin_SOURCES = \
bench/base58.cpp \
bench/lockedpool.cpp \
bench/perf.cpp \
- bench/perf.h
+ bench/perf.h \
+ bench/prevector_destructor.cpp
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index c3069e33bc..cfd08b8238 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -89,6 +89,7 @@ BITCOIN_TESTS =\
test/blockencodings_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
+ test/checkqueue_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 29fbd34631..06882f1514 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -20,7 +20,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<CO
CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx)));
int nAge = 6 * 24;
- COutput output(wtx, nInput, nAge, true, true);
+ COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
}
diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp
new file mode 100644
index 0000000000..55af3de4fe
--- /dev/null
+++ b/src/bench/prevector_destructor.cpp
@@ -0,0 +1,36 @@
+// Copyright (c) 2015-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.
+
+#include "bench.h"
+#include "prevector.h"
+
+static void PrevectorDestructor(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ for (auto x = 0; x < 1000; ++x) {
+ prevector<28, unsigned char> t0;
+ prevector<28, unsigned char> t1;
+ t0.resize(28);
+ t1.resize(29);
+ }
+ }
+}
+
+static void PrevectorClear(benchmark::State& state)
+{
+
+ while (state.KeepRunning()) {
+ for (auto x = 0; x < 1000; ++x) {
+ prevector<28, unsigned char> t0;
+ prevector<28, unsigned char> t1;
+ t0.resize(28);
+ t0.clear();
+ t1.resize(29);
+ t0.clear();
+ }
+ }
+}
+
+BENCHMARK(PrevectorDestructor);
+BENCHMARK(PrevectorClear);
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 32e25d5c8c..ea12df66dd 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -127,6 +127,9 @@ private:
}
public:
+ //! Mutex to ensure only one concurrent CCheckQueueControl
+ boost::mutex ControlMutex;
+
//! Create a new check queue
CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
@@ -161,12 +164,6 @@ public:
{
}
- bool IsIdle()
- {
- boost::unique_lock<boost::mutex> lock(mutex);
- return (nTotal == nIdle && nTodo == 0 && fAllOk == true);
- }
-
};
/**
@@ -177,16 +174,18 @@ template <typename T>
class CCheckQueueControl
{
private:
- CCheckQueue<T>* pqueue;
+ CCheckQueue<T> * const pqueue;
bool fDone;
public:
- CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false)
+ CCheckQueueControl() = delete;
+ CCheckQueueControl(const CCheckQueueControl&) = delete;
+ CCheckQueueControl& operator=(const CCheckQueueControl&) = delete;
+ explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false)
{
// passed queue is supposed to be unused, or NULL
if (pqueue != NULL) {
- bool isIdle = pqueue->IsIdle();
- assert(isIdle);
+ ENTER_CRITICAL_SECTION(pqueue->ControlMutex);
}
}
@@ -209,6 +208,9 @@ public:
{
if (!fDone)
Wait();
+ if (pqueue != NULL) {
+ LEAVE_CRITICAL_SECTION(pqueue->ControlMutex);
+ }
}
};
diff --git a/src/compat.h b/src/compat.h
index 28aa77eea2..e76ab94c82 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -47,10 +47,8 @@
#include <unistd.h>
#endif
-#ifdef WIN32
-#define MSG_DONTWAIT 0
-#else
-typedef u_int SOCKET;
+#ifndef WIN32
+typedef unsigned int SOCKET;
#include "errno.h"
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
@@ -74,11 +72,6 @@ typedef u_int SOCKET;
#define MAX_PATH 1024
#endif
-// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
-#define MSG_NOSIGNAL 0
-#endif
-
#if HAVE_DECL_STRNLEN == 0
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
diff --git a/src/miner.cpp b/src/miner.cpp
index 67e7ff155b..ff28a5680e 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -137,7 +137,7 @@ void BlockAssembler::resetBlock()
nFees = 0;
}
-std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
{
resetBlock();
@@ -175,7 +175,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// -promiscuousmempoolflags is used.
// TODO: replace this with a call to main to assess validity of a mempool
// transaction (which in most cases can be a no-op).
- fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus());
+ fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx;
addPackageTxs();
diff --git a/src/miner.h b/src/miner.h
index c105d07c23..a159b05534 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -170,7 +170,7 @@ public:
BlockAssembler(const CChainParams& params, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */
- std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true);
private:
// utility functions
diff --git a/src/net.cpp b/src/net.cpp
index 6ff63d4730..113823f0b4 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -44,10 +44,15 @@
// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+#if !defined(HAVE_MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
+// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0
+#if !defined(HAVE_MSG_DONTWAIT)
+#define MSG_DONTWAIT 0
+#endif
+
// Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h.
// Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version.
#ifdef WIN32
@@ -2319,9 +2324,17 @@ void CConnman::Interrupt()
interruptNet();
InterruptSocks5(true);
- if (semOutbound)
- for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++)
+ if (semOutbound) {
+ for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) {
semOutbound->post();
+ }
+ }
+
+ if (semAddnode) {
+ for (int i=0; i<nMaxAddnode; i++) {
+ semAddnode->post();
+ }
+ }
}
void CConnman::Stop()
@@ -2337,10 +2350,6 @@ void CConnman::Stop()
if (threadSocketHandler.joinable())
threadSocketHandler.join();
- if (semAddnode)
- for (int i=0; i<nMaxAddnode; i++)
- semOutbound->post();
-
if (fAddressesInitialized)
{
DumpData();
diff --git a/src/netbase.cpp b/src/netbase.cpp
index fc9a6ed0be..0f02e93e46 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -25,7 +25,7 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+#if !defined(HAVE_MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
diff --git a/src/pow.cpp b/src/pow.cpp
index e57fd866f8..e06d9662e6 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -12,12 +12,9 @@
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
+ assert(pindexLast != NULL);
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
- // Genesis block
- if (pindexLast == NULL)
- return nProofOfWorkLimit;
-
// Only change once per difficulty adjustment interval
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
{
diff --git a/src/prevector.h b/src/prevector.h
index cba2e30057..177d81383e 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -11,6 +11,7 @@
#include <string.h>
#include <iterator>
+#include <type_traits>
#pragma pack(push, 1)
/** Implements a drop-in replacement for std::vector<T> which stores up to N
@@ -388,10 +389,14 @@ public:
iterator erase(iterator first, iterator last) {
iterator p = first;
char* endp = (char*)&(*end());
- while (p != last) {
- (*p).~T();
- _size--;
- ++p;
+ if (!std::is_trivially_destructible<T>::value) {
+ while (p != last) {
+ (*p).~T();
+ _size--;
+ ++p;
+ }
+ } else {
+ _size -= last - p;
}
memmove(&(*first), &(*last), endp - ((char*)(&(*last))));
return first;
@@ -432,7 +437,9 @@ public:
}
~prevector() {
- clear();
+ if (!std::is_trivially_destructible<T>::value) {
+ clear();
+ }
if (!is_direct()) {
free(_union.indirect);
_union.indirect = NULL;
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index ca8ecffafe..f13b0d9cf9 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -760,10 +760,32 @@
</layout>
</item>
<item>
+ <widget class="QLabel" name="fallbackFeeWarningLabel">
+ <property name="toolTip">
+ <string>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain.</string>
+ </property>
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Warning: Fee estimation is currently not possible.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 1c0ed663c1..65ca007552 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -23,6 +23,7 @@
#include "txmempool.h"
#include "wallet/wallet.h"
+#include <QFontMetrics>
#include <QMessageBox>
#include <QScrollBar>
#include <QSettings>
@@ -656,6 +657,11 @@ void SendCoinsDialog::updateSmartFeeLabel()
std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...)
ui->labelFeeEstimation->setText("");
+ ui->fallbackFeeWarningLabel->setVisible(true);
+ int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness();
+ QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14));
+ ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }");
+ ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x"));
}
else
{
@@ -663,6 +669,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB");
ui->labelSmartFee2->hide();
ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks));
+ ui->fallbackFeeWarningLabel->setVisible(false);
}
updateFeeMinimizedLabel();
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 0a5a7c3e9f..878b7d58ae 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -580,7 +580,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true);
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
vOutputs.push_back(out);
}
}
@@ -607,7 +607,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
if (!wallet->mapWallet.count(outpoint.hash)) continue;
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true);
+ COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE)
vCoins.push_back(out);
}
@@ -619,7 +619,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
while (wallet->IsChange(cout.tx->tx->vout[cout.i]) && cout.tx->tx->vin.size() > 0 && wallet->IsMine(cout.tx->tx->vin[0]))
{
if (!wallet->mapWallet.count(cout.tx->tx->vin[0].prevout.hash)) break;
- cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0, true, true);
+ cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0 /* depth */, true /* spendable */, true /* solvable */, true /* safe */);
}
CTxDestination address;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index abdfa651ab..4db8ffaa7d 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -514,12 +514,22 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
+ const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
+ // If the caller is indicating segwit support, then allow CreateNewBlock()
+ // to select witness transactions, after segwit activates (otherwise
+ // don't).
+ bool fSupportsSegwit = setClientRules.find(segwit_info.name) != setClientRules.end();
+
// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
+ // Cache whether the last invocation was with segwit support, to avoid returning
+ // a segwit-block to a non-segwit caller.
+ static bool fLastTemplateSupportsSegwit = true;
if (pindexPrev != chainActive.Tip() ||
- (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
+ (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5) ||
+ fLastTemplateSupportsSegwit != fSupportsSegwit)
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = nullptr;
@@ -528,10 +538,11 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = chainActive.Tip();
nStart = GetTime();
+ fLastTemplateSupportsSegwit = fSupportsSegwit;
// Create new block
CScript scriptDummy = CScript() << OP_TRUE;
- pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy);
+ pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
@@ -681,8 +692,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
- const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT];
- if (!pblocktemplate->vchCoinbaseCommitment.empty() && setClientRules.find(segwit_info.name) != setClientRules.end()) {
+ if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) {
result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end())));
}
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
new file mode 100644
index 0000000000..d89f9b770b
--- /dev/null
+++ b/src/test/checkqueue_tests.cpp
@@ -0,0 +1,442 @@
+// Copyright (c) 2012-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.
+
+#include "util.h"
+#include "utiltime.h"
+#include "validation.h"
+
+#include "test/test_bitcoin.h"
+#include "checkqueue.h"
+#include <boost/test/unit_test.hpp>
+#include <boost/thread.hpp>
+#include <atomic>
+#include <thread>
+#include <vector>
+#include <mutex>
+#include <condition_variable>
+
+#include <unordered_set>
+#include <memory>
+#include "random.h"
+
+// BasicTestingSetup not sufficient because nScriptCheckThreads is not set
+// otherwise.
+BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup)
+
+static const int QUEUE_BATCH_SIZE = 128;
+
+struct FakeCheck {
+ bool operator()()
+ {
+ return true;
+ }
+ void swap(FakeCheck& x){};
+};
+
+struct FakeCheckCheckCompletion {
+ static std::atomic<size_t> n_calls;
+ bool operator()()
+ {
+ ++n_calls;
+ return true;
+ }
+ void swap(FakeCheckCheckCompletion& x){};
+};
+
+struct FailingCheck {
+ bool fails;
+ FailingCheck(bool fails) : fails(fails){};
+ FailingCheck() : fails(true){};
+ bool operator()()
+ {
+ return !fails;
+ }
+ void swap(FailingCheck& x)
+ {
+ std::swap(fails, x.fails);
+ };
+};
+
+struct UniqueCheck {
+ static std::mutex m;
+ static std::unordered_multiset<size_t> results;
+ size_t check_id;
+ UniqueCheck(size_t check_id_in) : check_id(check_id_in){};
+ UniqueCheck() : check_id(0){};
+ bool operator()()
+ {
+ std::lock_guard<std::mutex> l(m);
+ results.insert(check_id);
+ return true;
+ }
+ void swap(UniqueCheck& x) { std::swap(x.check_id, check_id); };
+};
+
+
+struct MemoryCheck {
+ static std::atomic<size_t> fake_allocated_memory;
+ bool b {false};
+ bool operator()()
+ {
+ return true;
+ }
+ MemoryCheck(){};
+ MemoryCheck(const MemoryCheck& x)
+ {
+ // We have to do this to make sure that destructor calls are paired
+ //
+ // Really, copy constructor should be deletable, but CCheckQueue breaks
+ // if it is deleted because of internal push_back.
+ fake_allocated_memory += b;
+ };
+ MemoryCheck(bool b_) : b(b_)
+ {
+ fake_allocated_memory += b;
+ };
+ ~MemoryCheck(){
+ fake_allocated_memory -= b;
+
+ };
+ void swap(MemoryCheck& x) { std::swap(b, x.b); };
+};
+
+struct FrozenCleanupCheck {
+ static std::atomic<uint64_t> nFrozen;
+ static std::condition_variable cv;
+ static std::mutex m;
+ // Freezing can't be the default initialized behavior given how the queue
+ // swaps in default initialized Checks.
+ bool should_freeze {false};
+ bool operator()()
+ {
+ return true;
+ }
+ FrozenCleanupCheck() {}
+ ~FrozenCleanupCheck()
+ {
+ if (should_freeze) {
+ std::unique_lock<std::mutex> l(m);
+ nFrozen = 1;
+ cv.notify_one();
+ cv.wait(l, []{ return nFrozen == 0;});
+ }
+ }
+ void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);};
+};
+
+// Static Allocations
+std::mutex FrozenCleanupCheck::m{};
+std::atomic<uint64_t> FrozenCleanupCheck::nFrozen{0};
+std::condition_variable FrozenCleanupCheck::cv{};
+std::mutex UniqueCheck::m;
+std::unordered_multiset<size_t> UniqueCheck::results;
+std::atomic<size_t> FakeCheckCheckCompletion::n_calls{0};
+std::atomic<size_t> MemoryCheck::fake_allocated_memory{0};
+
+// Queue Typedefs
+typedef CCheckQueue<FakeCheckCheckCompletion> Correct_Queue;
+typedef CCheckQueue<FakeCheck> Standard_Queue;
+typedef CCheckQueue<FailingCheck> Failing_Queue;
+typedef CCheckQueue<UniqueCheck> Unique_Queue;
+typedef CCheckQueue<MemoryCheck> Memory_Queue;
+typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;
+
+
+/** This test case checks that the CCheckQueue works properly
+ * with each specified size_t Checks pushed.
+ */
+void Correct_Queue_range(std::vector<size_t> range)
+{
+ auto small_queue = std::unique_ptr<Correct_Queue>(new Correct_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{small_queue->Thread();});
+ }
+ // Make vChecks here to save on malloc (this test can be slow...)
+ std::vector<FakeCheckCheckCompletion> vChecks;
+ for (auto i : range) {
+ size_t total = i;
+ FakeCheckCheckCompletion::n_calls = 0;
+ CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());
+ while (total) {
+ vChecks.resize(std::min(total, (size_t) GetRand(10)));
+ total -= vChecks.size();
+ control.Add(vChecks);
+ }
+ BOOST_REQUIRE(control.Wait());
+ if (FakeCheckCheckCompletion::n_calls != i) {
+ BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);
+ BOOST_TEST_MESSAGE("Failure on trial " << i << " expected, got " << FakeCheckCheckCompletion::n_calls);
+ }
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+/** Test that 0 checks is correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)
+{
+ std::vector<size_t> range;
+ range.push_back((size_t)0);
+ Correct_Queue_range(range);
+}
+/** Test that 1 check is correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One)
+{
+ std::vector<size_t> range;
+ range.push_back((size_t)1);
+ Correct_Queue_range(range);
+}
+/** Test that MAX check is correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max)
+{
+ std::vector<size_t> range;
+ range.push_back(100000);
+ Correct_Queue_range(range);
+}
+/** Test that random numbers of checks are correct
+ */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)
+{
+ std::vector<size_t> range;
+ range.reserve(100000/1000);
+ for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)GetRand(std::min((size_t)1000, ((size_t)100000) - i))))
+ range.push_back(i);
+ Correct_Queue_range(range);
+}
+
+
+/** Test that failing checks are caught */
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
+{
+ auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE});
+
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{fail_queue->Thread();});
+ }
+
+ for (size_t i = 0; i < 1001; ++i) {
+ CCheckQueueControl<FailingCheck> control(fail_queue.get());
+ size_t remaining = i;
+ while (remaining) {
+ size_t r = GetRand(10);
+
+ std::vector<FailingCheck> vChecks;
+ vChecks.reserve(r);
+ for (size_t k = 0; k < r && remaining; k++, remaining--)
+ vChecks.emplace_back(remaining == 1);
+ control.Add(vChecks);
+ }
+ bool success = control.Wait();
+ if (i > 0) {
+ BOOST_REQUIRE(!success);
+ } else if (i == 0) {
+ BOOST_REQUIRE(success);
+ }
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+// Test that a block validation which fails does not interfere with
+// future blocks, ie, the bad state is cleared.
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
+{
+ auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{fail_queue->Thread();});
+ }
+
+ for (auto times = 0; times < 10; ++times) {
+ for (bool end_fails : {true, false}) {
+ CCheckQueueControl<FailingCheck> control(fail_queue.get());
+ {
+ std::vector<FailingCheck> vChecks;
+ vChecks.resize(100, false);
+ vChecks[99] = end_fails;
+ control.Add(vChecks);
+ }
+ bool r =control.Wait();
+ BOOST_REQUIRE(r || end_fails);
+ }
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+// Test that unique checks are actually all called individually, rather than
+// just one check being called repeatedly. Test that checks are not called
+// more than once as well
+BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
+{
+ auto queue = std::unique_ptr<Unique_Queue>(new Unique_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{queue->Thread();});
+
+ }
+
+ size_t COUNT = 100000;
+ size_t total = COUNT;
+ {
+ CCheckQueueControl<UniqueCheck> control(queue.get());
+ while (total) {
+ size_t r = GetRand(10);
+ std::vector<UniqueCheck> vChecks;
+ for (size_t k = 0; k < r && total; k++)
+ vChecks.emplace_back(--total);
+ control.Add(vChecks);
+ }
+ }
+ bool r = true;
+ BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT);
+ for (size_t i = 0; i < COUNT; ++i)
+ r = r && UniqueCheck::results.count(i) == 1;
+ BOOST_REQUIRE(r);
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+
+// Test that blocks which might allocate lots of memory free their memory agressively.
+//
+// This test attempts to catch a pathological case where by lazily freeing
+// checks might mean leaving a check un-swapped out, and decreasing by 1 each
+// time could leave the data hanging across a sequence of blocks.
+BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
+{
+ auto queue = std::unique_ptr<Memory_Queue>(new Memory_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{queue->Thread();});
+ }
+ for (size_t i = 0; i < 1000; ++i) {
+ size_t total = i;
+ {
+ CCheckQueueControl<MemoryCheck> control(queue.get());
+ while (total) {
+ size_t r = GetRand(10);
+ std::vector<MemoryCheck> vChecks;
+ for (size_t k = 0; k < r && total; k++) {
+ total--;
+ // Each iteration leaves data at the front, back, and middle
+ // to catch any sort of deallocation failure
+ vChecks.emplace_back(total == 0 || total == i || total == i/2);
+ }
+ control.Add(vChecks);
+ }
+ }
+ BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0);
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+// Test that a new verification cannot occur until all checks
+// have been destructed
+BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
+{
+ auto queue = std::unique_ptr<FrozenCleanup_Queue>(new FrozenCleanup_Queue {QUEUE_BATCH_SIZE});
+ boost::thread_group tg;
+ bool fails = false;
+ for (auto x = 0; x < nScriptCheckThreads; ++x) {
+ tg.create_thread([&]{queue->Thread();});
+ }
+ std::thread t0([&]() {
+ CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
+ std::vector<FrozenCleanupCheck> vChecks(1);
+ // Freezing can't be the default initialized behavior given how the queue
+ // swaps in default initialized Checks (otherwise freezing destructor
+ // would get called twice).
+ vChecks[0].should_freeze = true;
+ control.Add(vChecks);
+ control.Wait(); // Hangs here
+ });
+ {
+ std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
+ // Wait until the queue has finished all jobs and frozen
+ FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;});
+ // Try to get control of the queue a bunch of times
+ for (auto x = 0; x < 100 && !fails; ++x) {
+ fails = queue->ControlMutex.try_lock();
+ }
+ // Unfreeze
+ FrozenCleanupCheck::nFrozen = 0;
+ }
+ // Awaken frozen destructor
+ FrozenCleanupCheck::cv.notify_one();
+ // Wait for control to finish
+ t0.join();
+ tg.interrupt_all();
+ tg.join_all();
+ BOOST_REQUIRE(!fails);
+}
+
+
+/** Test that CCheckQueueControl is threadsafe */
+BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
+{
+ auto queue = std::unique_ptr<Standard_Queue>(new Standard_Queue{QUEUE_BATCH_SIZE});
+ {
+ boost::thread_group tg;
+ std::atomic<int> nThreads {0};
+ std::atomic<int> fails {0};
+ for (size_t i = 0; i < 3; ++i) {
+ tg.create_thread(
+ [&]{
+ CCheckQueueControl<FakeCheck> control(queue.get());
+ // While sleeping, no other thread should execute to this point
+ auto observed = ++nThreads;
+ MilliSleep(10);
+ fails += observed != nThreads;
+ });
+ }
+ tg.join_all();
+ BOOST_REQUIRE_EQUAL(fails, 0);
+ }
+ {
+ boost::thread_group tg;
+ std::mutex m;
+ bool has_lock {false};
+ bool has_tried {false};
+ bool done {false};
+ bool done_ack {false};
+ std::condition_variable cv;
+ {
+ std::unique_lock<std::mutex> l(m);
+ tg.create_thread([&]{
+ CCheckQueueControl<FakeCheck> control(queue.get());
+ std::unique_lock<std::mutex> l(m);
+ has_lock = true;
+ cv.notify_one();
+ cv.wait(l, [&]{return has_tried;});
+ done = true;
+ cv.notify_one();
+ // Wait until the done is acknowledged
+ //
+ cv.wait(l, [&]{return done_ack;});
+ });
+ // Wait for thread to get the lock
+ cv.wait(l, [&](){return has_lock;});
+ bool fails = false;
+ for (auto x = 0; x < 100 && !fails; ++x) {
+ fails = queue->ControlMutex.try_lock();
+ }
+ has_tried = true;
+ cv.notify_one();
+ cv.wait(l, [&](){return done;});
+ // Acknowledge the done
+ done_ack = true;
+ cv.notify_one();
+ BOOST_REQUIRE(!fails);
+ }
+ tg.join_all();
+ }
+}
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 17f0360c42..5022d46809 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -123,7 +123,7 @@ namespace tinyformat {}
namespace tfm = tinyformat;
// Error handling; calls assert() by default.
-#define TINYFORMAT_ERROR(reasonString) throw std::runtime_error(reasonString)
+#define TINYFORMAT_ERROR(reasonString) throw tinyformat::format_error(reasonString)
// Define for C++11 variadic templates which make the code shorter & more
// general. If you don't define this, C++11 support is autodetected below.
@@ -164,6 +164,13 @@ namespace tfm = tinyformat;
namespace tinyformat {
+class format_error: public std::runtime_error
+{
+public:
+ format_error(const std::string &what): std::runtime_error(what) {
+ }
+};
+
//------------------------------------------------------------------------------
namespace detail {
diff --git a/src/util.h b/src/util.h
index e27ce121c8..61dc0d366c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -73,14 +73,24 @@ bool LogAcceptCategory(const char* category);
/** Send a string to the log output */
int LogPrintStr(const std::string &str);
-#define LogPrint(category, ...) do { \
- if (LogAcceptCategory((category))) { \
- LogPrintStr(tfm::format(__VA_ARGS__)); \
+/** Get format string from VA_ARGS for error reporting */
+template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
+
+#define LogPrintf(...) do { \
+ std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
+ try { \
+ _log_msg_ = tfm::format(__VA_ARGS__); \
+ } catch (tinyformat::format_error &fmterr) { \
+ /* Original format string will have newline so don't add one here */ \
+ _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \
} \
+ LogPrintStr(_log_msg_); \
} while(0)
-#define LogPrintf(...) do { \
- LogPrintStr(tfm::format(__VA_ARGS__)); \
+#define LogPrint(category, ...) do { \
+ if (LogAcceptCategory((category))) { \
+ LogPrintf(__VA_ARGS__); \
+ } \
} while(0)
template<typename... Args>
diff --git a/src/validation.cpp b/src/validation.cpp
index 63918a3f30..be82026b3c 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1714,7 +1714,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
{
AssertLockHeld(cs_main);
-
+ assert(pindex);
+ // pindex->phashBlock can be null if called by CreateNewBlock/TestBlockValidity
+ assert((pindex->phashBlock == NULL) ||
+ (*pindex->phashBlock == block.GetHash()));
int64_t nTimeStart = GetTimeMicros();
// Check it again in case a previous version let a bad block in
@@ -2948,7 +2951,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
{
- const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
+ assert(pindexPrev != NULL);
+ const int nHeight = pindexPrev->nHeight + 1;
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index d73f340510..8a7cce7485 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -17,7 +17,7 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION
},
{
/*.name =*/ "segwit",
- /*.gbt_force =*/ false,
+ /*.gbt_force =*/ true,
}
};
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 7d5cb930a9..84e7eb60d7 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -2506,9 +2506,7 @@ UniValue listunspent(const JSONRPCRequest& request)
" ,...\n"
" ]\n"
"4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n"
- " because they come from unconfirmed untrusted transactions or unconfirmed\n"
- " replacement transactions (cases where we are less sure that a conflicting\n"
- " transaction won't be mined).\n"
+ " See description of \"safe\" attribute below.\n"
"\nResult\n"
"[ (array of json object)\n"
" {\n"
@@ -2521,7 +2519,10 @@ UniValue listunspent(const JSONRPCRequest& request)
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\n"
" \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
- " \"solvable\" : xxx (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
+ " \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
+ " \"safe\" : xxx (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
+ " from outside keys and unconfirmed replacement transactions are considered unsafe\n"
+ " and are not eligible for spending by fundrawtransaction and sendtoaddress.\n"
" }\n"
" ,...\n"
"]\n"
@@ -2606,6 +2607,7 @@ UniValue listunspent(const JSONRPCRequest& request)
entry.push_back(Pair("confirmations", out.nDepth));
entry.push_back(Pair("spendable", out.fSpendable));
entry.push_back(Pair("solvable", out.fSolvable));
+ entry.push_back(Pair("safe", out.fSafe));
results.push_back(entry);
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c94491ca21..67e5e90224 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -54,7 +54,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
wtx->fDebitCached = true;
wtx->nDebitCached = 1;
}
- COutput output(wtx.get(), nInput, nAge, true, true);
+ COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
wtxn.emplace_back(std::move(wtx));
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 965fba67fc..9e3c8be3f2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1946,7 +1946,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
return nTotal;
}
-void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const
+void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue) const
{
vCoins.clear();
@@ -1960,9 +1960,6 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
if (!CheckFinalTx(*pcoin))
continue;
- if (fOnlyConfirmed && !pcoin->IsTrusted())
- continue;
-
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
@@ -1975,6 +1972,8 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
if (nDepth == 0 && !pcoin->InMempool())
continue;
+ bool safeTx = pcoin->IsTrusted();
+
// We should not consider coins from transactions that are replacing
// other transactions.
//
@@ -1990,8 +1989,8 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
// be a 1-block reorg away from the chain where transactions A and C
// were accepted to another chain where B, B', and C were all
// accepted.
- if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaces_txid")) {
- continue;
+ if (nDepth == 0 && pcoin->mapValue.count("replaces_txid")) {
+ safeTx = false;
}
// Similarly, we should not consider coins from transactions that
@@ -2002,7 +2001,11 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
// intending to replace A', but potentially resulting in a scenario
// where A, A', and D could all be accepted (instead of just B and
// D, or just A and A' like the user would want).
- if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaced_by_txid")) {
+ if (nDepth == 0 && pcoin->mapValue.count("replaced_by_txid")) {
+ safeTx = false;
+ }
+
+ if (fOnlySafe && !safeTx) {
continue;
}
@@ -2014,7 +2017,7 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed,
vCoins.push_back(COutput(pcoin, i, nDepth,
((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
(coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO),
- (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO));
+ (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, safeTx));
}
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index cae92a0b09..ae4321eef8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -466,12 +466,23 @@ public:
const CWalletTx *tx;
int i;
int nDepth;
+
+ /** Whether we have the private keys to spend this output */
bool fSpendable;
+
+ /** Whether we know how to spend this output, ignoring the lack of keys */
bool fSolvable;
- COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn)
+ /**
+ * Whether this output is considered safe to spend. Unconfirmed transactions
+ * from outside keys and unconfirmed replacement transactions are considered
+ * unsafe and will not be used to fund new spending transactions.
+ */
+ bool fSafe;
+
+ COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn)
{
- tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn;
+ tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn;
}
std::string ToString() const;
@@ -714,6 +725,7 @@ public:
nLastResend = 0;
nTimeFirstKey = 0;
fBroadcastTransactions = false;
+ nRelockTime = 0;
}
std::map<uint256, CWalletTx> mapWallet;
@@ -740,7 +752,7 @@ public:
/**
* populate vCoins with vector of available COutputs.
*/
- void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const;
+ void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const;
/**
* Shuffle and select coins until nTargetValue is reached while avoiding