aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-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/release-process.md33
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py4
-rwxr-xr-xqa/rpc-tests/listtransactions.py4
-rw-r--r--src/Makefile.bench.include3
-rw-r--r--src/bench/coin_selection.cpp2
-rw-r--r--src/bench/prevector_destructor.cpp36
-rw-r--r--src/net.cpp16
-rw-r--r--src/pow.cpp5
-rw-r--r--src/prevector.h17
-rw-r--r--src/qt/walletmodel.cpp6
-rw-r--r--src/tinyformat.h9
-rw-r--r--src/util.h20
-rw-r--r--src/validation.cpp8
-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.h17
26 files changed, 412 insertions, 122 deletions
diff --git a/.travis.yml b/.travis.yml
index ce6cdc2db0..8d20a7e1bb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,7 +51,7 @@ before_script:
- if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS
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/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/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/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/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/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/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/net.cpp b/src/net.cpp
index 6ff63d4730..4434793c4c 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2319,9 +2319,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 +2345,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/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/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/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..87eb16c91b 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 &e) { \
+ /* Original format string will have newline so don't add one here */ \
+ _log_msg_ = "Error \"" + std::string(e.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/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..80201e8ce0 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;
@@ -740,7 +751,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