aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml6
-rw-r--r--configure.ac9
-rw-r--r--contrib/debian/examples/bitcoin.conf7
-rwxr-xr-xcontrib/devtools/check-doc.py2
-rwxr-xr-xcontrib/devtools/github-merge.py68
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml9
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh2
-rwxr-xr-xcontrib/verify-commits/gpg.sh40
-rw-r--r--contrib/verify-commits/trusted-keys4
-rw-r--r--contrib/verify-commits/trusted-sha512-root-commit1
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh149
-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-notes.md49
-rw-r--r--doc/release-notes/release-notes-0.14.0.md873
-rw-r--r--doc/release-process.md33
-rwxr-xr-xqa/rpc-tests/abandonconflict.py17
-rwxr-xr-xqa/rpc-tests/assumevalid.py6
-rwxr-xr-xqa/rpc-tests/bip65-cltv-p2p.py2
-rwxr-xr-xqa/rpc-tests/bip65-cltv.py8
-rwxr-xr-xqa/rpc-tests/bip68-112-113-p2p.py2
-rwxr-xr-xqa/rpc-tests/bip68-sequence.py85
-rwxr-xr-xqa/rpc-tests/bip9-softforks.py2
-rwxr-xr-xqa/rpc-tests/bipdersig-p2p.py2
-rwxr-xr-xqa/rpc-tests/bipdersig.py8
-rwxr-xr-xqa/rpc-tests/blockchain.py6
-rwxr-xr-xqa/rpc-tests/bumpfee.py28
-rwxr-xr-xqa/rpc-tests/disablewallet.py17
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py42
-rwxr-xr-xqa/rpc-tests/getblocktemplate_longpoll.py6
-rwxr-xr-xqa/rpc-tests/getblocktemplate_proposals.py4
-rwxr-xr-xqa/rpc-tests/import-rescan.py18
-rwxr-xr-xqa/rpc-tests/importmulti.py42
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py16
-rwxr-xr-xqa/rpc-tests/invalidateblock.py34
-rwxr-xr-xqa/rpc-tests/keypool.py18
-rwxr-xr-xqa/rpc-tests/listsinceblock.py2
-rwxr-xr-xqa/rpc-tests/listtransactions.py4
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py8
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py18
-rwxr-xr-xqa/rpc-tests/mempool_limit.py2
-rwxr-xr-xqa/rpc-tests/mempool_packages.py37
-rwxr-xr-xqa/rpc-tests/mempool_reorg.py18
-rwxr-xr-xqa/rpc-tests/mempool_resurrect_test.py2
-rwxr-xr-xqa/rpc-tests/mempool_spendcoinbase.py4
-rwxr-xr-xqa/rpc-tests/merkle_blocks.py10
-rwxr-xr-xqa/rpc-tests/nodehandling.py14
-rwxr-xr-xqa/rpc-tests/nulldummy.py41
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py46
-rwxr-xr-xqa/rpc-tests/p2p-compactblocks.py50
-rwxr-xr-xqa/rpc-tests/p2p-feefilter.py4
-rwxr-xr-xqa/rpc-tests/p2p-leaktests.py4
-rwxr-xr-xqa/rpc-tests/p2p-mempool.py2
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py73
-rwxr-xr-xqa/rpc-tests/p2p-timeouts.py3
-rwxr-xr-xqa/rpc-tests/p2p-versionbits-warning.py2
-rwxr-xr-xqa/rpc-tests/preciousblock.py33
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py48
-rwxr-xr-xqa/rpc-tests/proxy_test.py8
-rwxr-xr-xqa/rpc-tests/pruning.py121
-rwxr-xr-xqa/rpc-tests/rawtransactions.py21
-rwxr-xr-xqa/rpc-tests/reindex.py4
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py135
-rwxr-xr-xqa/rpc-tests/rest.py2
-rwxr-xr-xqa/rpc-tests/rpcbind_test.py8
-rwxr-xr-xqa/rpc-tests/segwit.py234
-rwxr-xr-xqa/rpc-tests/sendheaders.py22
-rwxr-xr-xqa/rpc-tests/smartfees.py96
-rw-r--r--qa/rpc-tests/test_framework/blockstore.py6
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py19
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py28
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py68
-rw-r--r--qa/rpc-tests/test_framework/util.py106
-rwxr-xr-xqa/rpc-tests/wallet-hd.py9
-rwxr-xr-xqa/rpc-tests/wallet.py24
-rwxr-xr-xqa/rpc-tests/walletbackup.py16
-rwxr-xr-xqa/rpc-tests/zapwallettxes.py2
-rwxr-xr-xqa/rpc-tests/zmq_test.py2
-rw-r--r--src/Makefile.bench.include3
-rw-r--r--src/Makefile.qttest.include22
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/bench/bench.cpp2
-rw-r--r--src/bench/coin_selection.cpp2
-rw-r--r--src/bench/mempool_eviction.cpp7
-rw-r--r--src/bench/prevector_destructor.cpp36
-rw-r--r--src/bloom.cpp4
-rw-r--r--src/chain.h14
-rw-r--r--src/checkqueue.h22
-rw-r--r--src/coins.cpp19
-rw-r--r--src/coins.h7
-rw-r--r--src/compat.h11
-rw-r--r--src/init.cpp14
-rw-r--r--src/miner.cpp163
-rw-r--r--src/miner.h14
-rw-r--r--src/net.cpp25
-rw-r--r--src/net_processing.cpp7
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/policy/fees.cpp28
-rw-r--r--src/policy/fees.h26
-rw-r--r--src/policy/policy.h2
-rw-r--r--src/pow.cpp5
-rw-r--r--src/prevector.h17
-rw-r--r--src/primitives/transaction.cpp29
-rw-r--r--src/primitives/transaction.h6
-rw-r--r--src/qt/coincontroldialog.cpp20
-rw-r--r--src/qt/forms/debugwindow.ui2
-rw-r--r--src/qt/forms/sendcoinsdialog.ui36
-rw-r--r--src/qt/sendcoinsdialog.cpp17
-rw-r--r--src/qt/test/rpcnestedtests.cpp4
-rw-r--r--src/qt/test/test_main.cpp40
-rw-r--r--src/qt/test/wallettests.cpp104
-rw-r--r--src/qt/test/wallettests.h15
-rw-r--r--src/qt/walletmodel.cpp11
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/rpc/blockchain.cpp80
-rw-r--r--src/rpc/client.cpp9
-rw-r--r--src/rpc/mining.cpp126
-rw-r--r--src/rpc/misc.cpp60
-rw-r--r--src/rpc/net.cpp46
-rw-r--r--src/rpc/protocol.cpp8
-rw-r--r--src/rpc/protocol.h6
-rw-r--r--src/rpc/rawtransaction.cpp74
-rw-r--r--src/rpc/server.cpp63
-rw-r--r--src/scheduler.cpp12
-rw-r--r--src/scheduler.h9
-rw-r--r--src/script/interpreter.cpp26
-rw-r--r--src/script/ismine.cpp10
-rw-r--r--src/script/script.cpp4
-rw-r--r--src/script/sign.cpp28
-rw-r--r--src/script/standard.cpp24
-rw-r--r--src/test/bctest.py12
-rw-r--r--src/test/blockencodings_tests.cpp8
-rw-r--r--src/test/checkqueue_tests.cpp442
-rw-r--r--src/test/mempool_tests.cpp51
-rw-r--r--src/test/miner_tests.cpp4
-rw-r--r--src/test/policyestimator_tests.cpp12
-rw-r--r--src/test/test_bitcoin.cpp41
-rw-r--r--src/test/test_bitcoin.h9
-rw-r--r--src/test/test_bitcoin_main.cpp26
-rw-r--r--src/test/transaction_tests.cpp4
-rw-r--r--src/test/util_tests.cpp2
-rw-r--r--src/tinyformat.h9
-rw-r--r--src/txmempool.cpp61
-rw-r--r--src/txmempool.h54
-rw-r--r--src/util.cpp40
-rw-r--r--src/util.h20
-rw-r--r--src/utilmoneystr.cpp8
-rw-r--r--src/utilstrencodings.cpp50
-rw-r--r--src/utiltime.cpp2
-rw-r--r--src/validation.cpp56
-rw-r--r--src/validation.h2
-rw-r--r--src/versionbits.cpp2
-rw-r--r--src/wallet/coincontrol.h4
-rw-r--r--src/wallet/db.cpp198
-rw-r--r--src/wallet/db.h11
-rw-r--r--src/wallet/rpcdump.cpp72
-rw-r--r--src/wallet/rpcwallet.cpp276
-rw-r--r--src/wallet/test/wallet_tests.cpp65
-rw-r--r--src/wallet/wallet.cpp441
-rw-r--r--src/wallet/wallet.h73
-rw-r--r--src/wallet/walletdb.cpp255
-rw-r--r--src/wallet/walletdb.h17
165 files changed, 4111 insertions, 2653 deletions
diff --git a/.travis.yml b/.travis.yml
index ce6cdc2db0..ba250ec83b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,7 +32,7 @@ env:
# bitcoind
- HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER"
# No wallet
- - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
+ - HOST=x86_64-unknown-linux-gnu PACKAGES="python3 xvfb" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
# Cross-Mac
- HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy"
@@ -50,8 +50,10 @@ before_script:
- if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- 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
+ # 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/debian/examples/bitcoin.conf b/contrib/debian/examples/bitcoin.conf
index afbc7882e0..923ab75314 100644
--- a/contrib/debian/examples/bitcoin.conf
+++ b/contrib/debian/examples/bitcoin.conf
@@ -116,12 +116,7 @@
# running on another host using this option:
#rpcconnect=127.0.0.1
-# Transaction Fee Changes in 0.10.0
-
-# Send transactions as zero-fee transactions if possible (default: 0)
-#sendfreetransactions=0
-
-# Create transactions that have enough fees (or priority) so they are likely to begin confirmation within n blocks (default: 1).
+# Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6).
# This setting is over-ridden by the -paytxfee option.
#txconfirmtarget=n
diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py
index 249214e931..445175ec2b 100755
--- a/contrib/devtools/check-doc.py
+++ b/contrib/devtools/check-doc.py
@@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO
REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"')
REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")')
# list unsupported, deprecated and duplicate args as they need no documentation
-SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize'])
+SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions'])
def main():
used = check_output(CMD_GREP_ARGS, shell=True)
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index bb6ffb0253..3fee39143d 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -70,24 +70,61 @@ def ask_prompt(text):
print("",file=stderr)
return reply
-def tree_sha512sum():
- files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', '--name-only', 'HEAD']).splitlines())
+def get_symlink_files():
+ files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', 'HEAD']).splitlines())
+ ret = []
+ for f in files:
+ if (int(f.decode('utf-8').split(" ")[0], 8) & 0o170000) == 0o120000:
+ ret.append(f.decode('utf-8').split("\t")[1])
+ return ret
+
+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()
@@ -200,6 +237,12 @@ def main():
print("ERROR: Creating merge failed (already merged?).",file=stderr)
exit(4)
+ symlink_files = get_symlink_files()
+ for f in symlink_files:
+ print("ERROR: File %s was a symlink" % f)
+ if len(symlink_files) > 0:
+ exit(4)
+
# Put tree SHA512 into the message
try:
first_sha512 = tree_sha512sum()
@@ -212,10 +255,6 @@ def main():
except subprocess.CalledProcessError as e:
printf("ERROR: Cannot update message.",file=stderr)
exit(4)
- second_sha512 = tree_sha512sum()
- if first_sha512 != second_sha512:
- print("ERROR: Tree hash changed unexpectedly",file=stderr)
- exit(4)
print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
@@ -258,6 +297,11 @@ def main():
print("ERROR: Merge rejected.",file=stderr)
exit(7)
+ second_sha512 = tree_sha512sum()
+ if first_sha512 != second_sha512:
+ print("ERROR: Tree hash changed unexpectedly",file=stderr)
+ exit(8)
+
# Sign the merge commit.
reply = ask_prompt("Type 's' to sign off on the merge.")
if reply == 's':
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/gpg.sh b/contrib/verify-commits/gpg.sh
index 09ff237544..b01e2a6d39 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -8,21 +8,43 @@ VALID=false
REVSIG=false
IFS='
'
-for LINE in $(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null); do
+if [ "$BITCOIN_VERIFY_COMMITS_ALLOW_SHA1" = 1 ]; then
+ GPG_RES="$(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+else
+ # Note how we've disabled SHA1 with the --weak-digest option, disabling
+ # signatures - including selfsigs - that use SHA1. While you might think that
+ # collision attacks shouldn't be an issue as they'd be an attack on yourself,
+ # in fact because what's being signed is a commit object that's
+ # semi-deterministically generated by untrusted input (the pull-req) in theory
+ # an attacker could construct a pull-req that results in a commit object that
+ # they've created a collision for. Not the most likely attack, but preventing
+ # it is pretty easy so we do so as a "belt-and-suspenders" measure.
+ GPG_RES=""
+ for LINE in "$(gpg --version)"; do
+ case "$LINE" in
+ "gpg (GnuPG) 1.4.1"*|"gpg (GnuPG) 2.0."*)
+ echo "Please upgrade to at least gpg 2.1.10 to check for weak signatures" > /dev/stderr
+ GPG_RES="$(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null)"
+ ;;
+ # We assume if you're running 2.1+, you're probably running 2.1.10+
+ # gpg will fail otherwise
+ # We assume if you're running 1.X, it is either 1.4.1X or 1.4.20+
+ # gpg will fail otherwise
+ esac
+ done
+ [ "$GPG_RES" = "" ] && GPG_RES="$(echo "$INPUT" | gpg --trust-model always --weak-digest sha1 "$@" 2>/dev/null)"
+fi
+for LINE in $(echo "$GPG_RES"); do
case "$LINE" in
"[GNUPG:] VALIDSIG "*)
while read KEY; do
- case "$LINE" in "[GNUPG:] VALIDSIG $KEY "*) VALID=true;; esac
+ [ "${LINE#?GNUPG:? VALIDSIG * * * * * * * * * }" = "$KEY" ] && VALID=true
done < ./contrib/verify-commits/trusted-keys
;;
"[GNUPG:] REVKEYSIG "*)
[ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
- while read KEY; do
- case "$LINE" in "[GNUPG:] REVKEYSIG ${KEY#????????????????????????} "*)
- REVSIG=true
- GOODREVSIG="[GNUPG:] GOODSIG ${KEY#????????????????????????} "
- esac
- done < ./contrib/verify-commits/trusted-keys
+ REVSIG=true
+ GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
;;
esac
done
@@ -30,7 +52,7 @@ if ! $VALID; then
exit 1
fi
if $VALID && $REVSIG; then
- echo "$INPUT" | gpg --trust-model always "$@" | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" 2>/dev/null
+ echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)"
echo "$GOODREVSIG"
else
echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index 75242c2a97..5610692616 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -1,4 +1,4 @@
71A3B16735405025D447E8F274810B012346C9A6
-3F1888C6DCA92A6499C4911FDBA1A67379A1A931
+133EAC179436F14A5CF1B794860FEB804E669320
32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC
-FE09B823E6D83A3BC7983EAA2D7F2372E50FE137
+B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
diff --git a/contrib/verify-commits/trusted-sha512-root-commit b/contrib/verify-commits/trusted-sha512-root-commit
new file mode 100644
index 0000000000..7d41f90ad7
--- /dev/null
+++ b/contrib/verify-commits/trusted-sha512-root-commit
@@ -0,0 +1 @@
+309bf16257b2395ce502017be627186b749ee749
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
index b2cebdf1a0..74b7f38375 100755
--- a/contrib/verify-commits/verify-commits.sh
+++ b/contrib/verify-commits/verify-commits.sh
@@ -3,61 +3,130 @@
# 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")
+echo "Using verify-commits data from ${DIR}"
+
VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root")
+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
+
+ 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
+ VERIFY_TREE=0
+ NO_SHA1=0
fi
- if [ "${REVSIG_ALLOWED#*$1}" != "$REVSIG_ALLOWED" ]; then
+
+ if [ "$NO_SHA1" = "1" ]; then
+ export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=0
+ else
+ export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=1
+ fi
+
+ 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 2>&1; then
- return 1;
- fi
- local PARENTS
- PARENTS=$(git show -s --format=format:%P $1)
- for PARENT in $PARENTS; do
- if IS_SIGNED $PARENT; then
- return 0;
+
+ 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
- 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
+ exit 1
fi
- return 1;
-}
-if [ x"$1" = "x" ]; then
- TEST_COMMIT="HEAD"
-else
- TEST_COMMIT="$1"
-fi
+ # 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 "$CURRENT_COMMIT"); do
+ case "$LINE" in
+ "12"*)
+ echo "Repo contains symlinks" > /dev/stderr
+ IFS="$IFS_CACHE"
+ exit 1
+ ;;
+ esac
+ done
+ IFS="$IFS_CACHE"
+
+ FILE_HASHES=""
+ 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 "$CURRENT_COMMIT" | tail -n1)"
-IS_SIGNED "$TEST_COMMIT"
-RES=$?
-if [ "$RES" = 1 ]; then
- if ! "$HAVE_FAILED"; then
- echo "$TEST_COMMIT was not signed with a trusted key!"
+ case "$MSG -" in
+ "Tree-SHA512: $TREE_HASH")
+ HASH_MATCHES=1;;
+ esac
+
+ if [ "$HASH_MATCHES" = "0" ]; then
+ echo "Tree-SHA512 did not match for commit $CURRENT_COMMIT" > /dev/stderr
+ exit 1
+ fi
fi
-else
- echo "There is a valid path from $TEST_COMMIT to $VERIFIED_ROOT where all commits are signed!"
-fi
-exit $RES
+ PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT")
+ for PARENT in $PARENTS; do
+ PREV_COMMIT="$CURRENT_COMMIT"
+ CURRENT_COMMIT="$PARENT"
+ break
+ done
+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-notes.md b/doc/release-notes.md
index eaa0b330eb..af792118d6 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -33,6 +33,55 @@ frequently tested on them.
Notable changes
===============
+Low-level RPC changes
+---------------------
+
+- Error codes have been updated to be more accurate for the following error cases:
+ - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for
+ example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR.
+ - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned
+ because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND.
+ - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned
+ because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR.
+ - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned
+ because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR.
+ - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address
+ or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED.
+ - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban
+ a node that has not previously been banned. Previously returned RPC_MISC_ERROR.
+ - `removeprunedfunds` now returns RPC_WALLET_ERROR if bitcoind is unable to remove
+ the transaction. Previously returned RPC_INTERNAL_ERROR.
+ - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not
+ exist in the wallet. Previously returned RPC_INTERNAL_ERROR.
+ - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change
+ address is provided. Previously returned RPC_INVALID_PARAMETER.
+ - `fundrawtransaction` now returns RPC_WALLET_ERROR if bitcoind is unable to create
+ the transaction. The error message provides further details. Previously returned
+ RPC_INTERNAL_ERROR.
+ - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has
+ descendants in the wallet. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has
+ descendants in the mempool. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has
+ has been mined or conflicts with a mined transaction. Previously returned
+ RPC_INVALID_ADDRESS_OR_KEY.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not
+ BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already
+ been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains
+ inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change
+ outputs. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change
+ output. Previously returned RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned
+ RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned
+ RPC_MISC_ERROR.
+ - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the
+ fee. Previously returned RPC_MISC_ERROR.
+
Credits
=======
diff --git a/doc/release-notes/release-notes-0.14.0.md b/doc/release-notes/release-notes-0.14.0.md
new file mode 100644
index 0000000000..c41f22979b
--- /dev/null
+++ b/doc/release-notes/release-notes-0.14.0.md
@@ -0,0 +1,873 @@
+Bitcoin Core version 0.14.0 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.14.0/>
+
+This is a new major version release, including new features, various bugfixes
+and performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later.
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+No attempt is made to prevent installing or running the software on Windows XP, you
+can still do so at your own risk but be aware that there are known instabilities and issues.
+Please do not report issues about Windows XP to the issue tracker.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+Notable changes
+===============
+
+Performance Improvements
+--------------
+
+Validation speed and network propagation performance have been greatly
+improved, leading to much shorter sync and initial block download times.
+
+- The script signature cache has been reimplemented as a "cuckoo cache",
+ allowing for more signatures to be cached and faster lookups.
+- Assumed-valid blocks have been introduced which allows script validation to
+ be skipped for ancestors of known-good blocks, without changing the security
+ model. See below for more details.
+- In some cases, compact blocks are now relayed before being fully validated as
+ per BIP152.
+- P2P networking has been refactored with a focus on concurrency and
+ throughput. Network operations are no longer bottlenecked by validation. As a
+ result, block fetching is several times faster than previous releases in many
+ cases.
+- The UTXO cache now claims unused mempool memory. This speeds up initial block
+ download as UTXO lookups are a major bottleneck there, and there is no use for
+ the mempool at that stage.
+
+
+Manual Pruning
+--------------
+
+Bitcoin Core has supported automatically pruning the blockchain since 0.11. Pruning
+the blockchain allows for significant storage space savings as the vast majority of
+the downloaded data can be discarded after processing so very little of it remains
+on the disk.
+
+Manual block pruning can now be enabled by setting `-prune=1`. Once that is set,
+the RPC command `pruneblockchain` can be used to prune the blockchain up to the
+specified height or timestamp.
+
+`getinfo` Deprecated
+--------------------
+
+The `getinfo` RPC command has been deprecated. Each field in the RPC call
+has been moved to another command's output with that command also giving
+additional information that `getinfo` did not provide. The following table
+shows where each field has been moved to:
+
+|`getinfo` field | Moved to |
+|------------------|-------------------------------------------|
+`"version"` | `getnetworkinfo()["version"]`
+`"protocolversion"`| `getnetworkinfo()["protocolversion"]`
+`"walletversion"` | `getwalletinfo()["walletversion"]`
+`"balance"` | `getwalletinfo()["balance"]`
+`"blocks"` | `getblockchaininfo()["blocks"]`
+`"timeoffset"` | `getnetworkinfo()["timeoffset"]`
+`"connections"` | `getnetworkinfo()["connections"]`
+`"proxy"` | `getnetworkinfo()["networks"][0]["proxy"]`
+`"difficulty"` | `getblockchaininfo()["difficulty"]`
+`"testnet"` | `getblockchaininfo()["chain"] == "test"`
+`"keypoololdest"` | `getwalletinfo()["keypoololdest"]`
+`"keypoolsize"` | `getwalletinfo()["keypoolsize"]`
+`"unlocked_until"` | `getwalletinfo()["unlocked_until"]`
+`"paytxfee"` | `getwalletinfo()["paytxfee"]`
+`"relayfee"` | `getnetworkinfo()["relayfee"]`
+`"errors"` | `getnetworkinfo()["warnings"]`
+
+ZMQ On Windows
+--------------
+
+Previously the ZeroMQ notification system was unavailable on Windows
+due to various issues with ZMQ. These have been fixed upstream and
+now ZMQ can be used on Windows. Please see [this document](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md) for
+help with using ZMQ in general.
+
+Nested RPC Commands in Debug Console
+------------------------------------
+
+The ability to nest RPC commands has been added to the debug console. This
+allows users to have the output of a command become the input to another
+command without running the commands separately.
+
+The nested RPC commands use bracket syntax (i.e. `getwalletinfo()`) and can
+be nested (i.e. `getblock(getblockhash(1))`). Simple queries can be
+done with square brackets where object values are accessed with either an
+array index or a non-quoted string (i.e. `listunspent()[0][txid]`). Both
+commas and spaces can be used to separate parameters in both the bracket syntax
+and normal RPC command syntax.
+
+Network Activity Toggle
+-----------------------
+
+A RPC command and GUI toggle have been added to enable or disable all p2p
+network activity. The network status icon in the bottom right hand corner
+is now the GUI toggle. Clicking the icon will either enable or disable all
+p2p network activity. If network activity is disabled, the icon will
+be grayed out with an X on top of it.
+
+Additionally the `setnetworkactive` RPC command has been added which does
+the same thing as the GUI icon. The command takes one boolean parameter,
+`true` enables networking and `false` disables it.
+
+Out-of-sync Modal Info Layer
+----------------------------
+
+When Bitcoin Core is out-of-sync on startup, a semi-transparent information
+layer will be shown over top of the normal display. This layer contains
+details about the current sync progress and estimates the amount of time
+remaining to finish syncing. This layer can also be hidden and subsequently
+unhidden by clicking on the progress bar at the bottom of the window.
+
+Support for JSON-RPC Named Arguments
+------------------------------------
+
+Commands sent over the JSON-RPC interface and through the `bitcoin-cli` binary
+can now use named arguments. This follows the [JSON-RPC specification](http://www.jsonrpc.org/specification)
+for passing parameters by-name with an object.
+
+`bitcoin-cli` has been updated to support this by parsing `name=value` arguments
+when the `-named` option is given.
+
+Some examples:
+
+ src/bitcoin-cli -named help command="help"
+ src/bitcoin-cli -named getblockhash height=0
+ src/bitcoin-cli -named getblock blockhash=000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
+ src/bitcoin-cli -named sendtoaddress address="(snip)" amount="1.0" subtractfeefromamount=true
+
+The order of arguments doesn't matter in this case. Named arguments are also
+useful to leave out arguments that should stay at their default value. The
+rarely-used arguments `comment` and `comment_to` to `sendtoaddress`, for example, can
+be left out. However, this is not yet implemented for many RPC calls, this is
+expected to land in a later release.
+
+The RPC server remains fully backwards compatible with positional arguments.
+
+Opt into RBF When Sending
+-------------------------
+
+A new startup option, `-walletrbf`, has been added to allow users to have all
+transactions sent opt into RBF support. The default value for this option is
+currently `false`, so transactions will not opt into RBF by default. The new
+`bumpfee` RPC can be used to replace transactions that opt into RBF.
+
+Sensitive Data Is No Longer Stored In Debug Console History
+-----------------------------------------------------------
+
+The debug console maintains a history of previously entered commands that can be
+accessed by pressing the Up-arrow key so that users can easily reuse previously
+entered commands. Commands which have sensitive information such as passphrases and
+private keys will now have a `(...)` in place of the parameters when accessed through
+the history.
+
+Retaining the Mempool Across Restarts
+-------------------------------------
+
+The mempool will be saved to the data directory prior to shutdown
+to a `mempool.dat` file. This file preserves the mempool so that when the node
+restarts the mempool can be filled with transactions without waiting for new transactions
+to be created. This will also preserve any changes made to a transaction through
+commands such as `prioritisetransaction` so that those changes will not be lost.
+
+Final Alert
+-----------
+
+The Alert System was [disabled and deprecated](https://bitcoin.org/en/alert/2016-11-01-alert-retirement) in Bitcoin Core 0.12.1 and removed in 0.13.0.
+The Alert System was retired with a maximum sequence final alert which causes any nodes
+supporting the Alert System to display a static hard-coded "Alert Key Compromised" message which also
+prevents any other alerts from overriding it. This final alert is hard-coded into this release
+so that all old nodes receive the final alert.
+
+GUI Changes
+-----------
+
+ - After resetting the options by clicking the `Reset Options` button
+ in the options dialog or with the `-resetguioptions` startup option,
+ the user will be prompted to choose the data directory again. This
+ is to ensure that custom data directories will be kept after the
+ option reset which clears the custom data directory set via the choose
+ datadir dialog.
+
+ - Multiple peers can now be selected in the list of peers in the debug
+ window. This allows for users to ban or disconnect multiple peers
+ simultaneously instead of banning them one at a time.
+
+ - An indicator has been added to the bottom right hand corner of the main
+ window to indicate whether the wallet being used is a HD wallet. This
+ icon will be grayed out with an X on top of it if the wallet is not a
+ HD wallet.
+
+Low-level RPC changes
+----------------------
+
+ - `importprunedfunds` only accepts two required arguments. Some versions accept
+ an optional third arg, which was always ignored. Make sure to never pass more
+ than two arguments.
+
+ - The first boolean argument to `getaddednodeinfo` has been removed. This is
+ an incompatible change.
+
+ - RPC command `getmininginfo` loses the "testnet" field in favor of the more
+ generic "chain" (which has been present for years).
+
+ - A new RPC command `preciousblock` has been added which marks a block as
+ precious. A precious block will be treated as if it were received earlier
+ than a competing block.
+
+ - A new RPC command `importmulti` has been added which receives an array of
+ JSON objects representing the intention of importing a public key, a
+ private key, an address and script/p2sh
+
+ - Use of `getrawtransaction` for retrieving confirmed transactions with unspent
+ outputs has been deprecated. For now this will still work, but in the future
+ it may change to only be able to retrieve information about transactions in
+ the mempool or if `txindex` is enabled.
+
+ - A new RPC command `getmemoryinfo` has been added which will return information
+ about the memory usage of Bitcoin Core. This was added in conjunction with
+ optimizations to memory management. See [Pull #8753](https://github.com/bitcoin/bitcoin/pull/8753)
+ for more information.
+
+ - A new RPC command `bumpfee` has been added which allows replacing an
+ unconfirmed wallet transaction that signaled RBF (see the `-walletrbf`
+ startup option above) with a new transaction that pays a higher fee, and
+ should be more likely to get confirmed quickly.
+
+HTTP REST Changes
+-----------------
+
+ - UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>
+ /.../<txid>-<n>.<bin|hex|json>`) responses were changed to return status
+ code `HTTP_BAD_REQUEST` (400) instead of `HTTP_INTERNAL_SERVER_ERROR` (500)
+ when requests contain invalid parameters.
+
+Minimum Fee Rate Policies
+-------------------------
+
+Since the changes in 0.12 to automatically limit the size of the mempool and improve the performance of block creation in mining code it has not been important for relay nodes or miners to set `-minrelaytxfee`. With this release the following concepts that were tied to this option have been separated out:
+- incremental relay fee used for calculating BIP 125 replacement and mempool limiting. (1000 satoshis/kB)
+- calculation of threshold for a dust output. (effectively 3 * 1000 satoshis/kB)
+- minimum fee rate of a package of transactions to be included in a block created by the mining code. If miners wish to set this minimum they can use the new `-blockmintxfee` option. (defaults to 1000 satoshis/kB)
+
+The `-minrelaytxfee` option continues to exist but is recommended to be left unset.
+
+Fee Estimation Changes
+----------------------
+
+- Since 0.13.2 fee estimation for a confirmation target of 1 block has been
+ disabled. The fee slider will no longer be able to choose a target of 1 block.
+ This is only a minor behavior change as there was often insufficient
+ data for this target anyway. `estimatefee 1` will now always return -1 and
+ `estimatesmartfee 1` will start searching at a target of 2.
+
+- The default target for fee estimation is changed to 6 blocks in both the GUI
+ (previously 25) and for RPC calls (previously 2).
+
+Removal of Priority Estimation
+------------------------------
+
+- Estimation of "priority" needed for a transaction to be included within a target
+ number of blocks has been removed. The RPC calls are deprecated and will either
+ return -1 or 1e24 appropriately. The format for `fee_estimates.dat` has also
+ changed to no longer save these priority estimates. It will automatically be
+ converted to the new format which is not readable by prior versions of the
+ software.
+
+- Support for "priority" (coin age) transaction sorting for mining is
+ considered deprecated in Core and will be removed in the next major version.
+ This is not to be confused with the `prioritisetransaction` RPC which will remain
+ supported by Core for adding fee deltas to transactions.
+
+P2P connection management
+--------------------------
+
+- Peers manually added through the `-addnode` option or `addnode` RPC now have their own
+ limit of eight connections which does not compete with other inbound or outbound
+ connection usage and is not subject to the limitation imposed by the `-maxconnections`
+ option.
+
+- New connections to manually added peers are performed more quickly.
+
+Introduction of assumed-valid blocks
+-------------------------------------
+
+- A significant portion of the initial block download time is spent verifying
+ scripts/signatures. Although the verification must pass to ensure the security
+ of the system, no other result from this verification is needed: If the node
+ knew the history of a given block were valid it could skip checking scripts
+ for its ancestors.
+
+- A new configuration option 'assumevalid' is provided to express this knowledge
+ to the software. Unlike the 'checkpoints' in the past this setting does not
+ force the use of a particular chain: chains that are consistent with it are
+ processed quicker, but other chains are still accepted if they'd otherwise
+ be chosen as best. Also unlike 'checkpoints' the user can configure which
+ block history is assumed true, this means that even outdated software can
+ sync more quickly if the setting is updated by the user.
+
+- Because the validity of a chain history is a simple objective fact it is much
+ easier to review this setting. As a result the software ships with a default
+ value adjusted to match the current chain shortly before release. The use
+ of this default value can be disabled by setting -assumevalid=0
+
+Fundrawtransaction change address reuse
+----------------------------------------
+
+- Before 0.14, `fundrawtransaction` was by default wallet stateless. In
+ almost all cases `fundrawtransaction` does add a change-output to the
+ outputs of the funded transaction. Before 0.14, the used keypool key was
+ never marked as change-address key and directly returned to the keypool
+ (leading to address reuse). Before 0.14, calling `getnewaddress`
+ directly after `fundrawtransaction` did generate the same address as
+ the change-output address.
+
+- Since 0.14, fundrawtransaction does reserve the change-output-key from
+ the keypool by default (optional by setting `reserveChangeKey`, default =
+ `true`)
+
+- Users should also consider using `getrawchangeaddress()` in conjunction
+ with `fundrawtransaction`'s `changeAddress` option.
+
+Unused mempool memory used by coincache
+----------------------------------------
+
+- Before 0.14, memory reserved for mempool (using the `-maxmempool` option)
+ went unused during initial block download, or IBD. In 0.14, the UTXO DB cache
+ (controlled with the `-dbcache` option) borrows memory from the mempool
+ when there is extra memory available. This may result in an increase in
+ memory usage during IBD for those previously relying on only the `-dbcache`
+ option to limit memory during that time.
+
+0.14.0 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, minor refactors and string updates. For convenience
+in locating the code changes and accompanying discussion, both the pull request
+and git merge commit are mentioned.
+
+### RPC and other APIs
+- #8421 `b77bb95` httpserver: drop boost dependency (theuni)
+- #8638 `f061415` rest.cpp: change `HTTP_INTERNAL_SERVER_ERROR` to `HTTP_BAD_REQUEST` (djpnewton)
+- #8272 `91990ee` Make the dummy argument to getaddednodeinfo optional (sipa)
+- #8722 `bb843ad` bitcoin-cli: More detailed error reporting (laanwj)
+- #6996 `7f71a3c` Add preciousblock RPC (sipa)
+- #8788 `97c7f73` Give RPC commands more information about the RPC request (jonasschnelli)
+- #7948 `5d2c8e5` Augment getblockchaininfo bip9\_softforks data (mruddy)
+- #8980 `0e22855` importmulti: Avoid using boost::variant::operator!=, which is only in newer boost versions (luke-jr)
+- #9025 `4d8558a` Getrawtransaction should take a bool for verbose (jnewbery)
+- #8811 `5754e03` Add support for JSON-RPC named arguments (laanwj)
+- #9520 `2456a83` Deprecate non-txindex getrawtransaction and better warning (sipa)
+- #9518 `a65ced1` Return height of last block pruned by pruneblockchain RPC (ryanofsky)
+- #9222 `7cb024e` Add 'subtractFeeFromAmount' option to 'fundrawtransaction' (dooglus)
+- #8456 `2ef52d3` Simplified `bumpfee` command (mrbandrews)
+- #9516 `727a798` Bug-fix: listsinceblock: use fork point as reference for blocks in reorg'd chains (kallewoof)
+- #9640 `7bfb770` Bumpfee: bugfixes for error handling and feerate calculation (sdaftuar)
+- #9673 `8d6447e` Set correct metadata on bumpfee wallet transactions (ryanofsky)
+- #9650 `40f7e27` Better handle invalid parameters to signrawtransaction (TheBlueMatt)
+- #9682 `edc9e63` Require timestamps for importmulti keys (ryanofsky)
+- #9108 `d8e8b06` Use importmulti timestamp when importing watch only keys (on top of #9682) (ryanofsky)
+- #9756 `7a93af8` Return error when importmulti called with invalid address (ryanofsky)
+- #9778 `ad168ef` Add two hour buffer to manual pruning (morcos)
+- #9761 `9828f9a` Use 2 hour grace period for key timestamps in importmulti rescans (ryanofsky)
+- #9474 `48d7e0d` Mark the minconf parameter to move as ignored (sipa)
+- #9619 `861cb0c` Bugfix: RPC/Mining: GBT should return 1 MB sizelimit before segwit activates (luke-jr)
+- #9773 `9072395` Return errors from importmulti if complete rescans are not successful (ryanofsky)
+
+### Block and transaction handling
+- #8391 `37d83bb` Consensus: Remove ISM (NicolasDorier)
+- #8365 `618c9dd` Treat high-sigop transactions as larger rather than rejecting them (sipa)
+- #8814 `14b7b3f` wallet, policy: ParameterInteraction: Don't allow 0 fee (MarcoFalke)
+- #8515 `9bdf526` A few mempool removal optimizations (sipa)
+- #8448 `101c642` Store mempool and prioritization data to disk (sipa)
+- #7730 `3c03dc2` Remove priority estimation (morcos)
+- #9111 `fb15610` Remove unused variable `UNLIKELY_PCT` from fees.h (fanquake)
+- #9133 `434e683` Unset fImporting for loading mempool (morcos)
+- #9179 `b9a87b4` Set `DEFAULT_LIMITFREERELAY` = 0 kB/minute (MarcoFalke)
+- #9239 `3fbf079` Disable fee estimates for 1-block target (morcos)
+- #7562 `1eef038` Bump transaction version default to 2 (btcdrak)
+- #9313,#9367 If we don't allow free txs, always send a fee filter (morcos)
+- #9346 `b99a093` Batch construct batches (sipa)
+- #9262 `5a70572` Prefer coins that have fewer ancestors, sanity check txn before ATMP (instagibbs)
+- #9288 `1ce7ede` Fix a bug if the min fee is 0 for FeeFilterRounder (morcos)
+- #9395 `0fc1c31` Add test for `-walletrejectlongchains` (morcos)
+- #9107 `7dac1e5` Safer modify new coins (morcos)
+- #9312 `a72f76c` Increase mempool expiry time to 2 weeks (morcos)
+- #8610 `c252685` Share unused mempool memory with coincache (sipa)
+- #9138 `f646275` Improve fee estimation (morcos)
+- #9408 `46b249e` Allow shutdown during LoadMempool, dump only when necessary (jonasschnelli)
+- #9310 `8c87f17` Assert FRESH validity in CCoinsViewCache::BatchWrite (ryanofsky)
+- #7871 `e2e624d` Manual block file pruning (mrbandrews)
+- #9507 `0595042` Fix use-after-free in CTxMemPool::removeConflicts() (sdaftuar)
+- #9380 `dd98f04` Separate different uses of minimum fees (morcos)
+- #9596 `71148b8` bugfix save feeDelta instead of priorityDelta in DumpMempool (morcos)
+- #9371 `4a1dc35` Notify on removal (morcos)
+- #9519 `9b4d267` Exclude RBF replacement txs from fee estimation (morcos)
+- #8606 `e2a1a1e` Fix some locks (sipa)
+- #8681 `6898213` Performance Regression Fix: Pre-Allocate txChanged vector (JeremyRubin)
+- #8223 `744d265` c++11: Use std::unique\_ptr for block creation (domob1812)
+- #9125 `7490ae8` Make CBlock a vector of shared\_ptr of CTransactions (sipa)
+- #8930 `93566e0` Move orphan processing to ActivateBestChain (TheBlueMatt)
+- #8580 `46904ee` Make CTransaction actually immutable (sipa)
+- #9240 `a1dcf2e` Remove txConflicted (morcos)
+- #8589 `e8cfe1e` Inline CTxInWitness inside CTxIn (sipa)
+- #9349 `2db4cbc` Make CScript (and prevector) c++11 movable (sipa)
+- #9252 `ce5c1f4` Release cs\_main before calling ProcessNewBlock, or processing headers (cmpctblock handling) (sdaftuar)
+- #9283 `869781c` A few more CTransactionRef optimizations (sipa)
+- #9499 `9c9af5a` Use recent-rejects, orphans, and recently-replaced txn for compact-block-reconstruction (TheBlueMatt)
+- #9813 `3972a8e` Read/write mempool.dat as a binary (paveljanik)
+
+### P2P protocol and network code
+- #8128 `1030fa7` Turn net structures into dumb storage classes (theuni)
+- #8282 `026c6ed` Feeler connections to increase online addrs in the tried table (EthanHeilman)
+- #8462 `53f8f22` Move AdvertiseLocal debug output to net category (Mirobit)
+- #8612 `84decb5` Check for compatibility with download in FindNextBlocksToDownload (sipa)
+- #8594 `5b2ea29` Do not add random inbound peers to addrman (gmaxwell)
+- #8085 `6423116` Begin encapsulation (theuni)
+- #8715 `881d7ea` only delete CConnman if it's been created (theuni)
+- #8707 `f07424a` Fix maxuploadtarget setting (theuni)
+- #8661 `d2e4655` Do not set an addr time penalty when a peer advertises itself (gmaxwell)
+- #8822 `9bc6a6b` Consistent checksum handling (laanwj)
+- #8936 `1230890` Report NodeId in misbehaving debug (rebroad)
+- #8968 `3cf496d` Don't hold cs\_main when calling ProcessNewBlock from a cmpctblock (TheBlueMatt)
+- #9002 `e1d1f57` Make connect=0 disable automatic outbound connections (gmaxwell)
+- #9050 `fcf61b8` Make a few values immutable, and use deterministic randomness for the localnonce (theuni)
+- #8969 `3665483` Decouple peer-processing-logic from block-connection-logic (#2) (TheBlueMatt)
+- #8708 `c8c572f` have CConnman handle message sending (theuni)
+- #8709 `1e50d22` Allow filterclear messages for enabling TX relay only (rebroad)
+- #9045 `9f554e0` Hash P2P messages as they are received instead of at process-time (TheBlueMatt)
+- #9026 `dc6b940` Fix handling of invalid compact blocks (sdaftuar)
+- #8996 `ab914a6` Network activity toggle (luke-jr)
+- #9131 `62af164` fNetworkActive is not protected by a lock, use an atomic (jonasschnelli)
+- #8872 `0c577f2` Remove block-request logic from INV message processing (TheBlueMatt)
+- #8690 `791b58d` Do not fully sort all nodes for addr relay (sipa)
+- #9128 `76fec09` Decouple CConnman and message serialization (theuni)
+- #9226 `3bf06e9` Remove fNetworkNode and pnodeLocalHost (gmaxwell)
+- #9352 `a7f7651` Attempt reconstruction from all compact block announcements (sdaftuar)
+- #9319 `a55716a` Break addnode out from the outbound connection limits (gmaxwell)
+- #9261 `2742568` Add unstored orphans with rejected parents to recentRejects (morcos)
+- #9441 `8b66bf7` Massive speedup. Net locks overhaul (theuni)
+- #9375 `3908fc4` Relay compact block messages prior to full block connection (TheBlueMatt)
+- #9400 `8a445c5` Set peers as HB peers upon full block validation (instagibbs)
+- #9561 `6696b46` Wake message handling thread when we receive a new block (TheBlueMatt)
+- #9535 `82274c0` Split CNode::cs\_vSend: message processing and message sending (TheBlueMatt)
+- #9606 `3f9f962` Consistently use GetTimeMicros() for inactivity checks (sdaftuar)
+- #9594 `fd70211` Send final alert message to older peers after connecting (gmaxwell)
+- #9626 `36966a1` Clean up a few CConnman cs\_vNodes/CNode things (TheBlueMatt)
+- #9609 `4966917` Fix remaining net assertions (theuni)
+- #9671 `7821db3` Fix super-unlikely race introduced in 236618061a445d2cb11e72 (TheBlueMatt)
+- #9730 `33f3b21` Remove bitseed.xf2.org form the dns seed list (jonasschnelli)
+- #9698 `2447c10` Fix socket close race (theuni)
+- #9708 `a06ede9` Clean up all known races/platform-specific UB at the time PR was opened (TheBlueMatt)
+- #9715 `b08656e` Disconnect peers which we do not receive VERACKs from within 60 sec (TheBlueMatt)
+- #9720 `e87ce95` Fix banning and disallow sending messages before receiving verack (theuni)
+- #9268 `09c4fd1` Fix rounding privacy leak introduced in #9260 (TheBlueMatt)
+- #9075 `9346f84` Decouple peer-processing-logic from block-connection-logic (#3) (TheBlueMatt)
+- #8688 `047ded0` Move static global randomizer seeds into CConnman (sipa)
+- #9289 `d9ae1ce` net: drop boost::thread\_group (theuni)
+
+### Validation
+- #9014 `d04aeba` Fix block-connection performance regression (TheBlueMatt)
+- #9299 `d52ce89` Remove no longer needed check for premature v2 txs (morcos)
+- #9273 `b68685a` Remove unused `CDiskBlockPos*` argument from ProcessNewBlock (TheBlueMatt)
+- #8895 `b83264d` Better SigCache Implementation (JeremyRubin)
+- #9490 `e126d0c` Replace FindLatestBefore used by importmulti with FindEarliestAtLeast (gmaxwell)
+- #9484 `812714f` Introduce assumevalid setting to skip validation presumed valid scripts (gmaxwell)
+- #9511 `7884956` Don't overwrite validation state with corruption check (morcos)
+- #9765 `1e92e04` Harden against mistakes handling invalid blocks (sdaftuar)
+- #9779 `3c02b95` Update nMinimumChainWork and defaultAssumeValid (gmaxwell)
+- #8524 `19b0f33` Precompute sighashes (sipa)
+- #9791 `1825a03` Avoid VLA in hash.h (sipa)
+
+### Build system
+- #8238 `6caf3ee` ZeroMQ 4.1.5 && ZMQ on Windows (fanquake)
+- #8520 `b40e19c` Remove check for `openssl/ec.h` (laanwj)
+- #8617 `de07fdc` Include instructions to extract Mac OS X SDK on Linux using 7zip and SleuthKit (luke-jr)
+- #8566 `7b98895` Easy to use gitian building script (achow101)
+- #8604 `f256843` build,doc: Update for 0.13.0+ and OpenBSD 5.9 (laanwj)
+- #8640 `2663e51` depends: Remove Qt46 package (fanquake)
+- #8645 `8ea4440` Remove unused Qt 4.6 patch (droark)
+- #8608 `7e9ab95` Install manpages via make install, also add some autogenerated manpages (nomnombtc)
+- #8781 `ca69ef4` contrib: delete `qt_translations.py` (MarcoFalke)
+- #8783 `64dc645` share: remove qt/protobuf.pri (MarcoFalke)
+- #8423 `3166dff` depends: expat 2.2.0, ccache 3.3.1, fontconfig 2.12.1 (fanquake)
+- #8791 `b694b0d` travis: cross-mac: explicitly enable gui (MarcoFalke)
+- #8820 `dc64141` depends: Fix Qt compilation with Xcode 8 (fanquake)
+- #8730 `489a6ab` depends: Add libevent compatibility patch for windows (laanwj)
+- #8819 `c841816` depends: Boost 1.61.0 (fanquake)
+- #8826 `f560d95` Do not include `env_win.cc` on non-Windows systems (paveljanik)
+- #8948 `e077e00` Reorder Windows gitian build order to match Linux (Michagogo)
+- #8568 `078900d` new var `DIST_CONTRIB` adds useful things for packagers from contrib (nomnombtc)
+- #9114 `21e6c6b` depends: Set `OSX_MIN_VERSION` to 10.8 (fanquake)
+- #9140 `018a4eb` Bugfix: Correctly replace generated headers and fail cleanly (luke-jr)
+- #9156 `a8b2a82` Add compile and link options echo to configure (jonasschnelli)
+- #9393 `03d85f6` Include cuckoocache header in Makefile (MarcoFalke)
+- #9420 `bebe369` Fix linker error when configured with --enable-lcov (droark)
+- #9412 `53442af` Fix 'make deploy' for OSX (jonasschnelli)
+- #9475 `7014506` Let autoconf detect presence of `EVP_MD_CTX_new` (luke-jr)
+- #9513 `bbf193f` Fix qt distdir builds (theuni)
+- #9471 `ca615e6` depends: libevent 2.1.7rc (fanquake)
+- #9468 `f9117f2` depends: Dependency updates for 0.14.0 (fanquake)
+- #9469 `01c4576` depends: Qt 5.7.1 (fanquake)
+- #9574 `5ac6687` depends: Fix QT build on OSX (fanquake)
+- #9646 `720b579` depends: Fix cross build for qt5.7 (theuni)
+- #9705 `6a55515` Add options to override BDB cflags/libs (laanwj)
+- #8249 `4e1567a` Enable (and check for) 64-bit ASLR on Windows (laanwj)
+- #9758 `476cc47` Selectively suppress deprecation warnings (jonasschnelli)
+- #9783 `6d61a2b` release: bump gitian descriptors for a new 0.14 package cache (theuni)
+- #9789 `749fe95` build: add --enable-werror and warn on vla's (theuni)
+- #9831 `99fd85c` build: force a c++ standard to be specified (theuni)
+
+### GUI
+- #8192 `c503863` Remove URLs from About dialog translations (fanquake)
+- #8540 `36404ae` Fix random segfault when closing "Choose data directory" dialog (laanwj)
+- #8517 `2468292` Show wallet HD state in statusbar (jonasschnelli)
+- #8463 `62a5a8a` Remove Priority from coincontrol dialog (MarcoFalke)
+- #7579 `0606f95` Show network/chain errors in the GUI (jonasschnelli)
+- #8583 `c19f8a4` Show XTHIN in GUI (rebroad)
+- #7783 `4335d5a` RPC-Console: support nested commands and simple value queries (jonasschnelli)
+- #8672 `6052d50` Show transaction size in transaction details window (Cocosoft)
+- #8777 `fec6af7` WalletModel: Expose disablewallet (MarcoFalke)
+- #8371 `24f72e9` Add out-of-sync modal info layer (jonasschnelli)
+- #8885 `b2fec4e` Fix ban from qt console (theuni)
+- #8821 `bf8e68a` sync-overlay: Don't block during reindex (MarcoFalke)
+- #8906 `088d1f4` sync-overlay: Don't show progress twice (MarcoFalke)
+- #8918 `47ace42` Add "Copy URI" to payment request context menu (luke-jr)
+- #8925 `f628d9a` Display minimum ping in debug window (rebroad)
+- #8774 `3e942a7` Qt refactors to better abstract wallet access (luke-jr)
+- #8985 `7b1bfa3` Use pindexBestHeader instead of setBlockIndexCandidates for NotifyHeaderTip() (jonasschnelli)
+- #8989 `d2143dc` Overhaul smart-fee slider, adjust default confirmation target (jonasschnelli)
+- #9043 `273bde3` Return useful error message on ATMP failure (MarcoFalke)
+- #9088 `4e57824` Reduce ambiguity of warning message (rebroad)
+- #8874 `e984730` Multiple Selection for peer and ban tables (achow101)
+- #9145 `924745d` Make network disabled icon 50% opaque (MarcoFalke)
+- #9130 `ac489b2` Mention the new network toggle functionality in the tooltip (paveljanik)
+- #9218 `4d955fc` Show progress overlay when clicking spinner icon (laanwj)
+- #9280 `e15660c` Show ModalOverlay by pressing the progress bar, allow hiding (jonasschnelli)
+- #9296 `fde7d99` Fix missed change to WalletTx structure (morcos)
+- #9266 `2044e37` Bugfix: Qt/RPCConsole: Put column enum in the right places (luke-jr)
+- #9255 `9851a84` layoutAboutToChange signal is called layoutAboutToBeChanged (laanwj)
+- #9330 `47e6a19` Console: add security warning (jonasschnelli)
+- #9329 `db45ad8` Console: allow empty arguments (jonasschnelli)
+- #8877 `6dc4c43` Qt RPC console: history sensitive-data filter, and saving input line when browsing history (luke-jr)
+- #9462 `649cf5f` Do not translate tilde character (MarcoFalke)
+- #9457 `123ea73` Select more files for translation (MarcoFalke)
+- #9413 `fd7d8c7` CoinControl: Allow non-wallet owned change addresses (jonasschnelli)
+- #9461 `b250686` Improve progress display during headers-sync and peer-finding (jonasschnelli)
+- #9588 `5086452` Use nPowTargetSpacing constant (MarcoFalke)
+- #9637 `d9e4d1d` Fix transaction details output-index to reflect vout index (jonasschnelli)
+- #9718 `36f9d3a` Qt/Intro: Various fixes (luke-jr)
+- #9735 `ec66d06` devtools: Handle Qt formatting characters edge-case in update-translations.py (laanwj)
+- #9755 `a441db0` Bugfix: Qt/Options: Restore persistent "restart required" notice (luke-jr)
+- #9817 `7d75a5a` Fix segfault crash when shutdown the GUI in disablewallet mode (jonasschnelli)
+
+### Wallet
+- #8152 `b9c1cd8` Remove `CWalletDB*` parameter from CWallet::AddToWallet (pstratem)
+- #8432 `c7e05b3` Make CWallet::fFileBacked private (pstratem)
+- #8445 `f916700` Move CWallet::setKeyPool to private section of CWallet (pstratem)
+- #8564 `0168019` Remove unused code/conditions in ReadAtCursor (jonasschnelli)
+- #8601 `37ac678` Add option to opt into full-RBF when sending funds (rebase, original by petertodd) (laanwj)
+- #8494 `a5b20ed` init, wallet: ParameterInteraction() iff wallet enabled (MarcoFalke)
+- #8760 `02ac669` init: Get rid of some `ENABLE_WALLET` (MarcoFalke)
+- #8696 `a1f8d3e` Wallet: Remove last external reference to CWalletDB (pstratem)
+- #8768 `886e8c9` init: Get rid of fDisableWallet (MarcoFalke)
+- #8486 `ab0b411` Add high transaction fee warnings (MarcoFalke)
+- #8851 `940748b` Move key derivation logic from GenerateNewKey to DeriveNewChildKey (pstratem)
+- #8287 `e10af96` Set fLimitFree = true (MarcoFalke)
+- #8928 `c587577` Fix init segfault where InitLoadWallet() calls ATMP before genesis (TheBlueMatt)
+- #7551 `f2d7056` Add importmulti RPC call (pedrobranco)
+- #9016 `0dcb888` Return useful error message on ATMP failure (instagibbs)
+- #8753 `f8723d2` Locked memory manager (laanwj)
+- #8828 `a4fd8df` Move CWalletDB::ReorderTransactions to CWallet (pstratem)
+- #8977 `6a1343f` Refactor wallet/init interaction (Reaccept wtx, flush thread) (jonasschnelli)
+- #9036 `ed0cc50` Change default confirm target from 2 to 6 (laanwj)
+- #9071 `d1871da` Declare wallet.h functions inline (sipa)
+- #9132 `f54e460` Make strWalletFile const (jonasschnelli)
+- #9141 `5ea5e04` Remove unnecessary calls to CheckFinalTx (jonasschnelli)
+- #9165 `c01f16a` SendMoney: use already-calculated balance (instagibbs)
+- #9311 `a336d13` Flush wallet after abandontransaction (morcos)
+- #8717 `38e4887` Addition of ImmatureCreditCached to MarkDirty() (spencerlievens)
+- #9446 `510c0d9` SetMerkleBranch: remove unused code, remove cs\_main lock requirement (jonasschnelli)
+- #8776 `2a524b8` Wallet refactoring leading up to multiwallet (luke-jr)
+- #9465 `a7d55c9` Do not perform ECDSA signing in the fee calculation inner loop (gmaxwell)
+- #9404 `12e3112` Smarter coordination of change and fee in CreateTransaction (morcos)
+- #9377 `fb75cd0` fundrawtransaction: Keep change-output keys by default, make it optional (jonasschnelli)
+- #9578 `923dc44` Add missing mempool lock for CalculateMemPoolAncestors (TheBlueMatt)
+- #9227 `02464da` Make nWalletDBUpdated atomic to avoid a potential race (pstratem)
+- #9764 `f8af89a` Prevent "overrides a member function but is not marked 'override'" warnings (laanwj)
+- #9771 `e43a585` Add missing cs\_wallet lock that triggers new lock held assertion (ryanofsky)
+- #9316 `3097ea4` Disable free transactions when relay is disabled (MarcoFalke)
+- #9615 `d2c9e4d` Wallet incremental fee (morcos)
+- #9760 `40c754c` Remove importmulti always-true check (ryanofsky)
+
+### Tests and QA
+- #8270 `6e5e5ab` Tests: Use portable #! in python scripts (/usr/bin/env) (ChoHag)
+- #8534,#8504 Remove java comparison tool (laanwj,MarcoFalke)
+- #8482 `740cff5` Use single cache dir for chains (MarcoFalke)
+- #8450 `21857d2` Replace `rpc_wallet_tests.cpp` with python RPC unit tests (pstratem)
+- #8671 `ddc3080` Minimal fix to slow prevector tests as stopgap measure (JeremyRubin)
+- #8680 `666eaf0` Address Travis spurious failures (theuni)
+- #8789 `e31a43c` pull-tester: Only print output when failed (MarcoFalke)
+- #8810 `14e8f99` tests: Add exception error message for JSONRPCException (laanwj)
+- #8830 `ef0801b` test: Add option to run bitcoin-util-test.py manually (jnewbery)
+- #8881 `e66cc1d` Add some verbose logging to bitcoin-util-test.py (jnewbery)
+- #8922 `0329511` Send segwit-encoded blocktxn messages in p2p-compactblocks (TheBlueMatt)
+- #8873 `74dc388` Add microbenchmarks to profile more code paths (ryanofsky)
+- #9032 `6a8be7b` test: Add format-dependent comparison to bctest (laanwj)
+- #9023 `774db92` Add logging to bitcoin-util-test.py (jnewbery)
+- #9065 `c9bdf9a` Merge `doc/unit-tests.md` into `src/test/README.md` (laanwj)
+- #9069 `ed64bce` Clean up bctest.py and bitcoin-util-test.py (jnewbery)
+- #9095 `b8f43e3` test: Fix test\_random includes (MarcoFalke)
+- #8894 `faec09b` Testing: Include fRelay in mininode version messages (jnewbery)
+- #9097 `e536499` Rework `sync_*` and preciousblock.py (MarcoFalke)
+- #9049 `71bc39e` Remove duplicatable duplicate-input check from CheckTransaction (TheBlueMatt)
+- #9136 `b422913` sync\_blocks cleanup (ryanofsky)
+- #9151 `4333b1c` proxy\_test: Calculate hardcoded port numbers (MarcoFalke)
+- #9206 `e662d28` Make test constant consistent with consensus.h (btcdrak)
+- #9139 `0de7fd3` Change sync\_blocks to pick smarter maxheight (on top of #9196) (ryanofsky)
+- #9100 `97ec6e5` tx\_valid: re-order inputs to how they are encoded (dcousens)
+- #9202 `e56cf67` bench: Add support for measuring CPU cycles (laanwj)
+- #9223 `5412c08` unification of Bloom filter representation (s-matthew-english)
+- #9257 `d7ba4a2` Dump debug logs on travis failures (sdaftuar)
+- #9221 `9e4bb31` Get rid of duplicate code (MarcoFalke)
+- #9274 `919db03` Use cached utxo set to fix performance regression (MarcoFalke)
+- #9276 `ea33f19` Some minor testing cleanups (morcos)
+- #9291 `8601784` Remove mapOrphanTransactionsByPrev from DoS\_tests (sipa)
+- #9309 `76fcd9d` Wallet needs to stay unlocked for whole test (morcos)
+- #9172 `5bc209c` Resurrect pstratem's "Simple fuzzing framework" (laanwj)
+- #9331 `c6fd923` Add test for rescan feature of wallet key import RPCs (ryanofsky)
+- #9354 `b416095` Make fuzzer actually test CTxOutCompressor (sipa)
+- #9390,#9416 travis: make distdir (MarcoFalke)
+- #9308 `0698639` test: Add CCoinsViewCache Access/Modify/Write tests (ryanofsky)
+- #9406 `0f921e6` Re-enable a blank v1 Tx JSON test (droark)
+- #9435 `dbc8a8c` Removed unused variable in test, fixing warning (ryanofsky)
+- #9436 `dce853e` test: Include tx data in `EXTRA_DIST` (MarcoFalke)
+- #9525 `02e5308` test: Include tx data in `EXTRA_DIST` (MarcoFalke)
+- #9498 `054d664` Basic CCheckQueue Benchmarks (JeremyRubin)
+- #9554 `0b96abc` test: Avoid potential NULL pointer dereference in `addrman_tests.cpp` (practicalswift)
+- #9628 `f895023` Increase a sync\_blocks timeout in pruning.py (sdaftuar)
+- #9638 `a7ea2f8` Actually test assertions in pruning.py (MarcoFalke)
+- #9647 `e99f0d7` Skip RAII event tests if libevent is built without `event_set_mem_functions` (luke-jr)
+- #9691 `fc67cd2` Init ECC context for `test_bitcoin_fuzzy` (gmaxwell)
+- #9712 `d304fef` bench: Fix initialization order in registration (laanwj)
+- #9707 `b860915` Fix RPC failure testing (jnewbery)
+- #9269 `43e8150` Align struct COrphan definition (sipa)
+- #9820 `599c69a` Fix pruning test broken by 2 hour manual prune window (ryanofsky)
+- #9824 `260c71c` qa: Check return code when stopping nodes (MarcoFalke)
+- #9875 `50953c2` tests: Fix dangling pwalletMain pointer in wallet tests (laanwj)
+- #9839 `eddaa6b` [qa] Make import-rescan.py watchonly check reliable (ryanofsky)
+
+### Documentation
+- #8332 `806b9e7` Clarify witness branches in transaction.h serialization (dcousens)
+- #8935 `0306978` Documentation: Building on Windows with WSL (pooleja)
+- #9144 `c98f6b3` Correct waitforblockheight example help text (fanquake)
+- #9407 `041331e` Added missing colons in when running help command (anditto)
+- #9378 `870cd2b` Add documentation for CWalletTx::fFromMe member (ryanofsky)
+- #9297 `0b73807` Various RPC help outputs updated (Mirobit)
+- #9613 `07421cf` Clarify getbalance help string to explain interaction with bumpfee (ryanofsky)
+- #9663 `e30d928` Clarify listunspent amount description (instagibbs)
+- #9396 `d65a13b` Updated listsinceblock rpc documentation (accraze)
+- #8747 `ce43630` rpc: Fix transaction size comments and RPC help text (jnewbery)
+- #8058 `bbd9740` Doc: Add issue template (AmirAbrams)
+- #8567 `85d4e21` Add default port numbers to REST doc (djpnewton)
+- #8624 `89de153` build: Mention curl (MarcoFalke)
+- #8786 `9da7366` Mandatory copyright agreement (achow101)
+- #8823 `7b05af6` Add privacy recommendation when running hidden service (laanwj)
+- #9433 `caa2f10` Update the Windows build notes (droark)
+- #8879 `f928050` Rework docs (MarcoFalke)
+- #8887 `61d191f` Improve GitHub issue template (fanquake)
+- #8787 `279bbad` Add missing autogen to example builds (AmirAbrams)
+- #8892 `d270c30` Add build instructions for FreeBSD (laanwj)
+- #8890 `c71a654` Update Doxygen configuration file (fanquake)
+- #9207 `fa1f944` Move comments above bash command in build-unix (AmirAbrams)
+- #9219 `c4522e7` Improve windows build instructions using Linux subsystem (laanwj)
+- #8954 `932d02a` contrib: Add README for pgp keys (MarcoFalke)
+- #9093 `2fae5b9` release-process: Mention GitHub release and archived release notes (MarcoFalke)
+- #8743 `bae178f` Remove old manpages from contrib/debian in favour of doc/man (fanquake)
+- #9550 `4105cb6` Trim down the XP notice and say more about what we support (gmaxwell)
+- #9246 `9851498` Developer docs about existing subtrees (gmaxwell)
+- #9401 `c2ea1e6` Make rpcauth help message clearer, add example in example .conf (instagibbs)
+- #9022,#9033 Document dropping OS X 10.7 support (fanquake, MarcoFalke)
+- #8771 `bc9e3ab` contributing: Mention not to open several pulls (luke-jr)
+- #8852 `7b784cc` Mention Gitian building script in doc (Laudaa) (laanwj)
+- #8915 `03dd707` Add copyright/patent issues to possible NACK reasons (petertodd)
+- #8965 `23e03f8` Mention that PPA doesn't support Debian (anduck)
+- #9115 `bfc7aad` Mention reporting security issues responsibly (paveljanik)
+- #9840 `08e0690` Update sendfrom RPC help to correct coin selection misconception (ryanofsky)
+- #9865 `289204f` Change bitcoin address in RPC help message (marijnfs)
+
+### Miscellaneous
+- #8274 `7a2d402` util: Update tinyformat (laanwj)
+- #8291 `5cac8b1` util: CopyrightHolders: Check for untranslated substitution (MarcoFalke)
+- #8557 `44691f3` contrib: Rework verifybinaries (MarcoFalke)
+- #8621 `e8ed6eb` contrib: python: Don't use shell=True (MarcoFalke)
+- #8813 `fb24d7e` bitcoind: Daemonize using daemon(3) (laanwj)
+- #9004 `67728a3` Clarify `listenonion` (unsystemizer)
+- #8674 `bae81b8` tools for analyzing, updating and adding copyright headers in source files (isle2983)
+- #8976 `8c6218a` libconsensus: Add input validation of flags (laanwj)
+- #9112 `46027e8` Avoid ugly exception in log on unknown inv type (laanwj)
+- #8837 `2108911` Allow bitcoin-tx to parse partial transactions (jnewbery)
+- #9204 `74ced54` Clarify CreateTransaction error messages (instagibbs)
+- #9265 `31bcc66` bitcoin-cli: Make error message less confusing (laanwj)
+- #9303 `72bf1b3` Update comments in ctaes (sipa)
+- #9417 `c4b7d4f` Do not evaluate hidden LogPrint arguments (sipa)
+- #9506 `593a00c` RFC: Improve style for if indentation (sipa)
+- #8883 `d5d4ad8` Add all standard TXO types to bitcoin-tx (jnewbery)
+- #9531 `23281a4` Release notes for estimation changes (morcos)
+- #9486 `f62bc10` Make peer=%d log prints consistent (TheBlueMatt)
+- #9552 `41cb05c` Add IPv6 support to qos.sh (jamesmacwhite)
+- #9542 `e9e7993` Docs: Update CONTRIBUTING.md (jnewbery)
+- #9649 `53ab12d` Remove unused clang format dev script (MarcoFalke)
+- #9625 `77bd8c4` Increase minimum debug.log size to 10MB after shrink (morcos)
+- #9070 `7b22e50` Lockedpool fixes (kazcw)
+- #8779 `7008e28` contrib: Delete spendfrom (MarcoFalke)
+- #9587,#8793,#9496,#8191,#8109,#8655,#8472,#8677,#8981,#9124 Avoid shadowing of variables (paveljanik)
+- #9063 `f2a6e82` Use deprecated `MAP_ANON` if `MAP_ANONYMOUS` is not defined (paveljanik)
+- #9060 `1107653` Fix bloom filter init to isEmpty = true (robmcl4)
+- #8613 `613bda4` LevelDB 1.19 (sipa)
+- #9225 `5488514` Fix some benign races (TheBlueMatt)
+- #8736 `5fa7b07` base58: Improve DecodeBase58 performance (wjx)
+- #9039 `e81df49` Various serialization simplifcations and optimizations (sipa)
+- #9010 `a143b88` Split up AppInit2 into multiple phases, daemonize after datadir lock errors (laanwj)
+- #9230 `c79e52a` Fix some benign races in timestamp logging (TheBlueMatt)
+- #9183,#9260 Mrs Peacock in The Library with The Candlestick (killed main.{h,cpp}) (TheBlueMatt)
+- #9236 `7f72568` Fix races for strMiscWarning and `fLargeWork*Found`, make QT runawayException use GetWarnings (gmaxwell)
+- #9243 `7aa7004` Clean up mapArgs and mapMultiArgs Usage (TheBlueMatt)
+- #9387 `cfe41d7` RAII of libevent stuff using unique ptrs with deleters (kallewoof)
+- #9472 `fac0f30` Disentangle progress estimation from checkpoints and update it (sipa)
+- #9512 `6012967` Fix various things -fsanitize complains about (sipa)
+- #9373,#9580 Various linearization script issues (droark)
+- #9674 `dd163f5` Lock debugging: Always enforce strict lock ordering (try or not) (TheBlueMatt)
+- #8453,#9334 Update to latest libsecp256k1 (laanwj,sipa)
+- #9656 `7c93952` Check verify-commits on pushes to master (TheBlueMatt)
+- #9679 `a351162` Access WorkQueue::running only within the cs lock (TheBlueMatt)
+- #9777 `8dee822` Handle unusual maxsigcachesize gracefully (jnewbery)
+- #8863,#8807 univalue: Pull subtree (MarcoFalke)
+- #9798 `e22c067` Fix Issue #9775 (Check returned value of fopen) (kirit93)
+- #9856 `69832aa` Terminate immediately when allocation fails (theuni)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- accraze
+- adlawren
+- Alex Morcos
+- Alexey Vesnin
+- Amir Abrams
+- Anders Øyvind Urke-Sætre
+- Anditto Heristyo
+- Andrew Chow
+- anduck
+- Anthony Towns
+- Brian Deery
+- BtcDrak
+- Chris Moore
+- Chris Stewart
+- Christian Barcenas
+- Christian Decker
+- Cory Fields
+- crowning-
+- CryptAxe
+- CryptoVote
+- Dagur Valberg Johannsson
+- Daniel Cousens
+- Daniel Kraft
+- Derek Miller
+- djpnewton
+- Don Patterson
+- Doug
+- Douglas Roark
+- Ethan Heilman
+- fsb4000
+- Gaurav Rana
+- Geoffrey Tsui
+- Greg Walker
+- Gregory Maxwell
+- Gregory Sanders
+- Hampus Sjöberg
+- isle2983
+- Ivo van der Sangen
+- James White
+- Jameson Lopp
+- Jeremy Rubin
+- Jiaxing Wang
+- jnewbery
+- John Newbery
+- Johnson Lau
+- Jon Lund Steffensen
+- Jonas Schnelli
+- jonnynewbs
+- Jorge Timón
+- Justin Camarena
+- Karl-Johan Alm
+- Kaz Wesley
+- kirit93
+- Koki Takahashi
+- Lauda
+- leijurv
+- lizhi
+- Luke Dashjr
+- maiiz
+- MarcoFalke
+- Marijn Stollenga
+- Marty Jones
+- Masahiko Hyuga
+- Matt Corallo
+- Matthew King
+- matthias
+- Micha
+- Michael Ford
+- Michael Rotarius
+- Mitchell Cash
+- mrbandrews
+- mruddy
+- Nicolas DORIER
+- nomnombtc
+- Patrick Strateman
+- Pavel Janík
+- Pedro Branco
+- Peter Todd
+- Pieter Wuille
+- poole\_party
+- practicalswift
+- R E Broadley
+- randy-waterhouse
+- Richard Kiss
+- Robert McLaughlin
+- rodasmith
+- Russell Yanofsky
+- S. Matthew English
+- Sev
+- Spencer Lievens
+- Stanislas Marion
+- Steven
+- Suhas Daftuar
+- Thomas Snider
+- UdjinM6
+- unsystemizer
+- whythat
+- Will Binns
+- Wladimir J. van der Laan
+- wodry
+- Zak Wilcox
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
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/abandonconflict.py b/qa/rpc-tests/abandonconflict.py
index b32d4e2ce0..887dbebd4f 100755
--- a/qa/rpc-tests/abandonconflict.py
+++ b/qa/rpc-tests/abandonconflict.py
@@ -23,8 +23,8 @@ class AbandonConflictTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-logtimemicros"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"]))
+ self.nodes.append(start_node(1, self.options.tmpdir))
connect_nodes(self.nodes[0], 1)
def run_test(self):
@@ -80,9 +80,8 @@ class AbandonConflictTest(BitcoinTestFramework):
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool
# TODO: redo with eviction
- # Note had to make sure tx did not have AllowFree priority
stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
# Verify txs no longer in mempool
assert_equal(len(self.nodes[0].getrawmempool()), 0)
@@ -108,7 +107,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"])
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
assert_equal(self.nodes[0].getbalance(), balance)
@@ -128,7 +127,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Remove using high relay fee again
stop_node(self.nodes[0],0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("24.9996"))
@@ -159,9 +158,9 @@ class AbandonConflictTest(BitcoinTestFramework):
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
newbalance = self.nodes[0].getbalance()
#assert_equal(newbalance, balance - Decimal("10"))
- print("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
- print("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
- print(str(balance) + " -> " + str(newbalance) + " ?")
+ self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer")
+ self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315")
+ self.log.info(str(balance) + " -> " + str(newbalance) + " ?")
if __name__ == '__main__':
AbandonConflictTest().main()
diff --git a/qa/rpc-tests/assumevalid.py b/qa/rpc-tests/assumevalid.py
index b8dafff161..c60c8e6d1a 100755
--- a/qa/rpc-tests/assumevalid.py
+++ b/qa/rpc-tests/assumevalid.py
@@ -73,7 +73,7 @@ class SendHeadersTest(BitcoinTestFramework):
# we need to pre-mine a block with an invalid transaction
# signature so we can pass in the block hash as assumevalid.
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
+ self.nodes.append(start_node(0, self.options.tmpdir))
def run_test(self):
@@ -146,14 +146,14 @@ class SendHeadersTest(BitcoinTestFramework):
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.nodes.append(start_node(1, self.options.tmpdir,
- ["-debug", "-assumevalid=" + hex(block102.sha256)]))
+ ["-assumevalid=" + hex(block102.sha256)]))
node1 = BaseNode() # connects to node1
connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1))
node1.add_connection(connections[1])
node1.wait_for_verack()
self.nodes.append(start_node(2, self.options.tmpdir,
- ["-debug", "-assumevalid=" + hex(block102.sha256)]))
+ ["-assumevalid=" + hex(block102.sha256)]))
node2 = BaseNode() # connects to node2
connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
node2.add_connection(connections[2])
diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py
index ea9c3d73ab..63d05e8fc9 100755
--- a/qa/rpc-tests/bip65-cltv-p2p.py
+++ b/qa/rpc-tests/bip65-cltv-p2p.py
@@ -43,7 +43,7 @@ class BIP65Test(ComparisonTestFramework):
def setup_network(self):
# Must set the blockversion for this test
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']],
+ extra_args=[['-whitelist=127.0.0.1', '-blockversion=3']],
binary=[self.options.testbinary])
def run_test(self):
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-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py
index 836267ea7f..0867f42585 100755
--- a/qa/rpc-tests/bip68-112-113-p2p.py
+++ b/qa/rpc-tests/bip68-112-113-p2p.py
@@ -99,7 +99,7 @@ class BIP68_112_113Test(ComparisonTestFramework):
def setup_network(self):
# Must set the blockversion for this test
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']],
+ extra_args=[['-whitelist=127.0.0.1', '-blockversion=4']],
binary=[self.options.testbinary])
def run_test(self):
diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py
index 74ac393fe9..3ed6ebe044 100755
--- a/qa/rpc-tests/bip68-sequence.py
+++ b/qa/rpc-tests/bip68-sequence.py
@@ -24,8 +24,8 @@ class BIP68Test(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-blockprioritysize=0"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"]))
+ self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-acceptnonstdtxn=0"]))
self.is_network_split = False
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
connect_nodes(self.nodes[0], 1)
@@ -34,28 +34,26 @@ class BIP68Test(BitcoinTestFramework):
# Generate some coins
self.nodes[0].generate(110)
- print("Running test disable flag")
+ self.log.info("Running test disable flag")
self.test_disable_flag()
- print("Running test sequence-lock-confirmed-inputs")
+ self.log.info("Running test sequence-lock-confirmed-inputs")
self.test_sequence_lock_confirmed_inputs()
- print("Running test sequence-lock-unconfirmed-inputs")
+ self.log.info("Running test sequence-lock-unconfirmed-inputs")
self.test_sequence_lock_unconfirmed_inputs()
- print("Running test BIP68 not consensus before versionbits activation")
+ self.log.info("Running test BIP68 not consensus before versionbits activation")
self.test_bip68_not_consensus()
- print("Verifying nVersion=2 transactions aren't standard")
- self.test_version2_relay(before_activation=True)
-
- print("Activating BIP68 (and 112/113)")
+ self.log.info("Activating BIP68 (and 112/113)")
self.activateCSV()
- print("Verifying nVersion=2 transactions are now standard")
- self.test_version2_relay(before_activation=False)
+ self.log.info("Verifying nVersion=2 transactions are standard.")
+ self.log.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).")
+ self.test_version2_relay()
- print("Passed\n")
+ self.log.info("Passed")
# Test that BIP68 is not in effect if tx version is 1, or if
# the first sequence bit is set.
@@ -92,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.
@@ -192,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
@@ -241,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)
@@ -256,7 +246,7 @@ class BIP68Test(BitcoinTestFramework):
# Now mine some blocks, but make sure tx2 doesn't get mined.
# Use prioritisetransaction to lower the effective feerate to 0
- self.nodes[0].prioritisetransaction(tx2.hash, -1e15, int(-self.relayfee*COIN))
+ self.nodes[0].prioritisetransaction(tx2.hash, int(-self.relayfee*COIN))
cur_time = int(time.time())
for i in range(10):
self.nodes[0].setmocktime(cur_time + 600)
@@ -269,7 +259,7 @@ class BIP68Test(BitcoinTestFramework):
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
# Mine tx2, and then try again
- self.nodes[0].prioritisetransaction(tx2.hash, 1e15, int(self.relayfee*COIN))
+ self.nodes[0].prioritisetransaction(tx2.hash, int(self.relayfee*COIN))
# Advance the time on the node so that we can test timelocks
self.nodes[0].setmocktime(cur_time+600)
@@ -297,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
#
@@ -375,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)
@@ -403,8 +383,8 @@ class BIP68Test(BitcoinTestFramework):
assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active')
sync_blocks(self.nodes)
- # Use self.nodes[1] to test standardness relay policy
- def test_version2_relay(self, before_activation):
+ # Use self.nodes[1] to test that version 2 transactions are standard.
+ def test_version2_relay(self):
inputs = [ ]
outputs = { self.nodes[1].getnewaddress() : 1.0 }
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
@@ -412,12 +392,7 @@ class BIP68Test(BitcoinTestFramework):
tx = FromHex(CTransaction(), rawtxfund)
tx.nVersion = 2
tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"]
- try:
- tx_id = self.nodes[1].sendrawtransaction(tx_signed)
- assert(before_activation == False)
- except:
- assert(before_activation)
-
+ tx_id = self.nodes[1].sendrawtransaction(tx_signed)
if __name__ == '__main__':
BIP68Test().main()
diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py
index 70d4be3f69..0dffd06e1a 100755
--- a/qa/rpc-tests/bip9-softforks.py
+++ b/qa/rpc-tests/bip9-softforks.py
@@ -35,7 +35,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
def setup_network(self):
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']],
+ extra_args=[['-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
def run_test(self):
diff --git a/qa/rpc-tests/bipdersig-p2p.py b/qa/rpc-tests/bipdersig-p2p.py
index b82ef89395..22bd39fbe5 100755
--- a/qa/rpc-tests/bipdersig-p2p.py
+++ b/qa/rpc-tests/bipdersig-p2p.py
@@ -50,7 +50,7 @@ class BIP66Test(ComparisonTestFramework):
def setup_network(self):
# Must set the blockversion for this test
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']],
+ extra_args=[['-whitelist=127.0.0.1', '-blockversion=2']],
binary=[self.options.testbinary])
def run_test(self):
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 cc897a32c7..8f75e9ed4d 100755
--- a/qa/rpc-tests/bumpfee.py
+++ b/qa/rpc-tests/bumpfee.py
@@ -26,7 +26,7 @@ class BumpFeeTest(BitcoinTestFramework):
self.setup_clean_chain = True
def setup_network(self, split=False):
- extra_args = [["-debug", "-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
+ extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
for i in range(self.num_nodes)]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
@@ -45,7 +45,7 @@ class BumpFeeTest(BitcoinTestFramework):
rbf_node_address = rbf_node.getnewaddress()
# fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
peer_node.generate(110)
self.sync_all()
for i in range(25):
@@ -55,7 +55,7 @@ class BumpFeeTest(BitcoinTestFramework):
self.sync_all()
assert_equal(rbf_node.getbalance(), Decimal("0.025"))
- print("Running tests")
+ self.log.info("Running tests")
dest_address = peer_node.getnewaddress()
test_small_output_fails(rbf_node, dest_address)
test_dust_to_fee(rbf_node, dest_address)
@@ -70,7 +70,7 @@ class BumpFeeTest(BitcoinTestFramework):
test_unconfirmed_not_spendable(rbf_node, rbf_node_address)
test_bumpfee_metadata(rbf_node, dest_address)
test_locked_wallet_fails(rbf_node, dest_address)
- print("Success")
+ self.log.info("Success")
def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):
@@ -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"],
@@ -128,7 +128,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
def test_nonrbf_bumpfee_fails(peer_node, dest_address):
# cannot replace a non RBF transaction (from node which did not enable RBF)
not_rbfid = create_fund_sign_send(peer_node, {dest_address: 0.00090000})
- assert_raises_message(JSONRPCException, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
+ assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
@@ -148,7 +148,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
signedtx = rbf_node.signrawtransaction(rawtx)
signedtx = peer_node.signrawtransaction(signedtx["hex"])
rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
- assert_raises_message(JSONRPCException, "Transaction contains inputs that don't belong to this wallet",
+ assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet",
rbf_node.bumpfee, rbfid)
@@ -159,7 +159,7 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
tx = rbf_node.signrawtransaction(tx)
txid = rbf_node.sendrawtransaction(tx["hex"])
- assert_raises_message(JSONRPCException, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+ assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
def test_small_output_fails(rbf_node, dest_address):
@@ -174,7 +174,7 @@ def test_small_output_fails(rbf_node, dest_address):
Decimal("0.00100000"),
{dest_address: 0.00080000,
get_change_address(rbf_node): Decimal("0.00010000")})
- assert_raises_message(JSONRPCException, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001})
+ assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001})
def test_dust_to_fee(rbf_node, dest_address):
@@ -209,7 +209,7 @@ def test_rebumping(rbf_node, dest_address):
rbf_node.settxfee(Decimal("0.00001000"))
rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
bumped = rbf_node.bumpfee(rbfid, {"totalFee": 1000})
- assert_raises_message(JSONRPCException, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000})
+ assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000})
rbf_node.bumpfee(bumped["txid"], {"totalFee": 2000})
@@ -217,7 +217,7 @@ def test_rebumping_not_replaceable(rbf_node, dest_address):
# check that re-bumping a non-replaceable bump tx fails
rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
- assert_raises_message(JSONRPCException, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
+ assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
{"totalFee": 20000})
@@ -268,7 +268,7 @@ def test_bumpfee_metadata(rbf_node, dest_address):
def test_locked_wallet_fails(rbf_node, dest_address):
rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
rbf_node.walletlock()
- assert_raises_message(JSONRPCException, "Please enter the wallet passphrase with walletpassphrase first.",
+ assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.",
rbf_node.bumpfee, rbfid)
@@ -315,9 +315,7 @@ def submit_block_with_tx(node, tx):
block.rehash()
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- error = node.submitblock(bytes_to_hex_str(block.serialize(True)))
- if error is not None:
- raise Exception(error)
+ node.submitblock(bytes_to_hex_str(block.serialize(True)))
return block
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/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index 7892e85e22..fd330ef277 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -34,8 +34,6 @@ class RawTransactionsTest(BitcoinTestFramework):
self.sync_all()
def run_test(self):
- print("Mining blocks...")
-
min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
# This test is not meant to test fee estimation and we'd like
# to be sure all txs are sent at a consistent desired feerate
@@ -182,12 +180,7 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
- try:
- self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'})
- raise AssertionError("Accepted invalid option foo")
- except JSONRPCException as e:
- assert("Unexpected key foo" in e.error['message'])
-
+ assert_raises_jsonrpc(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'})
############################################################
# test a fundrawtransaction with an invalid change address #
@@ -200,12 +193,7 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
- try:
- self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': 'foobar'})
- raise AssertionError("Accepted invalid bitcoin address")
- except JSONRPCException as e:
- assert("changeAddress must be a valid bitcoin address" in e.error['message'])
-
+ assert_raises_jsonrpc(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'})
############################################################
# test a fundrawtransaction with a provided change address #
@@ -219,12 +207,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
change = self.nodes[2].getnewaddress()
- try:
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 2})
- except JSONRPCException as e:
- assert('changePosition out of bounds' == e.error['message'])
- else:
- assert(False)
+ assert_raises_jsonrpc(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2})
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
out = dec_tx['vout'][0]
@@ -333,12 +316,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
dec_tx = self.nodes[2].decoderawtransaction(rawtx)
- try:
- rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
- raise AssertionError("Spent more than available")
- except JSONRPCException as e:
- assert("Insufficient" in e.error['message'])
-
+ assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx)
############################################################
#compare fee of a standard pubkeyhash transaction
@@ -494,21 +472,13 @@ class RawTransactionsTest(BitcoinTestFramework):
rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
# fund a transaction that requires a new key for the change output
# creating the key must be impossible because the wallet is locked
- try:
- fundedTx = self.nodes[1].fundrawtransaction(rawTx)
- raise AssertionError("Wallet unlocked without passphrase")
- except JSONRPCException as e:
- assert('Keypool ran out' in e.error['message'])
+ assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[1].fundrawtransaction, rawtx)
#refill the keypool
self.nodes[1].walletpassphrase("test", 100)
self.nodes[1].walletlock()
- try:
- self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
- raise AssertionError("Wallet unlocked without passphrase")
- except JSONRPCException as e:
- assert('walletpassphrase' in e.error['message'])
+ assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2)
oldBalance = self.nodes[0].getbalance()
diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py
index b73fea0695..bbe1dda5f7 100755
--- a/qa/rpc-tests/getblocktemplate_longpoll.py
+++ b/qa/rpc-tests/getblocktemplate_longpoll.py
@@ -29,7 +29,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
self.setup_clean_chain = False
def run_test(self):
- print("Warning: this test will take about 70 seconds in the best case. Be patient.")
+ self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
self.nodes[0].generate(10)
templat = self.nodes[0].getblocktemplate()
longpollid = templat['longpollid']
@@ -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/import-rescan.py b/qa/rpc-tests/import-rescan.py
index 7ca61824c9..0218a46168 100755
--- a/qa/rpc-tests/import-rescan.py
+++ b/qa/rpc-tests/import-rescan.py
@@ -7,11 +7,11 @@
Test rescan behavior of importaddress, importpubkey, importprivkey, and
importmulti RPCs with different types of keys and rescan options.
-In the first part of the test, node 1 creates an address for each type of
-import RPC call and node 0 sends BTC to it. Then other nodes import the
-addresses, and the test makes listtransactions and getbalance calls to confirm
-that the importing node either did or did not execute rescans picking up the
-send transactions.
+In the first part of the test, node 0 creates an address for each type of
+import RPC call and sends BTC to it. Then other nodes import the addresses,
+and the test makes listtransactions and getbalance calls to confirm that the
+importing node either did or did not execute rescans picking up the send
+transactions.
In the second part of the test, node 0 sends more BTC to each address, and the
test makes more listtransactions and getbalance calls to confirm that the
@@ -56,7 +56,7 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
"scriptPubKey": {
"address": self.address["address"]
},
- "timestamp": timestamp + RESCAN_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
+ "timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
"keys": [self.key] if self.data == Data.priv else [],
"label": self.label,
@@ -108,7 +108,7 @@ ImportNode = collections.namedtuple("ImportNode", "prune rescan")
IMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True), repeat=2)]
# Rescans start at the earliest block up to 2 hours before the key timestamp.
-RESCAN_WINDOW = 2 * 60 * 60
+TIMESTAMP_WINDOW = 2 * 60 * 60
class ImportRescanTest(BitcoinTestFramework):
@@ -117,7 +117,7 @@ class ImportRescanTest(BitcoinTestFramework):
self.num_nodes = 2 + len(IMPORT_NODES)
def setup_network(self):
- extra_args = [["-debug=1"] for _ in range(self.num_nodes)]
+ extra_args = [[] for _ in range(self.num_nodes)]
for i, import_node in enumerate(IMPORT_NODES, 2):
if import_node.prune:
extra_args[i] += ["-prune=1"]
@@ -141,7 +141,7 @@ class ImportRescanTest(BitcoinTestFramework):
self.nodes[0].generate(1)
assert_equal(self.nodes[0].getrawmempool(), [])
timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
- set_node_times(self.nodes, timestamp + RESCAN_WINDOW + 1)
+ set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1)
self.nodes[0].generate(1)
sync_blocks(self.nodes)
diff --git a/qa/rpc-tests/importmulti.py b/qa/rpc-tests/importmulti.py
index b6a533502a..ca5d42eced 100755
--- a/qa/rpc-tests/importmulti.py
+++ b/qa/rpc-tests/importmulti.py
@@ -17,7 +17,7 @@ class ImportMultiTest (BitcoinTestFramework):
self.is_network_split=False
def run_test (self):
- print ("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
@@ -48,7 +48,7 @@ class ImportMultiTest (BitcoinTestFramework):
# RPC importmulti -----------------------------------------------
# Bitcoin Address
- print("Should import an address")
+ self.log.info("Should import an address")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": {
@@ -64,7 +64,7 @@ class ImportMultiTest (BitcoinTestFramework):
watchonly_address = address['address']
watchonly_timestamp = timestamp
- print("Should not import an invalid address")
+ self.log.info("Should not import an invalid address")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": "not valid address",
@@ -76,7 +76,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(result[0]['error']['message'], 'Invalid address')
# ScriptPubKey + internal
- print("Should import a scriptPubKey with internal flag")
+ self.log.info("Should import a scriptPubKey with internal flag")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
@@ -90,7 +90,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + !internal
- print("Should not import a scriptPubKey without internal flag")
+ self.log.info("Should not import a scriptPubKey without internal flag")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
@@ -106,7 +106,7 @@ class ImportMultiTest (BitcoinTestFramework):
# Address + Public key + !Internal
- print("Should import an address with public key")
+ self.log.info("Should import an address with public key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": {
@@ -123,7 +123,7 @@ class ImportMultiTest (BitcoinTestFramework):
# ScriptPubKey + Public key + internal
- print("Should import a scriptPubKey with internal and with public key")
+ self.log.info("Should import a scriptPubKey with internal and with public key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
request = [{
"scriptPubKey": address['scriptPubKey'],
@@ -139,7 +139,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + Public key + !internal
- print("Should not import a scriptPubKey without internal and with public key")
+ self.log.info("Should not import a scriptPubKey without internal and with public key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
request = [{
"scriptPubKey": address['scriptPubKey'],
@@ -156,7 +156,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal('timestamp' in address_assert, False)
# Address + Private key + !watchonly
- print("Should import an address with private key")
+ self.log.info("Should import an address with private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": {
@@ -172,7 +172,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['timestamp'], timestamp)
# Address + Private key + watchonly
- print("Should not import an address with private key and with watchonly")
+ self.log.info("Should not import an address with private key and with watchonly")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": {
@@ -191,7 +191,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal('timestamp' in address_assert, False)
# ScriptPubKey + Private key + internal
- print("Should import a scriptPubKey with internal and with private key")
+ self.log.info("Should import a scriptPubKey with internal and with private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
@@ -206,7 +206,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['timestamp'], timestamp)
# ScriptPubKey + Private key + !internal
- print("Should not import a scriptPubKey without internal and with private key")
+ self.log.info("Should not import a scriptPubKey without internal and with private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
"scriptPubKey": address['scriptPubKey'],
@@ -233,7 +233,7 @@ class ImportMultiTest (BitcoinTestFramework):
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
transaction = self.nodes[1].gettransaction(transactionid)
- print("Should import a p2sh")
+ self.log.info("Should import a p2sh")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
@@ -261,7 +261,7 @@ class ImportMultiTest (BitcoinTestFramework):
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
transaction = self.nodes[1].gettransaction(transactionid)
- print("Should import a p2sh with respective redeem script")
+ self.log.info("Should import a p2sh with respective redeem script")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
@@ -289,7 +289,7 @@ class ImportMultiTest (BitcoinTestFramework):
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
transaction = self.nodes[1].gettransaction(transactionid)
- print("Should import a p2sh with respective redeem script and private keys")
+ self.log.info("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
@@ -317,7 +317,7 @@ class ImportMultiTest (BitcoinTestFramework):
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
transaction = self.nodes[1].gettransaction(transactionid)
- print("Should import a p2sh with respective redeem script and private keys")
+ self.log.info("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
"scriptPubKey": {
"address": multi_sig_script['address']
@@ -333,7 +333,7 @@ class ImportMultiTest (BitcoinTestFramework):
# Address + Public key + !Internal + Wrong pubkey
- print("Should not import an address with a wrong public key")
+ self.log.info("Should not import an address with a wrong public key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
@@ -353,7 +353,7 @@ class ImportMultiTest (BitcoinTestFramework):
# ScriptPubKey + Public key + internal + Wrong pubkey
- print("Should not import a scriptPubKey with internal and with a wrong public key")
+ self.log.info("Should not import a scriptPubKey with internal and with a wrong public key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
request = [{
@@ -373,7 +373,7 @@ class ImportMultiTest (BitcoinTestFramework):
# Address + Private key + !watchonly + Wrong private key
- print("Should not import an address with a wrong private key")
+ self.log.info("Should not import an address with a wrong private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
@@ -393,7 +393,7 @@ class ImportMultiTest (BitcoinTestFramework):
# ScriptPubKey + Private key + internal + Wrong private key
- print("Should not import a scriptPubKey with internal and with a wrong private key")
+ self.log.info("Should not import a scriptPubKey with internal and with a wrong private key")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
result = self.nodes[1].importmulti([{
@@ -437,7 +437,7 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['timestamp'], watchonly_timestamp);
# Bad or missing timestamps
- print("Should throw on invalid or missing timestamp values")
+ self.log.info("Should throw on invalid or missing timestamp values")
assert_raises_message(JSONRPCException, 'Missing required timestamp field for key',
self.nodes[1].importmulti, [{
"scriptPubKey": address['scriptPubKey'],
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
index a941124656..b4c8ee6c70 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -21,7 +21,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.sync_all()
def run_test(self):
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(101)
self.sync_all()
@@ -76,12 +76,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.sync_all()
#Import with no affiliated address
- try:
- self.nodes[1].importprunedfunds(rawtxn1, proof1)
- except JSONRPCException as e:
- assert('No addresses' in e.error['message'])
- else:
- assert(False)
+ assert_raises_jsonrpc(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1)
balance1 = self.nodes[1].getbalance("", 0, True)
assert_equal(balance1, Decimal(0))
@@ -112,12 +107,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
assert_equal(address_info['ismine'], True)
#Remove transactions
- try:
- self.nodes[1].removeprunedfunds(txnid1)
- except JSONRPCException as e:
- assert('does not exist' in e.error['message'])
- else:
- assert(False)
+ assert_raises_jsonrpc(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1)
balance1 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance1, Decimal('0.075'))
diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py
index 92e65927d5..8c80b64003 100755
--- a/qa/rpc-tests/invalidateblock.py
+++ b/qa/rpc-tests/invalidateblock.py
@@ -18,53 +18,51 @@ class InvalidateTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
self.is_network_split = False
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"]))
+ self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes.append(start_node(1, self.options.tmpdir))
+ self.nodes.append(start_node(2, self.options.tmpdir))
def run_test(self):
- print("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
- print("Mine 4 blocks on Node 0")
+ self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:")
+ self.log.info("Mine 4 blocks on Node 0")
self.nodes[0].generate(4)
assert(self.nodes[0].getblockcount() == 4)
besthash = self.nodes[0].getbestblockhash()
- print("Mine competing 6 blocks on Node 1")
+ self.log.info("Mine competing 6 blocks on Node 1")
self.nodes[1].generate(6)
assert(self.nodes[1].getblockcount() == 6)
- print("Connect nodes to force a reorg")
+ self.log.info("Connect nodes to force a reorg")
connect_nodes_bi(self.nodes,0,1)
sync_blocks(self.nodes[0:2])
assert(self.nodes[0].getblockcount() == 6)
badhash = self.nodes[1].getblockhash(2)
- print("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain")
+ self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain")
self.nodes[0].invalidateblock(badhash)
newheight = self.nodes[0].getblockcount()
newhash = self.nodes[0].getbestblockhash()
if (newheight != 4 or newhash != besthash):
raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight))
- print("\nMake sure we won't reorg to a lower work chain:")
+ self.log.info("Make sure we won't reorg to a lower work chain:")
connect_nodes_bi(self.nodes,1,2)
- print("Sync node 2 to node 1 so both have 6 blocks")
+ self.log.info("Sync node 2 to node 1 so both have 6 blocks")
sync_blocks(self.nodes[1:3])
assert(self.nodes[2].getblockcount() == 6)
- print("Invalidate block 5 on node 1 so its tip is now at 4")
+ self.log.info("Invalidate block 5 on node 1 so its tip is now at 4")
self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5))
assert(self.nodes[1].getblockcount() == 4)
- print("Invalidate block 3 on node 2, so its tip is now 2")
+ self.log.info("Invalidate block 3 on node 2, so its tip is now 2")
self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3))
assert(self.nodes[2].getblockcount() == 2)
- print("..and then mine a block")
+ self.log.info("..and then mine a block")
self.nodes[2].generate(1)
- print("Verify all nodes are at the right height")
+ self.log.info("Verify all nodes are at the right height")
time.sleep(5)
- for i in range(3):
- print(i,self.nodes[i].getblockcount())
- assert(self.nodes[2].getblockcount() == 3)
- assert(self.nodes[0].getblockcount() == 4)
+ assert_equal(self.nodes[2].getblockcount(), 3)
+ assert_equal(self.nodes[0].getblockcount(), 4)
node1height = self.nodes[1].getblockcount()
if node1height < 4:
raise AssertionError("Node 1 reorged to a lower height: %d"%node1height)
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/listsinceblock.py b/qa/rpc-tests/listsinceblock.py
index 88304af5b0..a75e66c8c4 100755
--- a/qa/rpc-tests/listsinceblock.py
+++ b/qa/rpc-tests/listsinceblock.py
@@ -62,7 +62,7 @@ class ListSinceBlockTest (BitcoinTestFramework):
# generate on both sides
lastblockhash = self.nodes[1].generate(6)[5]
self.nodes[2].generate(7)
- print('lastblockhash=%s' % (lastblockhash))
+ self.log.info('lastblockhash=%s' % (lastblockhash))
self.sync_all()
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 8ea405b4d5..2c3766125a 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -13,7 +13,6 @@ reach. [0.10 clients shouldn't request more than 16 from a single peer.]
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import logging
MAX_REQUESTS = 128
@@ -33,7 +32,6 @@ class TestManager(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.log = logging.getLogger("BlockRelayTest")
def add_new_connection(self, connection):
self.connection = connection
@@ -65,7 +63,7 @@ class TestManager(NodeConnCB):
raise AssertionError("Error, test failed: block %064x requested more than once" % key)
if total_requests > MAX_REQUESTS:
raise AssertionError("Error, too many blocks (%d) requested" % total_requests)
- print("Round %d: success (total requests: %d)" % (count, total_requests))
+ self.log.info("Round %d: success (total requests: %d)" % (count, total_requests))
self.disconnectOkay = True
self.connection.disconnect_node()
@@ -84,11 +82,13 @@ class MaxBlocksInFlightTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']],
+ extra_args=[['-whitelist=127.0.0.1']],
binary=[self.options.testbinary])
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/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index 757aa60afd..40cd85c9ec 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -90,7 +90,7 @@ class MaxUploadTest(BitcoinTestFramework):
def setup_network(self):
# Start a node with maxuploadtarget of 200 MB (/24h)
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-maxuploadtarget=800", "-blockmaxsize=999000"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxuploadtarget=800", "-blockmaxsize=999000"]))
def run_test(self):
# Before we connect anything, we first set the time on the node
@@ -161,7 +161,7 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[0].send_message(getdata_request)
test_nodes[0].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 2)
- print("Peer 0 disconnected after downloading old block too many times")
+ self.log.info("Peer 0 disconnected after downloading old block too many times")
# Requesting the current block on test_nodes[1] should succeed indefinitely,
# even when over the max upload target.
@@ -172,7 +172,7 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[1].sync_with_ping()
assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1)
- print("Peer 1 able to repeatedly download new block")
+ self.log.info("Peer 1 able to repeatedly download new block")
# But if test_nodes[1] tries for an old block, it gets disconnected too.
getdata_request.inv = [CInv(2, big_old_block)]
@@ -180,9 +180,9 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[1].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 1)
- print("Peer 1 disconnected after trying to download old block")
+ self.log.info("Peer 1 disconnected after trying to download old block")
- print("Advancing system time on node to clear counters...")
+ self.log.info("Advancing system time on node to clear counters...")
# If we advance the time by 24 hours, then the counters should reset,
# and test_nodes[2] should be able to retrieve the old block.
@@ -192,14 +192,14 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[2].sync_with_ping()
assert_equal(test_nodes[2].block_receive_map[big_old_block], 1)
- print("Peer 2 able to download old block")
+ self.log.info("Peer 2 able to download old block")
[c.disconnect_node() for c in connections]
#stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1
- print("Restarting nodes with -whitelist=127.0.0.1")
+ self.log.info("Restarting nodes with -whitelist=127.0.0.1")
stop_node(self.nodes[0], 0)
- self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
+ self.nodes[0] = start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
#recreate/reconnect 3 test nodes
test_nodes = []
@@ -225,7 +225,7 @@ class MaxUploadTest(BitcoinTestFramework):
test_nodes[1].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist
- print("Peer 1 still connected after trying to download old block (whitelisted)")
+ self.log.info("Peer 1 still connected after trying to download old block (whitelisted)")
[c.disconnect_node() for c in connections]
diff --git a/qa/rpc-tests/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
index 8fae92ad2b..a7ca576aee 100755
--- a/qa/rpc-tests/mempool_limit.py
+++ b/qa/rpc-tests/mempool_limit.py
@@ -11,7 +11,7 @@ class MempoolLimitTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0"]))
self.is_network_split = False
self.sync_all()
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 388889d07c..17e3a9a967 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -19,8 +19,8 @@ class MempoolPackagesTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-limitancestorcount=5", "-debug"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000"]))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-limitancestorcount=5"]))
connect_nodes(self.nodes[0], 1)
self.is_network_split = False
self.sync_all()
@@ -103,7 +103,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Check that descendant modified fees includes fee deltas from
# prioritisetransaction
- self.nodes[0].prioritisetransaction(chain[-1], 0, 1000)
+ self.nodes[0].prioritisetransaction(chain[-1], 1000)
mempool = self.nodes[0].getrawmempool(True)
descendant_fees = 0
@@ -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:
- print("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.
@@ -124,7 +121,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getrawmempool()), 0)
# Prioritise a transaction that has been mined, then add it back to the
# mempool by using invalidateblock.
- self.nodes[0].prioritisetransaction(chain[-1], 0, 2000)
+ self.nodes[0].prioritisetransaction(chain[-1], 2000)
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# Keep node1's tip synced with node0
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
@@ -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:
- print(e.error['message'])
- assert_equal(i, MAX_DESCENDANTS - 1)
- print("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 2cd5573277..812b54ffcb 100755
--- a/qa/rpc-tests/mempool_reorg.py
+++ b/qa/rpc-tests/mempool_reorg.py
@@ -21,7 +21,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
alert_filename = None # Set by setup_network
def setup_network(self):
- args = ["-checkmempool", "-debug=mempool"]
+ args = ["-checkmempool"]
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, args))
self.nodes.append(start_node(1, self.options.tmpdir, args))
@@ -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_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py
index c7f37aaa44..727892d1f2 100755
--- a/qa/rpc-tests/mempool_resurrect_test.py
+++ b/qa/rpc-tests/mempool_resurrect_test.py
@@ -17,7 +17,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
def setup_network(self):
# Just need one node for this test
- args = ["-checkmempool", "-debug=mempool"]
+ args = ["-checkmempool"]
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, args))
self.is_network_split = False
diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py
index da8485e2a2..f562a93d86 100755
--- a/qa/rpc-tests/mempool_spendcoinbase.py
+++ b/qa/rpc-tests/mempool_spendcoinbase.py
@@ -25,7 +25,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework):
def setup_network(self):
# Just need one node for this test
- args = ["-checkmempool", "-debug=mempool"]
+ args = ["-checkmempool"]
self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, args))
self.is_network_split = False
@@ -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/merkle_blocks.py b/qa/rpc-tests/merkle_blocks.py
index c4b45425d7..5963f2e7b6 100755
--- a/qa/rpc-tests/merkle_blocks.py
+++ b/qa/rpc-tests/merkle_blocks.py
@@ -17,11 +17,11 @@ class MerkleBlockTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
# Nodes 0/1 are "wallet" nodes
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"]))
+ self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes.append(start_node(1, self.options.tmpdir))
# Nodes 2/3 are used for testing
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"]))
- self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-txindex"]))
+ self.nodes.append(start_node(2, self.options.tmpdir))
+ self.nodes.append(start_node(3, self.options.tmpdir, ["-txindex"]))
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)
connect_nodes(self.nodes[0], 3)
@@ -30,7 +30,7 @@ class MerkleBlockTest(BitcoinTestFramework):
self.sync_all()
def run_test(self):
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(105)
self.sync_all()
diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py
index 89059d2760..a6b10a0d83 100755
--- a/qa/rpc-tests/nodehandling.py
+++ b/qa/rpc-tests/nodehandling.py
@@ -29,15 +29,13 @@ class NodeHandlingTest (BitcoinTestFramework):
assert_equal(len(self.nodes[2].listbanned()), 0)
self.nodes[2].setban("127.0.0.0/24", "add")
assert_equal(len(self.nodes[2].listbanned()), 1)
- try:
- self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24
- except:
- pass
+ # This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24
+ assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[2].setban, "127.0.0.1", "add")
+ # This will throw an exception because 127.0.0.1/42 is not a real subnet
+ assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[2].setban, "127.0.0.1/42", "add")
assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
- try:
- self.nodes[2].setban("127.0.0.1", "remove")
- except:
- pass
+ # This will throw an exception because 127.0.0.1 was not added above
+ assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[2].setban, "127.0.0.1", "remove")
assert_equal(len(self.nodes[2].listbanned()), 1)
self.nodes[2].setban("127.0.0.0/24", "remove")
assert_equal(len(self.nodes[2].listbanned()), 0)
diff --git a/qa/rpc-tests/nulldummy.py b/qa/rpc-tests/nulldummy.py
index 66c4e90f21..7b19fbfd82 100755
--- a/qa/rpc-tests/nulldummy.py
+++ b/qa/rpc-tests/nulldummy.py
@@ -45,7 +45,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
def setup_network(self):
# Must set the blockversion for this test
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1', '-walletprematurewitness']])
+ extra_args=[['-whitelist=127.0.0.1', '-walletprematurewitness']])
def run_test(self):
self.address = self.nodes[0].getnewaddress()
@@ -64,40 +64,40 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.lastblockheight = 429
self.lastblocktime = int(time.time()) + 429
- print ("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]")
+ 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)
- print ("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, 48)
+ 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)
- print ("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]")
+ 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)
- print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
- test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 47)
+ 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])
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)
- print ("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]")
+ 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-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
index 2f21fa149a..e1111da4ae 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -119,10 +119,10 @@ class AcceptBlockTest(BitcoinTestFramework):
# from peers which are not whitelisted, while Node1 will be used for
# the whitelisted case.
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"],
+ self.nodes.append(start_node(0, self.options.tmpdir,
binary=self.options.testbinary))
self.nodes.append(start_node(1, self.options.tmpdir,
- ["-debug", "-whitelist=127.0.0.1"],
+ ["-whitelist=127.0.0.1"],
binary=self.options.testbinary))
def run_test(self):
@@ -160,7 +160,7 @@ class AcceptBlockTest(BitcoinTestFramework):
[ x.sync_with_ping() for x in [test_node, white_node] ]
assert_equal(self.nodes[0].getblockcount(), 2)
assert_equal(self.nodes[1].getblockcount(), 2)
- print("First height 2 block accepted by both nodes")
+ self.log.info("First height 2 block accepted by both nodes")
# 3. Send another block that builds on the original tip.
blocks_h2f = [] # Blocks at height 2 that fork off the main chain
@@ -179,7 +179,7 @@ class AcceptBlockTest(BitcoinTestFramework):
if x['hash'] == blocks_h2f[1].hash:
assert_equal(x['status'], "valid-headers")
- print("Second height 2 block accepted only from whitelisted peer")
+ self.log.info("Second height 2 block accepted only from whitelisted peer")
# 4. Now send another block that builds on the forking chain.
blocks_h3 = []
@@ -197,15 +197,12 @@ class AcceptBlockTest(BitcoinTestFramework):
assert_equal(x['status'], "headers-only")
# But this block should be accepted by node0 since it has more work.
- try:
- self.nodes[0].getblock(blocks_h3[0].hash)
- print("Unrequested more-work block accepted from non-whitelisted peer")
- except:
- raise AssertionError("Unrequested more work block was not processed")
+ self.nodes[0].getblock(blocks_h3[0].hash)
+ self.log.info("Unrequested more-work block accepted from non-whitelisted peer")
# Node1 should have accepted and reorged.
assert_equal(self.nodes[1].getblockcount(), 3)
- print("Successfully reorged to length 3 chain from whitelisted peer")
+ self.log.info("Successfully reorged to length 3 chain from whitelisted peer")
# 4b. Now mine 288 more blocks and deliver; all should be processed but
# the last (height-too-high) on node0. Node1 should process the tip if
@@ -225,26 +222,17 @@ class AcceptBlockTest(BitcoinTestFramework):
tips[j] = next_block
time.sleep(2)
- for x in all_blocks:
- try:
- self.nodes[0].getblock(x.hash)
- if x == all_blocks[287]:
- raise AssertionError("Unrequested block too far-ahead should have been ignored")
- except:
- if x == all_blocks[287]:
- print("Unrequested block too far-ahead not processed")
- else:
- raise AssertionError("Unrequested block with more work should have been accepted")
+ # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead
+ for x in all_blocks[:-1]:
+ self.nodes[0].getblock(x.hash)
+ assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash)
headers_message.headers.pop() # Ensure the last block is unrequested
white_node.send_message(headers_message) # Send headers leading to tip
white_node.send_message(msg_block(tips[1])) # Now deliver the tip
- try:
- white_node.sync_with_ping()
- self.nodes[1].getblock(tips[1].hash)
- print("Unrequested block far ahead of tip accepted from whitelisted peer")
- except:
- raise AssertionError("Unrequested block from whitelisted peer not accepted")
+ white_node.sync_with_ping()
+ self.nodes[1].getblock(tips[1].hash)
+ self.log.info("Unrequested block far ahead of tip accepted from whitelisted peer")
# 5. Test handling of unrequested block on the node that didn't process
# Should still not be processed (even though it has a child that has more
@@ -258,7 +246,7 @@ class AcceptBlockTest(BitcoinTestFramework):
# a getdata request for this block.
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 2)
- print("Unrequested block that would complete more-work chain was ignored")
+ self.log.info("Unrequested block that would complete more-work chain was ignored")
# 6. Try to get node to request the missing block.
# Poke the node with an inv for block at height 3 and see if that
@@ -274,14 +262,14 @@ class AcceptBlockTest(BitcoinTestFramework):
# Check that the getdata includes the right block
assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
- print("Inv at tip triggered getdata for unprocessed block")
+ self.log.info("Inv at tip triggered getdata for unprocessed block")
# 7. Send the missing block for the third time (now it is requested)
test_node.send_message(msg_block(blocks_h2f[0]))
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 290)
- print("Successfully reorged to longer chain from non-whitelisted peer")
+ self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
[ c.disconnect_node() for c in connections ]
diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py
index 79561f35f7..1fc0312c34 100755
--- a/qa/rpc-tests/p2p-compactblocks.py
+++ b/qa/rpc-tests/p2p-compactblocks.py
@@ -120,8 +120,8 @@ class CompactBlocksTest(BitcoinTestFramework):
# Start up node0 to be a version 1, pre-segwit node.
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- [["-debug", "-logtimemicros=1", "-bip9params=segwit:0:0"],
- ["-debug", "-logtimemicros", "-txindex"]])
+ [["-bip9params=segwit:0:0"],
+ ["-txindex"]])
connect_nodes(self.nodes[0], 1)
def build_block_on_tip(self, node, segwit=False):
@@ -846,102 +846,102 @@ class CompactBlocksTest(BitcoinTestFramework):
# We will need UTXOs to construct transactions in later tests.
self.make_utxos()
- print("Running tests, pre-segwit activation:")
+ self.log.info("Running tests, pre-segwit activation:")
- print("\tTesting SENDCMPCT p2p message... ")
+ self.log.info("Testing SENDCMPCT p2p message... ")
self.test_sendcmpct(self.nodes[0], self.test_node, 1)
sync_blocks(self.nodes)
self.test_sendcmpct(self.nodes[1], self.segwit_node, 2, old_node=self.old_node)
sync_blocks(self.nodes)
- print("\tTesting compactblock construction...")
+ self.log.info("Testing compactblock construction...")
self.test_compactblock_construction(self.nodes[0], self.test_node, 1, False)
sync_blocks(self.nodes)
self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, False)
sync_blocks(self.nodes)
- print("\tTesting compactblock requests... ")
+ self.log.info("Testing compactblock requests... ")
self.test_compactblock_requests(self.nodes[0], self.test_node, 1, False)
sync_blocks(self.nodes)
self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, False)
sync_blocks(self.nodes)
- print("\tTesting getblocktxn requests...")
+ self.log.info("Testing getblocktxn requests...")
self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
sync_blocks(self.nodes)
self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
sync_blocks(self.nodes)
- print("\tTesting getblocktxn handler...")
+ self.log.info("Testing getblocktxn handler...")
self.test_getblocktxn_handler(self.nodes[0], self.test_node, 1)
sync_blocks(self.nodes)
self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
sync_blocks(self.nodes)
- print("\tTesting compactblock requests/announcements not at chain tip...")
+ self.log.info("Testing compactblock requests/announcements not at chain tip...")
self.test_compactblocks_not_at_tip(self.nodes[0], self.test_node)
sync_blocks(self.nodes)
self.test_compactblocks_not_at_tip(self.nodes[1], self.segwit_node)
self.test_compactblocks_not_at_tip(self.nodes[1], self.old_node)
sync_blocks(self.nodes)
- print("\tTesting handling of incorrect blocktxn responses...")
+ self.log.info("Testing handling of incorrect blocktxn responses...")
self.test_incorrect_blocktxn_response(self.nodes[0], self.test_node, 1)
sync_blocks(self.nodes)
self.test_incorrect_blocktxn_response(self.nodes[1], self.segwit_node, 2)
sync_blocks(self.nodes)
# End-to-end block relay tests
- print("\tTesting end-to-end block relay...")
+ self.log.info("Testing end-to-end block relay...")
self.request_cb_announcements(self.test_node, self.nodes[0], 1)
self.request_cb_announcements(self.old_node, self.nodes[1], 1)
self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
self.test_end_to_end_block_relay(self.nodes[0], [self.segwit_node, self.test_node, self.old_node])
self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
- print("\tTesting handling of invalid compact blocks...")
+ self.log.info("Testing handling of invalid compact blocks...")
self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False)
self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False)
- print("\tTesting reconstructing compact blocks from all peers...")
+ self.log.info("Testing reconstructing compact blocks from all peers...")
self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node)
sync_blocks(self.nodes)
# Advance to segwit activation
- print ("\nAdvancing to segwit activation\n")
+ self.log.info("Advancing to segwit activation")
self.activate_segwit(self.nodes[1])
- print ("Running tests, post-segwit activation...")
+ self.log.info("Running tests, post-segwit activation...")
- print("\tTesting compactblock construction...")
+ self.log.info("Testing compactblock construction...")
self.test_compactblock_construction(self.nodes[1], self.old_node, 1, True)
self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, True)
sync_blocks(self.nodes)
- print("\tTesting compactblock requests (unupgraded node)... ")
+ self.log.info("Testing compactblock requests (unupgraded node)... ")
self.test_compactblock_requests(self.nodes[0], self.test_node, 1, True)
- print("\tTesting getblocktxn requests (unupgraded node)...")
+ self.log.info("Testing getblocktxn requests (unupgraded node)...")
self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
# Need to manually sync node0 and node1, because post-segwit activation,
# node1 will not download blocks from node0.
- print("\tSyncing nodes...")
+ self.log.info("Syncing nodes...")
assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash())
while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()):
block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount()+1)
self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False))
assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())
- print("\tTesting compactblock requests (segwit node)... ")
+ self.log.info("Testing compactblock requests (segwit node)... ")
self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, True)
- print("\tTesting getblocktxn requests (segwit node)...")
+ self.log.info("Testing getblocktxn requests (segwit node)...")
self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
sync_blocks(self.nodes)
- print("\tTesting getblocktxn handler (segwit node should return witnesses)...")
+ self.log.info("Testing getblocktxn handler (segwit node should return witnesses)...")
self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
@@ -949,18 +949,18 @@ class CompactBlocksTest(BitcoinTestFramework):
# announcement to all peers.
# (Post-segwit activation, blocks won't propagate from node0 to node1
# automatically, so don't bother testing a block announced to node0.)
- print("\tTesting end-to-end block relay...")
+ self.log.info("Testing end-to-end block relay...")
self.request_cb_announcements(self.test_node, self.nodes[0], 1)
self.request_cb_announcements(self.old_node, self.nodes[1], 1)
self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
- print("\tTesting handling of invalid compact blocks...")
+ self.log.info("Testing handling of invalid compact blocks...")
self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, True)
self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, True)
- print("\tTesting invalid index in cmpctblock message...")
+ self.log.info("Testing invalid index in cmpctblock message...")
self.test_invalid_cmpctblock_message()
diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py
index 1c62961db0..d8f07700d0 100755
--- a/qa/rpc-tests/p2p-feefilter.py
+++ b/qa/rpc-tests/p2p-feefilter.py
@@ -53,8 +53,8 @@ class FeeFilterTest(BitcoinTestFramework):
# Node1 will be used to generate txs which should be relayed from Node0
# to our test node
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"]))
+ self.nodes.append(start_node(0, self.options.tmpdir))
+ self.nodes.append(start_node(1, self.options.tmpdir))
connect_nodes(self.nodes[0], 1)
def run_test(self):
diff --git a/qa/rpc-tests/p2p-leaktests.py b/qa/rpc-tests/p2p-leaktests.py
index bf08ea32f4..3a843197fb 100755
--- a/qa/rpc-tests/p2p-leaktests.py
+++ b/qa/rpc-tests/p2p-leaktests.py
@@ -32,7 +32,7 @@ class CLazyNode(NodeConnCB):
def bad_message(self, message):
self.unexpected_msg = True
- print("should not have received message: %s" % message.command)
+ self.log.info("should not have received message: %s" % message.command)
def on_open(self, conn):
self.connected = True
@@ -102,7 +102,7 @@ class P2PLeakTest(BitcoinTestFramework):
super().__init__()
self.num_nodes = 1
def setup_network(self):
- extra_args = [['-debug', '-banscore='+str(banscore)]
+ extra_args = [['-banscore='+str(banscore)]
for i in range(self.num_nodes)]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
diff --git a/qa/rpc-tests/p2p-mempool.py b/qa/rpc-tests/p2p-mempool.py
index c6b1490211..0aa9c90e8f 100755
--- a/qa/rpc-tests/p2p-mempool.py
+++ b/qa/rpc-tests/p2p-mempool.py
@@ -85,7 +85,7 @@ class P2PMempoolTests(BitcoinTestFramework):
def setup_network(self):
# Start a node with maxuploadtarget of 200 MB (/24h)
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-peerbloomfilters=0"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-peerbloomfilters=0"]))
def run_test(self):
#connect a mininode
diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py
index 470a5398b6..dcf2b9a7de 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/qa/rpc-tests/p2p-segwit.py
@@ -70,7 +70,6 @@ class TestNode(NodeConnCB):
def on_reject(self, conn, message):
self.last_reject = message
- #print (message)
# Syncing helpers
def sync(self, test_function, timeout=60):
@@ -195,13 +194,13 @@ class SegWitTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1"]))
# Start a node for testing IsStandard rules.
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1", "-acceptnonstdtxn=0"]))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"]))
connect_nodes(self.nodes[0], 1)
# Disable segwit's bip9 parameter to simulate upgrading after activation.
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-bip9params=segwit:0:0"]))
+ self.nodes.append(start_node(2, self.options.tmpdir, ["-whitelist=127.0.0.1", "-bip9params=segwit:0:0"]))
connect_nodes(self.nodes[0], 2)
''' Helpers '''
@@ -224,7 +223,7 @@ class SegWitTest(BitcoinTestFramework):
''' Individual tests '''
def test_witness_services(self):
- print("\tVerifying NODE_WITNESS service bit")
+ self.log.info("Verifying NODE_WITNESS service bit")
assert((self.test_node.connection.nServices & NODE_WITNESS) != 0)
@@ -233,7 +232,7 @@ class SegWitTest(BitcoinTestFramework):
def test_non_witness_transaction(self):
# Mine a block with an anyone-can-spend coinbase,
# let it mature, then try to spend it.
- print("\tTesting non-witness transaction")
+ self.log.info("Testing non-witness transaction")
block = self.build_next_block(nVersion=1)
block.solve()
self.test_node.send_message(msg_block(block))
@@ -262,7 +261,7 @@ class SegWitTest(BitcoinTestFramework):
# Verify that blocks with witnesses are rejected before activation.
def test_unnecessary_witness_before_segwit_activation(self):
- print("\tTesting behavior of unnecessary witnesses")
+ self.log.info("Testing behavior of unnecessary witnesses")
# For now, rely on earlier tests to have created at least one utxo for
# us to use
assert(len(self.utxo) > 0)
@@ -389,7 +388,7 @@ class SegWitTest(BitcoinTestFramework):
# This test can only be run after segwit has activated
def test_witness_commitments(self):
- print("\tTesting witness commitments")
+ self.log.info("Testing witness commitments")
# First try a correct witness commitment.
block = self.build_next_block()
@@ -478,7 +477,7 @@ class SegWitTest(BitcoinTestFramework):
def test_block_malleability(self):
- print("\tTesting witness block malleability")
+ self.log.info("Testing witness block malleability")
# Make sure that a block that has too big a virtual size
# because of a too-large coinbase witness is not permanently
@@ -519,7 +518,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_block_size(self):
- print("\tTesting witness block size limit")
+ self.log.info("Testing witness block size limit")
# TODO: Test that non-witness carrying blocks can't exceed 1MB
# Skipping this test for now; this is covered in p2p-fullblocktest.py
@@ -636,7 +635,7 @@ class SegWitTest(BitcoinTestFramework):
# Consensus tests of extra witness data in a transaction.
def test_extra_witness_data(self):
- print("\tTesting extra witness data in tx")
+ self.log.info("Testing extra witness data in tx")
assert(len(self.utxo) > 0)
@@ -712,7 +711,7 @@ class SegWitTest(BitcoinTestFramework):
def test_max_witness_push_length(self):
''' Should only allow up to 520 byte pushes in witness stack '''
- print("\tTesting maximum witness push size")
+ self.log.info("Testing maximum witness push size")
MAX_SCRIPT_ELEMENT_SIZE = 520
assert(len(self.utxo))
@@ -752,7 +751,7 @@ class SegWitTest(BitcoinTestFramework):
def test_max_witness_program_length(self):
# Can create witness outputs that are long, but can't be greater than
# 10k bytes to successfully spend
- print("\tTesting maximum witness program length")
+ self.log.info("Testing maximum witness program length")
assert(len(self.utxo))
MAX_PROGRAM_LENGTH = 10000
@@ -801,7 +800,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_input_length(self):
''' Ensure that vin length must match vtxinwit length '''
- print("\tTesting witness input length")
+ self.log.info("Testing witness input length")
assert(len(self.utxo))
witness_program = CScript([OP_DROP, OP_TRUE])
@@ -884,7 +883,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_tx_relay_before_segwit_activation(self):
- print("\tTesting relay of witness transactions")
+ self.log.info("Testing relay of witness transactions")
# Generate a transaction that doesn't require a witness, but send it
# with a witness. Should be rejected for premature-witness, but should
# not be added to recently rejected list.
@@ -908,7 +907,7 @@ class SegWitTest(BitcoinTestFramework):
# a witness transaction ought not result in a getdata.
try:
self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2)
- print("Error: duplicate tx getdata!")
+ self.log.error("Error: duplicate tx getdata!")
assert(False)
except AssertionError as e:
pass
@@ -936,7 +935,7 @@ class SegWitTest(BitcoinTestFramework):
# - accepts transactions with valid witnesses
# and that witness transactions are relayed to non-upgraded peers.
def test_tx_relay_after_segwit_activation(self):
- print("\tTesting relay of witness transactions")
+ self.log.info("Testing relay of witness transactions")
# Generate a transaction that doesn't require a witness, but send it
# with a witness. Should be rejected because we can't use a witness
# when spending a non-witness output.
@@ -1025,7 +1024,7 @@ class SegWitTest(BitcoinTestFramework):
# This is true regardless of segwit activation.
# Also test that we don't ask for blocks from unupgraded peers
def test_block_relay(self, segwit_activated):
- print("\tTesting block relay")
+ self.log.info("Testing block relay")
blocktype = 2|MSG_WITNESS_FLAG
@@ -1113,7 +1112,7 @@ class SegWitTest(BitcoinTestFramework):
# V0 segwit outputs should be standard after activation, but not before.
def test_standardness_v0(self, segwit_activated):
- print("\tTesting standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before"))
+ self.log.info("Testing standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before"))
assert(len(self.utxo))
witness_program = CScript([OP_TRUE])
@@ -1190,7 +1189,7 @@ class SegWitTest(BitcoinTestFramework):
# Verify that future segwit upgraded transactions are non-standard,
# but valid in blocks. Can run this before and after segwit activation.
def test_segwit_versions(self):
- print("\tTesting standardness/consensus for segwit versions (0-16)")
+ self.log.info("Testing standardness/consensus for segwit versions (0-16)")
assert(len(self.utxo))
NUM_TESTS = 17 # will test OP_0, OP1, ..., OP_16
if (len(self.utxo) < NUM_TESTS):
@@ -1274,7 +1273,7 @@ class SegWitTest(BitcoinTestFramework):
def test_premature_coinbase_witness_spend(self):
- print("\tTesting premature coinbase witness spend")
+ self.log.info("Testing premature coinbase witness spend")
block = self.build_next_block()
# Change the output of the block to be a witness output.
witness_program = CScript([OP_TRUE])
@@ -1309,7 +1308,7 @@ class SegWitTest(BitcoinTestFramework):
def test_signature_version_1(self):
- print("\tTesting segwit signature hash version 1")
+ self.log.info("Testing segwit signature hash version 1")
key = CECKey()
key.set_secretbytes(b"9")
pubkey = CPubKey(key.get_pubkey())
@@ -1428,7 +1427,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
if (not used_sighash_single_out_of_bounds):
- print("WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value")
+ self.log.info("WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value")
# Test the transactions we've added to the block
if (len(block.vtx) > 1):
self.update_witness_block_with_transactions(block, [])
@@ -1491,7 +1490,7 @@ class SegWitTest(BitcoinTestFramework):
# Test P2SH wrapped witness programs.
def test_p2sh_witness(self, segwit_activated):
- print("\tTesting P2SH witness transactions")
+ self.log.info("Testing P2SH witness transactions")
assert(len(self.utxo))
@@ -1564,7 +1563,7 @@ class SegWitTest(BitcoinTestFramework):
# To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to
# the test.
def test_upgrade_after_activation(self, node, node_id):
- print("\tTesting software upgrade after softfork activation")
+ self.log.info("Testing software upgrade after softfork activation")
assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind
@@ -1573,7 +1572,7 @@ class SegWitTest(BitcoinTestFramework):
# Restart with the new binary
stop_node(node, node_id)
- self.nodes[node_id] = start_node(node_id, self.options.tmpdir, ["-debug"])
+ self.nodes[node_id] = start_node(node_id, self.options.tmpdir)
connect_nodes(self.nodes[0], node_id)
sync_blocks(self.nodes)
@@ -1592,7 +1591,7 @@ class SegWitTest(BitcoinTestFramework):
def test_witness_sigops(self):
'''Ensure sigop counting is correct inside witnesses.'''
- print("\tTesting sigops limit")
+ self.log.info("Testing sigops limit")
assert(len(self.utxo))
@@ -1694,14 +1693,16 @@ class SegWitTest(BitcoinTestFramework):
# TODO: test p2sh sigop counting
def test_getblocktemplate_before_lockin(self):
- print("\tTesting getblocktemplate setting of segwit versionbit (before lockin)")
+ self.log.info("Testing getblocktemplate setting of segwit versionbit (before lockin)")
# Node0 is segwit aware, node2 is not.
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:
@@ -1746,7 +1747,7 @@ class SegWitTest(BitcoinTestFramework):
# Uncompressed pubkeys are no longer supported in default relay policy,
# but (for now) are still valid in blocks.
def test_uncompressed_pubkey(self):
- print("\tTesting uncompressed pubkeys")
+ self.log.info("Testing uncompressed pubkeys")
# Segwit transactions using uncompressed pubkeys are not accepted
# under default policy, but should still pass consensus.
key = CECKey()
@@ -1848,7 +1849,7 @@ class SegWitTest(BitcoinTestFramework):
self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue))
def test_non_standard_witness(self):
- print("\tTesting detection of non-standard P2WSH witness")
+ self.log.info("Testing detection of non-standard P2WSH witness")
pad = chr(1).encode('latin-1')
# Create scripts for tests
@@ -1972,7 +1973,7 @@ class SegWitTest(BitcoinTestFramework):
# Test logic begins here
self.test_node.wait_for_verack()
- print("\nStarting tests before segwit lock in:")
+ self.log.info("Starting tests before segwit lock in:")
self.test_witness_services() # Verifies NODE_WITNESS
self.test_non_witness_transaction() # non-witness tx's are accepted
@@ -1987,7 +1988,7 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# At lockin, nothing should change.
- print("\nTesting behavior post lockin, pre-activation")
+ self.log.info("Testing behavior post lockin, pre-activation")
self.advance_to_segwit_lockin()
# Retest unnecessary witnesses
@@ -2000,7 +2001,7 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# Now activate segwit
- print("\nTesting behavior after segwit activation")
+ self.log.info("Testing behavior after segwit activation")
self.advance_to_segwit_active()
sync_blocks(self.nodes)
diff --git a/qa/rpc-tests/p2p-timeouts.py b/qa/rpc-tests/p2p-timeouts.py
index 7f596b6e4b..498acb23fe 100755
--- a/qa/rpc-tests/p2p-timeouts.py
+++ b/qa/rpc-tests/p2p-timeouts.py
@@ -53,8 +53,7 @@ class TimeoutsTest(BitcoinTestFramework):
self.nodes = []
# Start up node0 to be a version 1, pre-segwit node.
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- [["-debug", "-logtimemicros=1"]])
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
# Setup the p2p connections and start up the network thread.
diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/qa/rpc-tests/p2p-versionbits-warning.py
index 8e3e361fc1..dc714e9a4a 100755
--- a/qa/rpc-tests/p2p-versionbits-warning.py
+++ b/qa/rpc-tests/p2p-versionbits-warning.py
@@ -72,7 +72,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# Open and close to create zero-length file
with open(self.alert_filename, 'w', encoding='utf8') as _:
pass
- self.extra_args = [["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]]
+ self.extra_args = [["-alertnotify=echo %s >> \"" + self.alert_filename + "\""]]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
# Send numblocks blocks via peer with nVersionToUse set.
diff --git a/qa/rpc-tests/preciousblock.py b/qa/rpc-tests/preciousblock.py
index dde164f329..30b0b5a301 100755
--- a/qa/rpc-tests/preciousblock.py
+++ b/qa/rpc-tests/preciousblock.py
@@ -39,13 +39,12 @@ class PreciousTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 3
- self.extra_args = [["-debug"]] * self.num_nodes
def setup_network(self):
self.nodes = self.setup_nodes()
def run_test(self):
- print("Ensure submitblock can in principle reorg to a competing chain")
+ self.log.info("Ensure submitblock can in principle reorg to a competing chain")
self.nodes[0].generate(1)
assert_equal(self.nodes[0].getblockcount(), 1)
(hashY, hashZ) = self.nodes[1].generate(2)
@@ -53,62 +52,62 @@ class PreciousTest(BitcoinTestFramework):
node_sync_via_rpc(self.nodes[0:3])
assert_equal(self.nodes[0].getbestblockhash(), hashZ)
- print("Mine blocks A-B-C on Node 0")
+ self.log.info("Mine blocks A-B-C on Node 0")
(hashA, hashB, hashC) = self.nodes[0].generate(3)
assert_equal(self.nodes[0].getblockcount(), 5)
- print("Mine competing blocks E-F-G on Node 1")
+ self.log.info("Mine competing blocks E-F-G on Node 1")
(hashE, hashF, hashG) = self.nodes[1].generate(3)
assert_equal(self.nodes[1].getblockcount(), 5)
assert(hashC != hashG)
- print("Connect nodes and check no reorg occurs")
+ self.log.info("Connect nodes and check no reorg occurs")
# Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
node_sync_via_rpc(self.nodes[0:2])
connect_nodes_bi(self.nodes,0,1)
assert_equal(self.nodes[0].getbestblockhash(), hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashG)
- print("Make Node0 prefer block G")
+ self.log.info("Make Node0 prefer block G")
self.nodes[0].preciousblock(hashG)
assert_equal(self.nodes[0].getbestblockhash(), hashG)
- print("Make Node0 prefer block C again")
+ self.log.info("Make Node0 prefer block C again")
self.nodes[0].preciousblock(hashC)
assert_equal(self.nodes[0].getbestblockhash(), hashC)
- print("Make Node1 prefer block C")
+ self.log.info("Make Node1 prefer block C")
self.nodes[1].preciousblock(hashC)
sync_chain(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC
assert_equal(self.nodes[1].getbestblockhash(), hashC)
- print("Make Node1 prefer block G again")
+ self.log.info("Make Node1 prefer block G again")
self.nodes[1].preciousblock(hashG)
assert_equal(self.nodes[1].getbestblockhash(), hashG)
- print("Make Node0 prefer block G again")
+ self.log.info("Make Node0 prefer block G again")
self.nodes[0].preciousblock(hashG)
assert_equal(self.nodes[0].getbestblockhash(), hashG)
- print("Make Node1 prefer block C again")
+ self.log.info("Make Node1 prefer block C again")
self.nodes[1].preciousblock(hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashC)
- print("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
+ self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
self.nodes[0].generate(1)
assert_equal(self.nodes[0].getblockcount(), 6)
sync_blocks(self.nodes[0:2])
hashH = self.nodes[0].getbestblockhash()
assert_equal(self.nodes[1].getbestblockhash(), hashH)
- print("Node1 should not be able to prefer block C anymore")
+ self.log.info("Node1 should not be able to prefer block C anymore")
self.nodes[1].preciousblock(hashC)
assert_equal(self.nodes[1].getbestblockhash(), hashH)
- print("Mine competing blocks I-J-K-L on Node 2")
+ self.log.info("Mine competing blocks I-J-K-L on Node 2")
self.nodes[2].generate(4)
assert_equal(self.nodes[2].getblockcount(), 6)
hashL = self.nodes[2].getbestblockhash()
- print("Connect nodes and check no reorg occurs")
+ self.log.info("Connect nodes and check no reorg occurs")
node_sync_via_rpc(self.nodes[1:3])
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
assert_equal(self.nodes[0].getbestblockhash(), hashH)
assert_equal(self.nodes[1].getbestblockhash(), hashH)
assert_equal(self.nodes[2].getbestblockhash(), hashL)
- print("Make Node1 prefer block L")
+ self.log.info("Make Node1 prefer block L")
self.nodes[1].preciousblock(hashL)
assert_equal(self.nodes[1].getbestblockhash(), hashL)
- print("Make Node2 prefer block H")
+ self.log.info("Make Node2 prefer block H")
self.nodes[2].preciousblock(hashH)
assert_equal(self.nodes[2].getbestblockhash(), hashH)
diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py
index 9a63d0838f..0b04ad17ab 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/qa/rpc-tests/prioritise_transaction.py
@@ -21,7 +21,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.nodes = []
self.is_network_split = False
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-printpriority=1"]))
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
def run_test(self):
@@ -50,15 +50,13 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
assert(sizes[i] > MAX_BLOCK_BASE_SIZE) # Fail => raise utxo_count
# add a fee delta to something in the cheapest bucket and make sure it gets mined
- # also check that a different entry in the cheapest bucket is NOT mined (lower
- # the priority to ensure its not mined due to priority)
- self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN))
- self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0)
+ # also check that a different entry in the cheapest bucket is NOT mined
+ self.nodes[0].prioritisetransaction(txids[0][0], int(3*base_fee*COIN))
self.nodes[0].generate(1)
mempool = self.nodes[0].getrawmempool()
- print("Assert that prioritised transaction was mined")
+ self.log.info("Assert that prioritised transaction was mined")
assert(txids[0][0] not in mempool)
assert(txids[0][1] in mempool)
@@ -72,7 +70,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Add a prioritisation before a tx is in the mempool (de-prioritising a
# high-fee transaction so that it's now low fee).
- self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN))
+ self.nodes[0].prioritisetransaction(high_fee_tx, -int(2*base_fee*COIN))
# Add everything back to mempool
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
@@ -90,13 +88,13 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# High fee transaction should not have been mined, but other high fee rate
# transactions should have been.
mempool = self.nodes[0].getrawmempool()
- print("Assert that de-prioritised transaction is still in mempool")
+ self.log.info("Assert that de-prioritised transaction is still in mempool")
assert(high_fee_tx in mempool)
for x in txids[2]:
if (x != high_fee_tx):
assert(x not in mempool)
- # Create a free, low priority transaction. Should be rejected.
+ # Create a free transaction. Should be rejected.
utxo_list = self.nodes[0].listunspent()
assert(len(utxo_list) > 0)
utxo = utxo_list[0]
@@ -104,37 +102,23 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
inputs = []
outputs = {}
inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]})
- outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
+ outputs[self.nodes[0].getnewaddress()] = utxo["amount"]
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
- txid = self.nodes[0].sendrawtransaction(tx_hex)
+ tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"]
- # A tx that spends an in-mempool tx has 0 priority, so we can use it to
- # test the effect of using prioritise transaction for mempool acceptance
- inputs = []
- inputs.append({"txid": txid, "vout": 0})
- outputs = {}
- outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
- raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs)
- tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"]
- tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"]
-
- try:
- self.nodes[0].sendrawtransaction(tx2_hex)
- except JSONRPCException as exp:
- assert_equal(exp.error['code'], -26) # insufficient fee
- assert(tx2_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
# accepted.
- self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN))
+ self.nodes[0].prioritisetransaction(tx_id, int(self.relayfee*COIN))
- print("Assert that prioritised free transaction is accepted to mempool")
- assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id)
- assert(tx2_id in self.nodes[0].getrawmempool())
+ self.log.info("Assert that prioritised free transaction is accepted to mempool")
+ assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)
+ assert(tx_id in self.nodes[0].getrawmempool())
if __name__ == '__main__':
PrioritiseTransactionTest().main()
diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py
index e4e231f312..6b2a8ed1c7 100755
--- a/qa/rpc-tests/proxy_test.py
+++ b/qa/rpc-tests/proxy_test.py
@@ -83,13 +83,13 @@ class ProxyTest(BitcoinTestFramework):
# Note: proxies are not used to connect to local nodes
# this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost
args = [
- ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],
- ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],
- ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],
+ ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'],
+ ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'],
+ ['-listen', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'],
[]
]
if self.have_ipv6:
- args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
+ args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
def node_test(self, node, proxies, auth, test_onion=True):
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index ace8ced422..cc84c8c085 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -19,7 +19,7 @@ MIN_BLOCKS_TO_KEEP = 288
# Rescans start at the earliest block up to 2 hours before a key timestamp, so
# the manual prune RPC avoids pruning blocks in the same window to be
# compatible with pruning based on key creation time.
-RESCAN_WINDOW = 2 * 60 * 60
+TIMESTAMP_WINDOW = 2 * 60 * 60
def calc_usage(blockdir):
@@ -41,19 +41,19 @@ class PruneTest(BitcoinTestFramework):
self.is_network_split = False
# Create nodes 0 and 1 to mine
- self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900))
# Create node 2 to test pruning
- self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-prune=550"], timewait=900))
+ self.nodes.append(start_node(2, self.options.tmpdir, ["-maxreceivebuffer=20000","-prune=550"], timewait=900))
self.prunedir = self.options.tmpdir+"/node2/regtest/blocks/"
# Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
- self.nodes.append(start_node(3, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
- self.nodes.append(start_node(4, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
+ self.nodes.append(start_node(3, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
+ self.nodes.append(start_node(4, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
# Create nodes 5 to test wallet in prune mode, but do not connect
- self.nodes.append(start_node(5, self.options.tmpdir, ["-debug=0", "-prune=550"]))
+ self.nodes.append(start_node(5, self.options.tmpdir, ["-prune=550"]))
# Determine default relay fee
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
@@ -79,9 +79,9 @@ class PruneTest(BitcoinTestFramework):
def test_height_min(self):
if not os.path.isfile(self.prunedir+"blk00000.dat"):
raise AssertionError("blk00000.dat is missing, pruning too early")
- print("Success")
- print("Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir))
- print("Mining 25 more blocks should cause the first block file to be pruned")
+ self.log.info("Success")
+ 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):
mine_large_block(self.nodes[0], self.utxo_cache_0)
@@ -92,22 +92,22 @@ class PruneTest(BitcoinTestFramework):
if time.time() - waitstart > 30:
raise AssertionError("blk00000.dat not pruned when it should be")
- print("Success")
+ self.log.info("Success")
usage = calc_usage(self.prunedir)
- print("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")
def create_chain_with_staleblocks(self):
# Create stale blocks in manageable sized chunks
- print("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds")
+ self.log.info("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds")
for j in range(12):
# Disconnect node 0 so it can mine a longer reorg chain without knowing about node 1's soon-to-be-stale chain
# Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects
# Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine
self.stop_node(0)
- self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)
+ self.nodes[0]=start_node(0, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)
# Mine 24 blocks in node 1
for i in range(24):
if j == 0:
@@ -124,7 +124,7 @@ class PruneTest(BitcoinTestFramework):
connect_nodes(self.nodes[2], 0)
sync_blocks(self.nodes[0:3])
- print("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
@@ -132,14 +132,14 @@ class PruneTest(BitcoinTestFramework):
# Reboot node 1 to clear its mempool (hopefully make the invalidate faster)
# Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks)
self.stop_node(1)
- self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
height = self.nodes[1].getblockcount()
- print("Current block height:", height)
+ self.log.info("Current block height: %d" % height)
invalidheight = height-287
badhash = self.nodes[1].getblockhash(invalidheight)
- print("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,24 +151,24 @@ class PruneTest(BitcoinTestFramework):
curhash = self.nodes[1].getblockhash(invalidheight - 1)
assert(self.nodes[1].getblockcount() == invalidheight - 1)
- print("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)
- self.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
- print("Generating new longer chain of 300 more blocks")
+ self.log.info("Generating new longer chain of 300 more blocks")
self.nodes[1].generate(300)
- print("Reconnect nodes")
+ self.log.info("Reconnect nodes")
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[2], 1)
sync_blocks(self.nodes[0:3], timeout=120)
- print("Verify height on node 2:",self.nodes[2].getblockcount())
- print("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))
- print("Mine 220 more blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)")
+ 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):
# This can be slow, so do this in multiple RPC calls to avoid
# RPC timeouts.
@@ -176,7 +176,7 @@ class PruneTest(BitcoinTestFramework):
sync_blocks(self.nodes[0:3], timeout=300)
usage = calc_usage(self.prunedir)
- print("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")
@@ -184,11 +184,8 @@ class PruneTest(BitcoinTestFramework):
def reorg_back(self):
# Verify that a block on the old main chain fork has been pruned away
- try:
- self.nodes[2].getblock(self.forkhash)
- raise AssertionError("Old block wasn't pruned so can't test redownload")
- except JSONRPCException as e:
- print("Will need to redownload block",self.forkheight)
+ assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash)
+ 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
@@ -212,14 +209,14 @@ 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
- print("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)
goalbesthash = self.nodes[0].generate(blocks_to_mine)[-1]
goalbestheight = first_reorg_height + 1
- print("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload")
+ self.log.info("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload")
waitstart = time.time()
while self.nodes[2].getblockcount() < goalbestheight:
time.sleep(0.1)
@@ -231,18 +228,18 @@ class PruneTest(BitcoinTestFramework):
def manual_test(self, node_number, use_timestamp):
# at this point, node has 995 blocks and has not yet run in prune mode
- node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0"], timewait=900)
+ node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, timewait=900)
assert_equal(node.getblockcount(), 995)
- assert_raises_message(JSONRPCException, "not in prune mode", node.pruneblockchain, 500)
+ assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500)
self.stop_node(node_number)
# now re-start in manual pruning mode
- node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0","-prune=1"], timewait=900)
+ node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900)
assert_equal(node.getblockcount(), 995)
def height(index):
if use_timestamp:
- return node.getblockheader(node.getblockhash(index))["time"] + RESCAN_WINDOW
+ return node.getblockheader(node.getblockhash(index))["time"] + TIMESTAMP_WINDOW
else:
return index
@@ -265,14 +262,14 @@ class PruneTest(BitcoinTestFramework):
return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index))
# should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
- assert_raises_message(JSONRPCException, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
+ assert_raises_jsonrpc(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500))
# mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
node.generate(6)
assert_equal(node.getblockchaininfo()["blocks"], 1001)
# negative heights should raise an exception
- assert_raises_message(JSONRPCException, "Negative", node.pruneblockchain, -10)
+ assert_raises_jsonrpc(-8, "Negative", node.pruneblockchain, -10)
# height=100 too low to prune first block file so this is a no-op
prune(100)
@@ -311,36 +308,30 @@ class PruneTest(BitcoinTestFramework):
# stop node, start back up with auto-prune at 550MB, make sure still runs
self.stop_node(node_number)
- self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0","-prune=550"], timewait=900)
+ self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900)
- print("Success")
+ self.log.info("Success")
def wallet_test(self):
# check that the pruning node's wallet is still in good shape
- print("Stop and start pruning node to trigger wallet rescan")
- try:
- self.stop_node(2)
- start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"])
- print("Success")
- except Exception as detail:
- raise AssertionError("Wallet test: unable to re-start the pruning node")
+ self.log.info("Stop and start pruning node to trigger wallet rescan")
+ self.stop_node(2)
+ start_node(2, self.options.tmpdir, ["-prune=550"])
+ self.log.info("Success")
# check that wallet loads loads successfully when restarting a pruned node after IBD.
# this was reported to fail in #7494.
- print ("Syncing node 5 to test wallet")
+ self.log.info("Syncing node 5 to test wallet")
connect_nodes(self.nodes[0], 5)
nds = [self.nodes[0], self.nodes[5]]
sync_blocks(nds, wait=5, timeout=300)
- try:
- self.stop_node(5) #stop and start to trigger rescan
- start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"])
- print ("Success")
- except Exception as detail:
- raise AssertionError("Wallet test: unable to re-start node5")
+ self.stop_node(5) #stop and start to trigger rescan
+ start_node(5, self.options.tmpdir, ["-prune=550"])
+ self.log.info("Success")
def run_test(self):
- print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
- print("Mining a big blockchain of 995 blocks")
+ self.log.info("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
+ self.log.info("Mining a big blockchain of 995 blocks")
self.create_big_chain()
# Chain diagram key:
# * blocks on main chain
@@ -355,12 +346,12 @@ class PruneTest(BitcoinTestFramework):
self.stop_node(3)
self.stop_node(4)
- print("Check that we haven't started pruning yet because we're below PruneAfterHeight")
+ self.log.info("Check that we haven't started pruning yet because we're below PruneAfterHeight")
self.test_height_min()
# Extend this chain past the PruneAfterHeight
# N0=N1=N2 **...*(1020)
- print("Check that we'll exceed disk space target if we have a very high stale block rate")
+ self.log.info("Check that we'll exceed disk space target if we have a very high stale block rate")
self.create_chain_with_staleblocks()
# Disconnect N0
# And mine a 24 block chain on N1 and a separate 25 block chain on N0
@@ -384,7 +375,7 @@ class PruneTest(BitcoinTestFramework):
self.mainchainheight = self.nodes[2].getblockcount() #1320
self.mainchainhash2 = self.nodes[2].getblockhash(self.mainchainheight)
- print("Check that we can survive a 288 block reorg still")
+ self.log.info("Check that we can survive a 288 block reorg still")
(self.forkheight,self.forkhash) = self.reorg_test() #(1033, )
# Now create a 288 block reorg by mining a longer chain on N1
# First disconnect N1
@@ -417,7 +408,7 @@ class PruneTest(BitcoinTestFramework):
# \
# *...**(1320)
- print("Test that we can rerequest a block we previously pruned if needed for a reorg")
+ self.log.info("Test that we can rerequest a block we previously pruned if needed for a reorg")
self.reorg_back()
# Verify that N2 still has block 1033 on current chain (@), but not on main chain (*)
# Invalidate 1033 on current chain (@) on N2 and we should be able to reorg to
@@ -437,16 +428,16 @@ class PruneTest(BitcoinTestFramework):
#
# N1 doesn't change because 1033 on main chain (*) is invalid
- print("Test manual pruning with block indices")
+ self.log.info("Test manual pruning with block indices")
self.manual_test(3, use_timestamp=False)
- print("Test manual pruning with timestamps")
+ self.log.info("Test manual pruning with timestamps")
self.manual_test(4, use_timestamp=True)
- print("Test wallet re-scan")
+ self.log.info("Test wallet re-scan")
self.wallet_test()
- print("Done")
+ self.log.info("Done")
if __name__ == '__main__':
PruneTest().main()
diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py
index 5adef31207..0374d8984a 100755
--- a/qa/rpc-tests/rawtransactions.py
+++ b/qa/rpc-tests/rawtransactions.py
@@ -61,13 +61,8 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
rawtx = self.nodes[2].signrawtransaction(rawtx)
- try:
- rawtx = self.nodes[2].sendrawtransaction(rawtx['hex'])
- except JSONRPCException as e:
- assert("Missing inputs" in e.error['message'])
- else:
- assert(False)
-
+ # This will raise an exception since there are missing inputs
+ assert_raises_jsonrpc(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex'])
#########################
# RAW TX MULTISIG TESTS #
@@ -161,13 +156,13 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex'])
# 6. invalid parameters - supply txid and string "Flase"
- assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, "Flase")
+ assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase")
# 7. invalid parameters - supply txid and empty array
- assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, [])
+ assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, [])
# 8. invalid parameters - supply txid and empty dict
- assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, {})
+ assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {})
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
outputs = { self.nodes[0].getnewaddress() : 1 }
@@ -175,13 +170,15 @@ class RawTransactionsTest(BitcoinTestFramework):
decrawtx= self.nodes[0].decoderawtransaction(rawtx)
assert_equal(decrawtx['vin'][0]['sequence'], 1000)
+ # 9. invalid parameters - sequence number out of range
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}]
outputs = { self.nodes[0].getnewaddress() : 1 }
- assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs)
+ assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)
+ # 10. invalid parameters - sequence number out of range
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}]
outputs = { self.nodes[0].getnewaddress() : 1 }
- assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs)
+ assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs)
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}]
outputs = { self.nodes[0].getnewaddress() : 1 }
diff --git a/qa/rpc-tests/reindex.py b/qa/rpc-tests/reindex.py
index 1b547a920f..0cebb0466f 100755
--- a/qa/rpc-tests/reindex.py
+++ b/qa/rpc-tests/reindex.py
@@ -31,12 +31,12 @@ class ReindexTest(BitcoinTestFramework):
self.nodes[0].generate(3)
blockcount = self.nodes[0].getblockcount()
stop_nodes(self.nodes)
- extra_args = [["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
+ extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
while self.nodes[0].getblockcount() < blockcount:
time.sleep(0.1)
assert_equal(self.nodes[0].getblockcount(), blockcount)
- print("Success")
+ self.log.info("Success")
def run_test(self):
self.reindex(False)
diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index a3c1deddf6..163c304eba 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -25,19 +25,15 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
fee = 1*COIN
while node.getbalance() < satoshi_round((amount + fee)/COIN):
node.generate(100)
- #print (node.getbalance(), amount, fee)
new_addr = node.getnewaddress()
- #print new_addr
txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN))
tx1 = node.getrawtransaction(txid, 1)
txid = int(txid, 16)
i = None
for i, txout in enumerate(tx1['vout']):
- #print i, txout['scriptPubKey']['addresses']
if txout['scriptPubKey']['addresses'] == [new_addr]:
- #print i
break
assert i is not None
@@ -72,7 +68,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
"-whitelist=127.0.0.1",
"-limitancestorcount=50",
"-limitancestorsize=101",
@@ -84,34 +80,34 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def run_test(self):
make_utxo(self.nodes[0], 1*COIN)
- print("Running test simple doublespend...")
+ self.log.info("Running test simple doublespend...")
self.test_simple_doublespend()
- print("Running test doublespend chain...")
+ self.log.info("Running test doublespend chain...")
self.test_doublespend_chain()
- print("Running test doublespend tree...")
+ self.log.info("Running test doublespend tree...")
self.test_doublespend_tree()
- print("Running test replacement feeperkb...")
+ self.log.info("Running test replacement feeperkb...")
self.test_replacement_feeperkb()
- print("Running test spends of conflicting outputs...")
+ self.log.info("Running test spends of conflicting outputs...")
self.test_spends_of_conflicting_outputs()
- print("Running test new unconfirmed inputs...")
+ self.log.info("Running test new unconfirmed inputs...")
self.test_new_unconfirmed_inputs()
- print("Running test too many replacements...")
+ self.log.info("Running test too many replacements...")
self.test_too_many_replacements()
- print("Running test opt-in...")
+ self.log.info("Running test opt-in...")
self.test_opt_in()
- print("Running test prioritised transactions...")
+ self.log.info("Running test prioritised transactions...")
self.test_prioritised_transactions()
- print("Passed\n")
+ self.log.info("Passed")
def test_simple_doublespend(self):
"""Simple doublespend"""
@@ -129,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()
@@ -176,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()
@@ -241,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()
@@ -273,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()
@@ -302,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"""
@@ -329,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()
@@ -350,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"""
@@ -373,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"""
@@ -423,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()
@@ -455,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:
- print(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))
@@ -478,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
@@ -535,15 +484,10 @@ 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, 0, int(-0.1*COIN))
+ self.nodes[0].prioritisetransaction(tx1a_txid, int(-0.1*COIN))
# Now tx1b should be able to replace tx1a
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
@@ -567,15 +511,10 @@ 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, 0, int(0.1*COIN))
+ self.nodes[0].prioritisetransaction(tx2b.hash, int(0.1*COIN))
# tx2b should now be accepted
tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index 9ca1cc187a..776211d301 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -58,7 +58,7 @@ class RESTTest (BitcoinTestFramework):
def run_test(self):
url = urllib.parse.urlparse(self.nodes[0].url)
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
self.sync_all()
diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py
index 499fe33679..8720a345ce 100755
--- a/qa/rpc-tests/rpcbind_test.py
+++ b/qa/rpc-tests/rpcbind_test.py
@@ -61,7 +61,7 @@ class RPCBindTest(BitcoinTestFramework):
break
if non_loopback_ip is None:
assert(not 'This test requires at least one non-loopback IPv4 interface')
- print("Using interface %s for testing" % non_loopback_ip)
+ self.log.info("Using interface %s for testing" % non_loopback_ip)
defaultport = rpc_port(0)
@@ -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 f475427842..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)
@@ -82,9 +84,9 @@ class SegWitTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"]))
- self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"]))
- self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-walletprematurewitness", "-rpcserialversion=0"]))
+ self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"]))
+ self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]))
connect_nodes(self.nodes[1], 0)
connect_nodes(self.nodes[2], 1)
connect_nodes(self.nodes[0], 2)
@@ -103,28 +105,18 @@ 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):
self.nodes[0].generate(161) #block 161
- print("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
+ self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
tmpl = self.nodes[0].getblocktemplate({})
assert(tmpl['sizelimit'] == 1000000)
@@ -173,22 +165,22 @@ class SegWitTest(BitcoinTestFramework):
self.nodes[0].generate(260) #block 423
sync_blocks(self.nodes)
- print("Verify default node can't accept any witness format txs before fork")
+ 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)
- print("Verify witness txs are skipped for mining before the fork")
+ 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
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425
self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426
@@ -196,19 +188,19 @@ class SegWitTest(BitcoinTestFramework):
# TODO: An old node would see these txs without witnesses and be able to mine them
- print("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork")
+ self.log.info("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork")
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428
self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429
- print("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.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
+ 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)
- print("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.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, 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
- print("Verify previous witness txs skipped for mining can now be mined")
+ self.log.info("Verify previous witness txs skipped for mining can now be mined")
assert_equal(len(self.nodes[2].getrawmempool()), 4)
block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3)
sync_blocks(self.nodes)
@@ -216,7 +208,7 @@ class SegWitTest(BitcoinTestFramework):
segwit_tx_list = self.nodes[2].getblock(block[0])["tx"]
assert_equal(len(segwit_tx_list), 5)
- print("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
+ self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False))
assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False))
for i in range(len(segwit_tx_list)):
@@ -227,19 +219,19 @@ class SegWitTest(BitcoinTestFramework):
assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"])
assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness()))
- print("Verify witness txs without witness data are invalid after the fork")
+ 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]))
- print("Verify default node can now use witness txs")
+ 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
self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433
self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434
self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435
- print("Verify sigops are counted in GBT with BIP141 rules after the fork")
+ self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']})
assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data
@@ -248,22 +240,56 @@ class SegWitTest(BitcoinTestFramework):
assert(tmpl['transactions'][0]['txid'] == txid)
assert(tmpl['transactions'][0]['sigops'] == 8)
- print("Verify non-segwit miners get a valid GBT response after the fork")
- send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.998"))
- try:
- tmpl = self.nodes[0].getblocktemplate({})
- assert(len(tmpl['transactions']) == 1) # Doesn't include witness tx
- assert(tmpl['sizelimit'] == 1000000)
- assert('weightlimit' not in tmpl)
- assert(tmpl['sigoplimit'] == 20000)
- assert(tmpl['transactions'][0]['hash'] == txid)
- assert(tmpl['transactions'][0]['sigops'] == 2)
- assert(('!segwit' in tmpl['rules']) or ('segwit' not in tmpl['rules']))
- except JSONRPCException:
- # This is an acceptable outcome
- pass
-
- print("Verify behaviour of importaddress, addwitnessaddress and listunspent")
+ 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")
# Some public keys to be used later
pubkeys = [
@@ -421,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
@@ -439,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)
@@ -523,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/sendheaders.py b/qa/rpc-tests/sendheaders.py
index 16ca4a4913..de7f5e0849 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -229,7 +229,7 @@ class SendHeadersTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
connect_nodes(self.nodes[0], 1)
# mine count blocks and return the new tip
@@ -283,7 +283,7 @@ class SendHeadersTest(BitcoinTestFramework):
# PART 1
# 1. Mine a block; expect inv announcements each time
- print("Part 1: headers don't start before sendheaders message...")
+ self.log.info("Part 1: headers don't start before sendheaders message...")
for i in range(4):
old_tip = tip
tip = self.mine_blocks(1)
@@ -314,8 +314,8 @@ class SendHeadersTest(BitcoinTestFramework):
inv_node.clear_last_announcement()
test_node.clear_last_announcement()
- print("Part 1: success!")
- print("Part 2: announce blocks with headers after sendheaders message...")
+ self.log.info("Part 1: success!")
+ self.log.info("Part 2: announce blocks with headers after sendheaders message...")
# PART 2
# 2. Send a sendheaders message and test that headers announcements
# commence and keep working.
@@ -376,9 +376,9 @@ class SendHeadersTest(BitcoinTestFramework):
height += 1
block_time += 1
- print("Part 2: success!")
+ self.log.info("Part 2: success!")
- print("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...")
+ self.log.info("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...")
# PART 3. Headers announcements can stop after large reorg, and resume after
# getheaders or inv from peer.
@@ -440,9 +440,9 @@ class SendHeadersTest(BitcoinTestFramework):
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
- print("Part 3: success!")
+ self.log.info("Part 3: success!")
- print("Part 4: Testing direct fetch behavior...")
+ self.log.info("Part 4: Testing direct fetch behavior...")
tip = self.mine_blocks(1)
height = self.nodes[0].getblockcount() + 1
last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time']
@@ -523,12 +523,12 @@ class SendHeadersTest(BitcoinTestFramework):
with mininode_lock:
assert_equal(test_node.last_getdata, None)
- print("Part 4: success!")
+ self.log.info("Part 4: success!")
# Now deliver all those blocks we announced.
[ test_node.send_message(msg_block(x)) for x in blocks ]
- print("Part 5: Testing handling of unconnecting headers")
+ self.log.info("Part 5: Testing handling of unconnecting headers")
# First we test that receipt of an unconnecting header doesn't prevent
# chain sync.
for i in range(10):
@@ -595,7 +595,7 @@ class SendHeadersTest(BitcoinTestFramework):
with mininode_lock:
self.last_getheaders = True
- print("Part 5: success!")
+ self.log.info("Part 5: success!")
# Finally, check that the inv node never received a getdata request,
# throughout the test
diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py
index bde454968f..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,60 +39,55 @@ 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):
"""
- We need to generate a lot of very small inputs so we can generate a ton of transactions
- and they will have low priority.
+ We need to generate a lot of inputs so we can generate a ton of transactions.
This function takes an input from txins, and creates and sends a transaction
which splits the value into 2 outputs which are appended to txouts.
+ Previously this was designed to be small inputs so they wouldn't have
+ 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})
@@ -98,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:
- print([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]:
@@ -150,7 +151,7 @@ class EstimateFeeTest(BitcoinTestFramework):
def setup_network(self):
"""
We'll setup the network to have 3 nodes that all mine with different parameters.
- But first we need to use one node to create a lot of small low priority outputs
+ But first we need to use one node to create a lot of outputs
which we will use to generate our transactions.
"""
self.nodes = []
@@ -158,8 +159,8 @@ class EstimateFeeTest(BitcoinTestFramework):
self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
"-whitelist=127.0.0.1"]))
- print("This test is time consuming, please be patient")
- print("Splitting inputs to small size so we can generate low priority tx's")
+ self.log.info("This test is time consuming, please be patient")
+ self.log.info("Splitting inputs so we can generate tx's")
self.txouts = []
self.txouts2 = []
# Split a coinbase into two transaction puzzle outputs
@@ -184,22 +185,20 @@ class EstimateFeeTest(BitcoinTestFramework):
while (len(self.nodes[0].getrawmempool()) > 0):
self.nodes[0].generate(1)
reps += 1
- print("Finished splitting")
+ self.log.info("Finished splitting")
# Now we can connect the other nodes, didn't want to connect them earlier
# so the estimates would not be affected by the splitting transactions
- # Node1 mines small blocks but that are bigger than the expected transaction rate,
- # and allows free transactions.
+ # Node1 mines small blocks but that are bigger than the expected transaction rate.
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
# (17k is room enough for 110 or so transactions)
self.nodes.append(start_node(1, self.options.tmpdir,
- ["-blockprioritysize=1500", "-blockmaxsize=17000",
- "-maxorphantx=1000", "-debug=estimatefee"]))
+ ["-blockmaxsize=17000", "-maxorphantx=1000"]))
connect_nodes(self.nodes[1], 0)
# Node2 is a stingy miner, that
# produces too small blocks (room for only 55 or so transactions)
- node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000"]
+ node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"]
self.nodes.append(start_node(2, self.options.tmpdir, node2args))
connect_nodes(self.nodes[0], 2)
@@ -235,18 +234,21 @@ 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
- print("Will output estimates for 1/2/3/6/15/25 blocks")
+ self.log.info("Will output estimates for 1/2/3/6/15/25 blocks")
for i in range(2):
- print("Creating transactions and mining them with a block size that can't keep up")
+ self.log.info("Creating transactions and mining them with a block size that can't keep up")
# Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine
self.transact_and_mine(10, self.nodes[2])
check_estimates(self.nodes[1], self.fees_per_kb, 14)
- print("Creating transactions and mining them at a block size that is just big enough")
+ self.log.info("Creating transactions and mining them at a block size that is just big enough")
# Generate transactions while mining 10 more blocks, this time with node1
# which mines blocks with capacity just above the rate that transactions are being created
self.transact_and_mine(10, self.nodes[1])
@@ -257,7 +259,7 @@ class EstimateFeeTest(BitcoinTestFramework):
self.nodes[1].generate(1)
sync_blocks(self.nodes[0:3], wait=.1)
- print("Final estimates after emptying mempools")
+ self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb, 2)
if __name__ == '__main__':
diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py
index 5280d18cdc..4cfd682bb5 100644
--- a/qa/rpc-tests/test_framework/blockstore.py
+++ b/qa/rpc-tests/test_framework/blockstore.py
@@ -8,6 +8,8 @@ from .mininode import *
from io import BytesIO
import dbm.dumb as dbmd
+logger = logging.getLogger("TestFramework.blockstore")
+
class BlockStore(object):
"""BlockStore helper class.
@@ -86,7 +88,7 @@ class BlockStore(object):
try:
self.blockDB[repr(block.sha256)] = bytes(block.serialize())
except TypeError as e:
- print("Unexpected error: ", sys.exc_info()[0], e.args)
+ logger.exception("Unexpected error")
self.currentBlock = block.sha256
self.headers_map[block.sha256] = CBlockHeader(block)
@@ -156,7 +158,7 @@ class TxStore(object):
try:
self.txDB[repr(tx.sha256)] = bytes(tx.serialize())
except TypeError as e:
- print("Unexpected error: ", sys.exc_info()[0], e.args)
+ logger.exception("Unexpected error")
def get_transactions(self, inv):
responses = []
diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py
index b617895cac..70d1d700ef 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/qa/rpc-tests/test_framework/comptool.py
@@ -21,6 +21,10 @@ from .mininode import *
from .blockstore import BlockStore, TxStore
from .util import p2p_port
+import logging
+
+logger=logging.getLogger("TestFramework.comptool")
+
global mininode_lock
class RejectResult(object):
@@ -209,7 +213,6 @@ class TestManager(object):
# --> error if not requested
if not wait_until(blocks_requested, attempts=20*num_blocks):
- # print [ c.cb.block_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested block")
# Send getheaders message
@@ -231,7 +234,6 @@ class TestManager(object):
# --> error if not requested
if not wait_until(transaction_requested, attempts=20*num_events):
- # print [ c.cb.tx_request_map for c in self.connections ]
raise AssertionError("Not all nodes requested transaction")
# Get the mempool
@@ -258,13 +260,12 @@ class TestManager(object):
if c.cb.bestblockhash == blockhash:
return False
if blockhash not in c.cb.block_reject_map:
- print('Block not in reject map: %064x' % (blockhash))
+ logger.error('Block not in reject map: %064x' % (blockhash))
return False
if not outcome.match(c.cb.block_reject_map[blockhash]):
- print('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash))
+ logger.error('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash))
return False
elif ((c.cb.bestblockhash == blockhash) != outcome):
- # print c.cb.bestblockhash, blockhash, outcome
return False
return True
@@ -280,19 +281,17 @@ class TestManager(object):
if outcome is None:
# Make sure the mempools agree with each other
if c.cb.lastInv != self.connections[0].cb.lastInv:
- # print c.rpc.getrawmempool()
return False
elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code
if txhash in c.cb.lastInv:
return False
if txhash not in c.cb.tx_reject_map:
- print('Tx not in reject map: %064x' % (txhash))
+ logger.error('Tx not in reject map: %064x' % (txhash))
return False
if not outcome.match(c.cb.tx_reject_map[txhash]):
- print('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash))
+ logger.error('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash))
return False
elif ((txhash in c.cb.lastInv) != outcome):
- # print c.rpc.getrawmempool(), c.cb.lastInv
return False
return True
@@ -402,7 +401,7 @@ class TestManager(object):
if (not self.check_mempool(tx.sha256, tx_outcome)):
raise AssertionError("Mempool test failed at test %d" % test_number)
- print("Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ])
+ logger.info("Test %d: PASS" % test_number)
test_number += 1
[ c.disconnect_node() for c in self.connections ]
diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py
index b2292f6477..aace17a043 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -51,6 +51,8 @@ NODE_GETUTXO = (1 << 1)
NODE_BLOOM = (1 << 2)
NODE_WITNESS = (1 << 3)
+logger = logging.getLogger("TestFramework.mininode")
+
# Keep our own socket map for asyncore, so that we can track disconnects
# ourselves (to workaround an issue with closing an asyncore socket when
# using select)
@@ -1502,8 +1504,7 @@ class NodeConnCB(object):
try:
getattr(self, 'on_' + message.command.decode('ascii'))(conn, message)
except:
- print("ERROR delivering %s (%s)" % (repr(message),
- sys.exc_info()[0]))
+ logger.exception("ERROR delivering %s" % repr(message))
def on_version(self, conn, message):
if message.nVersion >= 209:
@@ -1615,7 +1616,6 @@ class NodeConn(asyncore.dispatcher):
def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
- self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport))
self.dstaddr = dstaddr
self.dstport = dstport
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -1640,8 +1640,7 @@ class NodeConn(asyncore.dispatcher):
vt.addrFrom.port = 0
self.send_message(vt, True)
- print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \
- + str(dstport))
+ logger.info('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport))
try:
self.connect((dstaddr, dstport))
@@ -1649,18 +1648,14 @@ class NodeConn(asyncore.dispatcher):
self.handle_close()
self.rpc = rpc
- def show_debug_msg(self, msg):
- self.log.debug(msg)
-
def handle_connect(self):
if self.state != "connected":
- self.show_debug_msg("MiniNode: Connected & Listening: \n")
+ logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport))
self.state = "connected"
self.cb.on_open(self)
def handle_close(self):
- self.show_debug_msg("MiniNode: Closing Connection to %s:%d... "
- % (self.dstaddr, self.dstport))
+ logger.debug("Closing connection to: %s:%d" % (self.dstaddr, self.dstport))
self.state = "closed"
self.recvbuf = b""
self.sendbuf = b""
@@ -1742,17 +1737,14 @@ class NodeConn(asyncore.dispatcher):
t.deserialize(f)
self.got_message(t)
else:
- self.show_debug_msg("Unknown command: '" + command + "' " +
- repr(msg))
+ logger.warning("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg)))
except Exception as e:
- print('got_data:', repr(e))
- # import traceback
- # traceback.print_tb(sys.exc_info()[2])
+ logger.exception('got_data:', repr(e))
def send_message(self, message, pushbuf=False):
if self.state != "connected" and not pushbuf:
raise IOError('Not connected, no pushbuf')
- self.show_debug_msg("Send %s" % repr(message))
+ logger.debug("Send message to %s:%d: %s" % (self.dstaddr, self.dstport, repr(message)))
command = message.command
data = message.serialize()
tmsg = self.MAGIC_BYTES[self.network]
@@ -1774,7 +1766,7 @@ class NodeConn(asyncore.dispatcher):
self.messagemap[b'ping'] = msg_ping_prebip31
if self.last_sent + 30 * 60 < time.time():
self.send_message(self.messagemap[b'ping']())
- self.show_debug_msg("Recv %s" % repr(message))
+ logger.debug("Received message from %s:%d: %s" % (self.dstaddr, self.dstport, repr(message)))
self.cb.deliver(self, message)
def disconnect_node(self):
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index c5e9c6a658..d7072fa78d 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -42,7 +42,7 @@ class BitcoinTestFramework(object):
pass
def setup_chain(self):
- print("Initializing test directory "+self.options.tmpdir)
+ self.log.info("Initializing test directory "+self.options.tmpdir)
if self.setup_clean_chain:
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
else:
@@ -112,6 +112,8 @@ class BitcoinTestFramework(object):
help="Directory for caching pregenerated datadirs")
parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
help="Root directory for datadirs")
+ parser.add_option("-l", "--loglevel", dest="loglevel", default="INFO",
+ help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.")
parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
help="Print out all RPC calls as they are made")
parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int',
@@ -124,9 +126,6 @@ class BitcoinTestFramework(object):
# backup dir variable for removal at cleanup
self.options.root, self.options.tmpdir = self.options.tmpdir, self.options.tmpdir + '/' + str(self.options.port_seed)
- if self.options.trace_rpc:
- logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
-
if self.options.coveragedir:
enable_coverage(self.options.coveragedir)
@@ -136,41 +135,41 @@ class BitcoinTestFramework(object):
check_json_precision()
+ # Set up temp directory and start logging
+ os.makedirs(self.options.tmpdir, exist_ok=False)
+ self._start_logging()
+
success = False
+
try:
- os.makedirs(self.options.tmpdir, exist_ok=False)
self.setup_chain()
self.setup_network()
self.run_test()
success = True
except JSONRPCException as e:
- print("JSONRPC error: "+e.error['message'])
- traceback.print_tb(sys.exc_info()[2])
+ self.log.exception("JSONRPC error")
except AssertionError as e:
- print("Assertion failed: " + str(e))
- traceback.print_tb(sys.exc_info()[2])
+ self.log.exception("Assertion failed")
except KeyError as e:
- print("key not found: "+ str(e))
- traceback.print_tb(sys.exc_info()[2])
+ self.log.exception("Key error")
except Exception as e:
- print("Unexpected exception caught during testing: " + repr(e))
- traceback.print_tb(sys.exc_info()[2])
+ self.log.exception("Unexpected exception caught during testing")
except KeyboardInterrupt as e:
- print("Exiting after " + repr(e))
+ self.log.warning("Exiting after keyboard interrupt")
if not self.options.noshutdown:
- print("Stopping nodes")
+ self.log.info("Stopping nodes")
stop_nodes(self.nodes)
else:
- print("Note: bitcoinds were not stopped and may still be running")
+ self.log.info("Note: bitcoinds were not stopped and may still be running")
if not self.options.nocleanup and not self.options.noshutdown and success:
- print("Cleaning up")
+ self.log.info("Cleaning up")
shutil.rmtree(self.options.tmpdir)
if not os.listdir(self.options.root):
os.rmdir(self.options.root)
else:
- print("Not cleaning up dir %s" % self.options.tmpdir)
+ self.log.warning("Not cleaning up dir %s" % self.options.tmpdir)
if os.getenv("PYTHON_DEBUG", ""):
# Dump the end of the debug logs, to aid in debugging rare
# travis failures.
@@ -182,12 +181,39 @@ class BitcoinTestFramework(object):
from collections import deque
print("".join(deque(open(f), MAX_LINES_TO_PRINT)))
if success:
- print("Tests successful")
+ self.log.info("Tests successful")
sys.exit(0)
else:
- print("Failed")
+ self.log.error("Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir)
+ logging.shutdown()
sys.exit(1)
+ def _start_logging(self):
+ # Add logger and logging handlers
+ self.log = logging.getLogger('TestFramework')
+ self.log.setLevel(logging.DEBUG)
+ # Create file handler to log all messages
+ fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log')
+ fh.setLevel(logging.DEBUG)
+ # Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel.
+ ch = logging.StreamHandler(sys.stdout)
+ # User can provide log level as a number or string (eg DEBUG). loglevel was caught as a string, so try to convert it to an int
+ ll = int(self.options.loglevel) if self.options.loglevel.isdigit() else self.options.loglevel.upper()
+ ch.setLevel(ll)
+ # Format logs the same as bitcoind's debug.log with microprecision (so log files can be concatenated and sorted)
+ formatter = logging.Formatter(fmt = '%(asctime)s.%(msecs)03d000 %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
+ fh.setFormatter(formatter)
+ ch.setFormatter(formatter)
+ # add the handlers to the logger
+ self.log.addHandler(fh)
+ self.log.addHandler(ch)
+
+ if self.options.trace_rpc:
+ rpc_logger = logging.getLogger("BitcoinRPC")
+ rpc_logger.setLevel(logging.DEBUG)
+ rpc_handler = logging.StreamHandler(sys.stdout)
+ rpc_handler.setLevel(logging.DEBUG)
+ rpc_logger.addHandler(rpc_handler)
# Test framework for doing p2p comparison testing, which sets up some bitcoind
# binaries:
@@ -213,6 +239,6 @@ class ComparisonTestFramework(BitcoinTestFramework):
def setup_network(self):
self.nodes = start_nodes(
self.num_nodes, self.options.tmpdir,
- extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes,
+ extra_args=[['-whitelist=127.0.0.1']] * self.num_nodes,
binary=[self.options.testbinary] +
[self.options.refbinary]*(self.num_nodes-1))
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index e838a40582..23ac324510 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -15,15 +15,19 @@ import http.client
import random
import shutil
import subprocess
+import tempfile
import time
import re
import errno
+import logging
from . import coverage
from .authproxy import AuthServiceProxy, JSONRPCException
COVERAGE_DIR = None
+logger = logging.getLogger("TestFramework.utils")
+
# The maximum number of nodes a single test can spawn
MAX_NODES = 8
# Don't assign rpc or p2p ports lower than this
@@ -236,6 +240,7 @@ def initialize_chain(test_dir, num_nodes, cachedir):
break
if create_cache:
+ logger.debug("Creating data directories from cached datadir")
#find and delete old cache directories if any exist
for i in range(MAX_NODES):
@@ -249,11 +254,9 @@ def initialize_chain(test_dir, num_nodes, cachedir):
if i > 0:
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
bitcoind_processes[i] = subprocess.Popen(args)
- if os.getenv("PYTHON_DEBUG", ""):
- print("initialize_chain: bitcoind started, waiting for RPC to come up")
+ logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i)
- if os.getenv("PYTHON_DEBUG", ""):
- print("initialize_chain: RPC successfully started")
+ logger.debug("initialize_chain: RPC successfully started")
rpcs = []
for i in range(MAX_NODES):
@@ -305,42 +308,20 @@ def initialize_chain_clean(test_dir, num_nodes):
datadir=initialize_datadir(test_dir, i)
-def _rpchost_to_args(rpchost):
- '''Convert optional IP:port spec to rpcconnect/rpcport args'''
- if rpchost is None:
- return []
-
- match = re.match('(\[[0-9a-fA-f:]+\]|[^:]+)(?::([0-9]+))?$', rpchost)
- if not match:
- raise ValueError('Invalid RPC host spec ' + rpchost)
-
- rpcconnect = match.group(1)
- rpcport = match.group(2)
-
- if rpcconnect.startswith('['): # remove IPv6 [...] wrapping
- rpcconnect = rpcconnect[1:-1]
-
- rv = ['-rpcconnect=' + rpcconnect]
- if rpcport:
- rv += ['-rpcport=' + rpcport]
- return rv
-
-def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
+def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
"""
Start a bitcoind and return RPC connection to it
"""
datadir = os.path.join(dirname, "node"+str(i))
if binary is None:
binary = os.getenv("BITCOIND", "bitcoind")
- args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ]
+ args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-mocktime="+str(get_mocktime()) ]
if extra_args is not None: args.extend(extra_args)
- bitcoind_processes[i] = subprocess.Popen(args)
- if os.getenv("PYTHON_DEBUG", ""):
- print("start_node: bitcoind started, waiting for RPC to come up")
+ bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr)
+ logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
url = rpc_url(i, rpchost)
wait_for_bitcoind_start(bitcoind_processes[i], url, i)
- if os.getenv("PYTHON_DEBUG", ""):
- print("start_node: RPC successfully started")
+ logger.debug("initialize_chain: RPC successfully started")
proxy = get_rpc_proxy(url, i, timeout=timewait)
if COVERAGE_DIR:
@@ -348,6 +329,25 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
return proxy
+def assert_start_raises_init_error(i, dirname, extra_args=None, expected_msg=None):
+ with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr:
+ try:
+ node = start_node(i, dirname, extra_args, stderr=log_stderr)
+ stop_node(node, i)
+ except Exception as e:
+ assert 'bitcoind exited' in str(e) #node must have shutdown
+ if expected_msg is not None:
+ log_stderr.seek(0)
+ stderr = log_stderr.read().decode('utf-8')
+ if expected_msg not in stderr:
+ raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr)
+ else:
+ if expected_msg is None:
+ assert_msg = "bitcoind should have exited with an error"
+ else:
+ assert_msg = "bitcoind should have exited with expected error " + expected_msg
+ raise AssertionError(assert_msg)
+
def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
"""
Start multiple bitcoinds, return RPC connections to them
@@ -367,10 +367,11 @@ def log_filename(dirname, n_node, logname):
return os.path.join(dirname, "node"+str(n_node), "regtest", logname)
def stop_node(node, i):
+ logger.debug("Stopping node %d" % i)
try:
node.stop()
except http.client.CannotSendRequest as e:
- print("WARN: Unable to stop node: " + repr(e))
+ logger.exception("Unable to stop node")
return_code = bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
assert_equal(return_code, 0)
del bitcoind_processes[i]
@@ -442,47 +443,6 @@ def make_change(from_node, amount_in, amount_out, fee):
outputs[from_node.getnewaddress()] = change
return outputs
-def send_zeropri_transaction(from_node, to_node, amount, fee):
- """
- Create&broadcast a zero-priority transaction.
- Returns (txid, hex-encoded-txdata)
- Ensures transaction is zero-priority by first creating a send-to-self,
- then using its output
- """
-
- # Create a send-to-self with confirmed inputs:
- self_address = from_node.getnewaddress()
- (total_in, inputs) = gather_inputs(from_node, amount+fee*2)
- outputs = make_change(from_node, total_in, amount+fee, fee)
- outputs[self_address] = float(amount+fee)
-
- self_rawtx = from_node.createrawtransaction(inputs, outputs)
- self_signresult = from_node.signrawtransaction(self_rawtx)
- self_txid = from_node.sendrawtransaction(self_signresult["hex"], True)
-
- vout = find_output(from_node, self_txid, amount+fee)
- # Now immediately spend the output to create a 1-input, 1-output
- # zero-priority transaction:
- inputs = [ { "txid" : self_txid, "vout" : vout } ]
- outputs = { to_node.getnewaddress() : float(amount) }
-
- rawtx = from_node.createrawtransaction(inputs, outputs)
- signresult = from_node.signrawtransaction(rawtx)
- txid = from_node.sendrawtransaction(signresult["hex"], True)
-
- return (txid, signresult["hex"])
-
-def random_zeropri_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
- """
- Create a random zero-priority transaction.
- Returns (txid, hex-encoded-transaction-data, fee)
- """
- from_node = random.choice(nodes)
- to_node = random.choice(nodes)
- fee = min_fee + fee_increment*random.randint(0,fee_variants)
- (txid, txhex) = send_zeropri_transaction(from_node, to_node, amount, fee)
- return (txid, txhex, fee)
-
def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
"""
Create a random transaction.
diff --git a/qa/rpc-tests/wallet-hd.py b/qa/rpc-tests/wallet-hd.py
index bf07590098..c40662dc3d 100755
--- a/qa/rpc-tests/wallet-hd.py
+++ b/qa/rpc-tests/wallet-hd.py
@@ -10,6 +10,7 @@ from test_framework.util import (
start_node,
assert_equal,
connect_nodes_bi,
+ assert_start_raises_init_error
)
import os
import shutil
@@ -31,6 +32,12 @@ class WalletHDTest(BitcoinTestFramework):
def run_test (self):
tmpdir = self.options.tmpdir
+ # Make sure can't switch off usehd after wallet creation
+ self.stop_node(1)
+ assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet')
+ self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1])
+ connect_nodes_bi(self.nodes, 0, 1)
+
# Make sure we use hd, keep masterkeyid
masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid']
assert_equal(len(masterkeyid), 40)
@@ -61,7 +68,7 @@ class WalletHDTest(BitcoinTestFramework):
self.sync_all()
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
- print("Restore backup ...")
+ self.log.info("Restore backup ...")
self.stop_node(1)
os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index ddeac657e5..80f74fa108 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -35,7 +35,7 @@ class WalletTest (BitcoinTestFramework):
assert_equal(len(self.nodes[1].listunspent()), 0)
assert_equal(len(self.nodes[2].listunspent()), 0)
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
@@ -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
@@ -332,7 +324,7 @@ class WalletTest (BitcoinTestFramework):
]
chainlimit = 6
for m in maintenance:
- print("check " + m)
+ self.log.info("check " + m)
stop_nodes(self.nodes)
# set lower ancestor limit for later
self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3)
@@ -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/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
index ea249096cf..af1718572f 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/qa/rpc-tests/walletbackup.py
@@ -34,8 +34,6 @@ and confirm again balances are correct.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from random import randint
-import logging
-logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout)
class WalletBackupTest(BitcoinTestFramework):
@@ -100,7 +98,7 @@ class WalletBackupTest(BitcoinTestFramework):
os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat")
def run_test(self):
- logging.info("Generating initial blockchain")
+ self.log.info("Generating initial blockchain")
self.nodes[0].generate(1)
sync_blocks(self.nodes)
self.nodes[1].generate(1)
@@ -115,12 +113,12 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), 50)
assert_equal(self.nodes[3].getbalance(), 0)
- logging.info("Creating transactions")
+ self.log.info("Creating transactions")
# Five rounds of sending each other transactions.
for i in range(5):
self.do_one_round()
- logging.info("Backing up")
+ self.log.info("Backing up")
tmpdir = self.options.tmpdir
self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak")
self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump")
@@ -129,7 +127,7 @@ class WalletBackupTest(BitcoinTestFramework):
self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak")
self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump")
- logging.info("More transactions")
+ self.log.info("More transactions")
for i in range(5):
self.do_one_round()
@@ -150,7 +148,7 @@ class WalletBackupTest(BitcoinTestFramework):
##
# Test restoring spender wallets from backups
##
- logging.info("Restoring using wallet.dat")
+ self.log.info("Restoring using wallet.dat")
self.stop_three()
self.erase_three()
@@ -163,7 +161,7 @@ class WalletBackupTest(BitcoinTestFramework):
shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat")
shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat")
- logging.info("Re-starting nodes")
+ self.log.info("Re-starting nodes")
self.start_three()
sync_blocks(self.nodes)
@@ -171,7 +169,7 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), balance1)
assert_equal(self.nodes[2].getbalance(), balance2)
- logging.info("Restoring using dumped wallet")
+ self.log.info("Restoring using dumped wallet")
self.stop_three()
self.erase_three()
diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py
index 9597d05f3a..ce446e44a3 100755
--- a/qa/rpc-tests/zapwallettxes.py
+++ b/qa/rpc-tests/zapwallettxes.py
@@ -32,7 +32,7 @@ class ZapWalletTXesTest (BitcoinTestFramework):
self.sync_all()
def run_test (self):
- print("Mining blocks...")
+ self.log.info("Mining blocks...")
self.nodes[0].generate(1)
self.sync_all()
self.nodes[1].generate(101)
diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py
index 1e2f06bd54..e6f18b0b93 100755
--- a/qa/rpc-tests/zmq_test.py
+++ b/qa/rpc-tests/zmq_test.py
@@ -36,7 +36,7 @@ class ZMQTest (BitcoinTestFramework):
genhashes = self.nodes[0].generate(1)
self.sync_all()
- print("listen...")
+ self.log.info("listen...")
msg = self.zmqSubSocket.recv_multipart()
topic = msg[0]
assert_equal(topic, b"hashtx")
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.qttest.include b/src/Makefile.qttest.include
index 039f8ac547..948e13a9e1 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -11,7 +11,9 @@ TEST_QT_MOC_CPP = \
qt/test/moc_uritests.cpp
if ENABLE_WALLET
-TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp
+TEST_QT_MOC_CPP += \
+ qt/test/moc_paymentservertests.cpp \
+ qt/test/moc_wallettests.cpp
endif
TEST_QT_H = \
@@ -19,7 +21,16 @@ TEST_QT_H = \
qt/test/rpcnestedtests.h \
qt/test/uritests.h \
qt/test/paymentrequestdata.h \
- qt/test/paymentservertests.h
+ qt/test/paymentservertests.h \
+ qt/test/wallettests.h
+
+TEST_BITCOIN_CPP = \
+ test/test_bitcoin.cpp \
+ test/testutil.cpp
+
+TEST_BITCOIN_H = \
+ test/test_bitcoin.h \
+ test/testutil.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
@@ -29,10 +40,13 @@ qt_test_test_bitcoin_qt_SOURCES = \
qt/test/rpcnestedtests.cpp \
qt/test/test_main.cpp \
qt/test/uritests.cpp \
- $(TEST_QT_H)
+ $(TEST_QT_H) \
+ $(TEST_BITCOIN_CPP) \
+ $(TEST_BITCOIN_H)
if ENABLE_WALLET
qt_test_test_bitcoin_qt_SOURCES += \
- qt/test/paymentservertests.cpp
+ qt/test/paymentservertests.cpp \
+ qt/test/wallettests.cpp
endif
nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 55a587cf87..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 \
@@ -126,6 +127,7 @@ BITCOIN_TESTS =\
test/streams_tests.cpp \
test/test_bitcoin.cpp \
test/test_bitcoin.h \
+ test/test_bitcoin_main.cpp \
test/test_random.h \
test/testutil.cpp \
test/testutil.h \
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 3c9df4f713..b0df3d2b04 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -92,6 +92,8 @@ bool benchmark::State::KeepRunning()
--count;
+ assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
+
// Output results
double average = (now-beginTime)/count;
int64_t averageCycles = (nowCycles-beginCycles)/count;
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/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index 5790d51a82..073bbde016 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -12,14 +12,13 @@
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
{
int64_t nTime = 0;
- double dPriority = 10.0;
unsigned int nHeight = 1;
bool spendsCoinbase = false;
unsigned int sigOpCost = 4;
LockPoints lp;
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
- MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight,
- tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
+ MakeTransactionRef(tx), nFee, nTime, nHeight,
+ spendsCoinbase, sigOpCost, lp));
}
// Right now this is only testing eviction performance in an extremely small
@@ -97,7 +96,7 @@ static void MempoolEviction(benchmark::State& state)
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[1].nValue = 10 * COIN;
- CTxMemPool pool(CFeeRate(1000));
+ CTxMemPool pool;
while (state.KeepRunning()) {
AddTx(tx1, 10000LL, pool);
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/bloom.cpp b/src/bloom.cpp
index 8d47cb76e8..ac3e565721 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -254,8 +254,8 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
if (nGeneration == 4) {
nGeneration = 1;
}
- uint64_t nGenerationMask1 = -(uint64_t)(nGeneration & 1);
- uint64_t nGenerationMask2 = -(uint64_t)(nGeneration >> 1);
+ uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1);
+ uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1);
/* Wipe old entries that used this generation number. */
for (uint32_t p = 0; p < data.size(); p += 2) {
uint64_t p1 = data[p], p2 = data[p + 1];
diff --git a/src/chain.h b/src/chain.h
index 4fd5aed93b..de120d2d75 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -14,6 +14,20 @@
#include <vector>
+/**
+ * Maximum amount of time that a block timestamp is allowed to exceed the
+ * current network-adjusted time before the block will be accepted.
+ */
+static const int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
+
+/**
+ * Timestamp window used as a grace period by code that compares external
+ * timestamps (such as timestamps passed to RPCs, or wallet key creation times)
+ * to block timestamps. This should be set at least as high as
+ * MAX_FUTURE_BLOCK_TIME.
+ */
+static const int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
+
class CBlockFileInfo
{
public:
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/coins.cpp b/src/coins.cpp
index 4d0e4bc0ad..b2e33abf33 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -295,25 +295,6 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
return true;
}
-double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
-{
- inChainInputValue = 0;
- if (tx.IsCoinBase())
- return 0.0;
- double dResult = 0.0;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- const CCoins* coins = AccessCoins(txin.prevout.hash);
- assert(coins);
- if (!coins->IsAvailable(txin.prevout.n)) continue;
- if (coins->nHeight <= nHeight) {
- dResult += (double)(coins->vout[txin.prevout.n].nValue) * (nHeight-coins->nHeight);
- inChainInputValue += coins->vout[txin.prevout.n].nValue;
- }
- }
- return tx.ComputePriority(dResult);
-}
-
CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
assert(!cache.hasModifier);
cache.hasModifier = true;
diff --git a/src/coins.h b/src/coins.h
index 902cb57f69..d921f5c2a5 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -460,13 +460,6 @@ public:
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;
- /**
- * Return priority of tx at height nHeight. Also calculate the sum of the values of the inputs
- * that are already in the chain. These are the inputs that will age and increase priority as
- * new blocks are added to the chain.
- */
- double GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const;
-
const CTxOut &GetOutputFor(const CTxIn& input) const;
friend class CCoinsModifier;
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/init.cpp b/src/init.cpp
index a311ee7d8c..93131b4f94 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -444,8 +444,6 @@ std::string HelpMessage(HelpMessageMode mode)
{
strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)");
- strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY));
- strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY));
strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
}
@@ -456,7 +454,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
if (showDebug)
{
- strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
+ strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
@@ -476,7 +474,6 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Block creation options:"));
strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT));
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
- strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));
if (showDebug)
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
@@ -998,17 +995,18 @@ bool AppInitParameterInteraction()
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
- // Fee-per-kilobyte amount considered the same as "free"
+ // Fee-per-kilobyte amount required for mempool acceptance and relay
// If you are mining, be careful setting this:
// if you set it to zero then
// a transaction spammer can cheaply fill blocks using
- // 1-satoshi-fee transactions. It should be set above the real
+ // 0-fee transactions. It should be set above the real
// cost to you of processing a transaction.
if (IsArgSet("-minrelaytxfee"))
{
CAmount n = 0;
- if (!ParseMoney(GetArg("-minrelaytxfee", ""), n) || 0 == n)
+ if (!ParseMoney(GetArg("-minrelaytxfee", ""), n)) {
return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
+ }
// High fee check is done afterward in CWallet::ParameterInteraction()
::minRelayTxFee = CFeeRate(n);
} else if (incrementalRelayFee > ::minRelayTxFee) {
@@ -1639,7 +1637,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifdef ENABLE_WALLET
if (pwalletMain)
- pwalletMain->postInitProcess(threadGroup);
+ pwalletMain->postInitProcess(scheduler);
#endif
return !fRequestShutdown;
diff --git a/src/miner.cpp b/src/miner.cpp
index 167e74284c..ff28a5680e 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -39,8 +39,8 @@
//
// Unconfirmed transactions in the memory pool often depend on other
// transactions in the memory pool. When we select transactions from the
-// pool, we select by highest priority or fee rate, so we might consider
-// transactions that depend on transactions that aren't yet in the block.
+// pool, we select by highest fee rate of a transaction combined with all
+// its ancestors.
uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0;
@@ -135,12 +135,9 @@ void BlockAssembler::resetBlock()
// These counters do not include coinbase tx
nBlockTx = 0;
nFees = 0;
-
- lastFewTxs = 0;
- blockFinished = false;
}
-std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx)
{
resetBlock();
@@ -178,9 +175,8 @@ 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;
- addPriorityTxs();
addPackageTxs();
nLastBlockTx = nBlockTx;
@@ -217,17 +213,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
return std::move(pblocktemplate);
}
-bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter)
-{
- BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter))
- {
- if (!inBlock.count(parent)) {
- return true;
- }
- }
- return false;
-}
-
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
{
for (CTxMemPool::setEntries::iterator iit = testSet.begin(); iit != testSet.end(); ) {
@@ -275,58 +260,6 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
return true;
}
-bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter)
-{
- if (nBlockWeight + iter->GetTxWeight() >= nBlockMaxWeight) {
- // If the block is so close to full that no more txs will fit
- // or if we've tried more than 50 times to fill remaining space
- // then flag that the block is finished
- if (nBlockWeight > nBlockMaxWeight - 400 || lastFewTxs > 50) {
- blockFinished = true;
- return false;
- }
- // Once we're within 4000 weight of a full block, only look at 50 more txs
- // to try to fill the remaining space.
- if (nBlockWeight > nBlockMaxWeight - 4000) {
- lastFewTxs++;
- }
- return false;
- }
-
- if (fNeedSizeAccounting) {
- if (nBlockSize + ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION) >= nBlockMaxSize) {
- if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) {
- blockFinished = true;
- return false;
- }
- if (nBlockSize > nBlockMaxSize - 1000) {
- lastFewTxs++;
- }
- return false;
- }
- }
-
- if (nBlockSigOpsCost + iter->GetSigOpCost() >= MAX_BLOCK_SIGOPS_COST) {
- // If the block has room for no more sig ops then
- // flag that the block is finished
- if (nBlockSigOpsCost > MAX_BLOCK_SIGOPS_COST - 8) {
- blockFinished = true;
- return false;
- }
- // Otherwise attempt to find another tx with fewer sigops
- // to put in the block.
- return false;
- }
-
- // Must check that lock times are still valid
- // This can be removed once MTP is always enforced
- // as long as reorgs keep the mempool consistent.
- if (!IsFinalTx(iter->GetTx(), nHeight, nLockTimeCutoff))
- return false;
-
- return true;
-}
-
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
{
pblock->vtx.emplace_back(iter->GetSharedTx());
@@ -343,11 +276,7 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
if (fPrintPriority) {
- double dPriority = iter->GetPriority(nHeight);
- CAmount dummy;
- mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy);
- LogPrintf("priority %.1f fee %s txid %s\n",
- dPriority,
+ LogPrintf("fee %s txid %s\n",
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
iter->GetTx().GetHash().ToString());
}
@@ -525,88 +454,6 @@ void BlockAssembler::addPackageTxs()
}
}
-void BlockAssembler::addPriorityTxs()
-{
- // How much of the block should be dedicated to high-priority transactions,
- // included regardless of the fees they pay
- unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
- nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
-
- if (nBlockPrioritySize == 0) {
- return;
- }
-
- bool fSizeAccounting = fNeedSizeAccounting;
- fNeedSizeAccounting = true;
-
- // This vector will be sorted into a priority queue:
- std::vector<TxCoinAgePriority> vecPriority;
- TxCoinAgePriorityCompare pricomparer;
- std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash> waitPriMap;
- typedef std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
- double actualPriority = -1;
-
- vecPriority.reserve(mempool.mapTx.size());
- for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
- mi != mempool.mapTx.end(); ++mi)
- {
- double dPriority = mi->GetPriority(nHeight);
- CAmount dummy;
- mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy);
- vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
- }
- std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
-
- CTxMemPool::txiter iter;
- while (!vecPriority.empty() && !blockFinished) { // add a tx from priority queue to fill the blockprioritysize
- iter = vecPriority.front().second;
- actualPriority = vecPriority.front().first;
- std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
- vecPriority.pop_back();
-
- // If tx already in block, skip
- if (inBlock.count(iter)) {
- assert(false); // shouldn't happen for priority txs
- continue;
- }
-
- // cannot accept witness transactions into a non-witness block
- if (!fIncludeWitness && iter->GetTx().HasWitness())
- continue;
-
- // If tx is dependent on other mempool txs which haven't yet been included
- // then put it in the waitSet
- if (isStillDependent(iter)) {
- waitPriMap.insert(std::make_pair(iter, actualPriority));
- continue;
- }
-
- // If this tx fits in the block add it, otherwise keep looping
- if (TestForBlock(iter)) {
- AddToBlock(iter);
-
- // If now that this txs is added we've surpassed our desired priority size
- // or have dropped below the AllowFreeThreshold, then we're done adding priority txs
- if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) {
- break;
- }
-
- // This tx was successfully added, so
- // add transactions that depend on this one to the priority queue to try again
- BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter))
- {
- waitPriIter wpiter = waitPriMap.find(child);
- if (wpiter != waitPriMap.end()) {
- vecPriority.push_back(TxCoinAgePriority(wpiter->second,child));
- std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
- waitPriMap.erase(wpiter);
- }
- }
- }
- }
- fNeedSizeAccounting = fSizeAccounting;
-}
-
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
diff --git a/src/miner.h b/src/miner.h
index fc2526ff5a..a159b05534 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -158,10 +158,6 @@ private:
int64_t nLockTimeCutoff;
const CChainParams& chainparams;
- // Variables used for addPriorityTxs
- int lastFewTxs;
- bool blockFinished;
-
public:
struct Options {
Options();
@@ -174,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
@@ -184,17 +180,9 @@ private:
void AddToBlock(CTxMemPool::txiter iter);
// Methods for how to add transactions to a block.
- /** Add transactions based on tx "priority" */
- void addPriorityTxs();
/** Add transactions based on feerate including unconfirmed ancestors */
void addPackageTxs();
- // helper function for addPriorityTxs
- /** Test if tx will still "fit" in the block */
- bool TestForBlock(CTxMemPool::txiter iter);
- /** Test if tx still has unconfirmed parents not yet in block */
- bool isStillDependent(CTxMemPool::txiter iter);
-
// helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
diff --git a/src/net.cpp b/src/net.cpp
index e38d3b344e..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
@@ -2288,7 +2293,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
// Dump network addresses
- scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL);
+ scheduler.scheduleEvery(std::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL * 1000);
return true;
}
@@ -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/net_processing.cpp b/src/net_processing.cpp
index 3ec1a1c27d..71a0a1de22 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1853,7 +1853,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
}
// Has inputs but not accepted to mempool
- // Probably non-standard or insufficient fee/priority
+ // Probably non-standard or insufficient fee
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash);
if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
@@ -3249,9 +3249,8 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
static CFeeRate default_feerate(DEFAULT_MIN_RELAY_TX_FEE);
static FeeFilterRounder filterRounder(default_feerate);
CAmount filterToSend = filterRounder.round(currentFilter);
- // If we don't allow free transactions, then we always have a fee filter of at least minRelayTxFee
- if (GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
- filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
+ // We always have a fee filter of at least minRelayTxFee
+ filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
if (filterToSend != pto->lastSentFeeFilter) {
connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
pto->lastSentFeeFilter = filterToSend;
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/policy/fees.cpp b/src/policy/fees.cpp
index 8f6a1e60f4..da33e4100f 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -298,13 +298,13 @@ bool CBlockPolicyEstimator::removeTx(uint256 hash)
}
}
-CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
+CBlockPolicyEstimator::CBlockPolicyEstimator()
: nBestSeenHeight(0), trackedTxs(0), untrackedTxs(0)
{
- static_assert(MIN_FEERATE > 0, "Min feerate must be nonzero");
- minTrackedFee = _minRelayFee < CFeeRate(MIN_FEERATE) ? CFeeRate(MIN_FEERATE) : _minRelayFee;
+ static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
+ minTrackedFee = CFeeRate(MIN_BUCKET_FEERATE);
std::vector<double> vfeelist;
- for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING) {
vfeelist.push_back(bucketBoundary);
}
vfeelist.push_back(INF_FEERATE);
@@ -452,24 +452,6 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
return CFeeRate(median);
}
-double CBlockPolicyEstimator::estimatePriority(int confTarget)
-{
- return -1;
-}
-
-double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
-{
- if (answerFoundAtTarget)
- *answerFoundAtTarget = confTarget;
-
- // If mempool is limiting txs, no priority txs are allowed
- CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
- if (minPoolFee > 0)
- return INF_PRIORITY;
-
- return -1;
-}
-
void CBlockPolicyEstimator::Write(CAutoFile& fileout)
{
fileout << nBestSeenHeight;
@@ -489,7 +471,7 @@ FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
{
CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
feeset.insert(0);
- for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING) {
feeset.insert(bucketBoundary);
}
}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 064466afe4..dd01c90c45 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -179,10 +179,14 @@ static const double MIN_SUCCESS_PCT = .95;
static const double SUFFICIENT_FEETXS = 1;
// Minimum and Maximum values for tracking feerates
-static constexpr double MIN_FEERATE = 10;
-static const double MAX_FEERATE = 1e7;
+// The MIN_BUCKET_FEERATE should just be set to the lowest reasonable feerate we
+// might ever want to track. Historically this has been 1000 since it was
+// inheriting DEFAULT_MIN_RELAY_TX_FEE and changing it is disruptive as it
+// invalidates old estimates files. So leave it at 1000 unless it becomes
+// necessary to lower it, and then lower it substantially.
+static constexpr double MIN_BUCKET_FEERATE = 1000;
+static const double MAX_BUCKET_FEERATE = 1e7;
static const double INF_FEERATE = MAX_MONEY;
-static const double INF_PRIORITY = 1e9 * MAX_MONEY;
// We have to lump transactions into buckets based on feerate, but we want to be able
// to give accurate estimates over a large range of potential feerates
@@ -199,7 +203,7 @@ class CBlockPolicyEstimator
{
public:
/** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
- CBlockPolicyEstimator(const CFeeRate& minRelayFee);
+ CBlockPolicyEstimator();
/** Process all the transactions that have been included in a block */
void processBlock(unsigned int nBlockHeight,
@@ -223,20 +227,6 @@ public:
*/
CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
- /** Return a priority estimate.
- * DEPRECATED
- * Returns -1
- */
- double estimatePriority(int confTarget);
-
- /** Estimate priority needed to get be included in a block within
- * confTarget blocks.
- * DEPRECATED
- * Returns -1 unless mempool is currently limited then returns INF_PRIORITY
- * answerFoundAtTarget is set to confTarget
- */
- double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
-
/** Write estimation data to a file */
void Write(CAutoFile& fileout);
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 9b1323ac26..6df541bc0f 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -16,8 +16,6 @@ class CCoinsViewCache;
/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
-/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
-static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 0;
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
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/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 790bc71d14..a0d7793f97 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -69,6 +69,9 @@ uint256 CTransaction::ComputeHash() const
uint256 CTransaction::GetWitnessHash() const
{
+ if (!HasWitness()) {
+ return GetHash();
+ }
return SerializeHash(*this, SER_GETHASH, 0);
}
@@ -89,32 +92,6 @@ CAmount CTransaction::GetValueOut() const
return nValueOut;
}
-double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
-{
- nTxSize = CalculateModifiedSize(nTxSize);
- if (nTxSize == 0) return 0.0;
-
- return dPriorityInputs / nTxSize;
-}
-
-unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
-{
- // In order to avoid disincentivizing cleaning up the UTXO set we don't count
- // the constant overhead for each txin and up to 110 bytes of scriptSig (which
- // is enough to cover a compressed pubkey p2sh redemption) for priority.
- // Providing any more cleanup incentive than making additional inputs free would
- // risk encouraging people to create junk outputs to redeem later.
- if (nTxSize == 0)
- nTxSize = (GetTransactionWeight(*this) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
- for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
- {
- unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
- if (nTxSize > offset)
- nTxSize -= offset;
- }
- return nTxSize;
-}
-
unsigned int CTransaction::GetTotalSize() const
{
return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index af2986a41b..d413e8b087 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -361,12 +361,6 @@ public:
// GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in.
- // Compute priority, given priority of inputs and (optionally) tx size
- double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
-
- // Compute modified tx size for priority calculation (optionally given tx size)
- unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
-
/**
* Get the total transaction size in bytes, including witness data.
* "Total Size" defined in BIP141 and BIP144.
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index d4fd8bd372..1d19c65753 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -444,11 +444,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CAmount nChange = 0;
unsigned int nBytes = 0;
unsigned int nBytesInputs = 0;
- double dPriority = 0;
- double dPriorityInputs = 0;
unsigned int nQuantity = 0;
- int nQuantityUncompressed = 0;
- bool fAllowFree = false;
bool fWitness = false;
std::vector<COutPoint> vCoinControl;
@@ -473,9 +469,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Amount
nAmount += out.tx->tx->vout[out.i].nValue;
- // Priority
- dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue * (out.nDepth+1);
-
// Bytes
CTxDestination address;
int witnessversion = 0;
@@ -492,8 +485,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (keyid && model->getPubKey(*keyid, pubkey))
{
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
- if (!pubkey.IsCompressed())
- nQuantityUncompressed++;
}
else
nBytesInputs += 148; // in all error cases, simply assume 148 here
@@ -525,17 +516,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee)
nPayFee = coinControl->nMinimumTotalFee;
-
- // Allow free? (require at least hard-coded threshold and default to that if no estimate)
- double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
- dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
- double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
- fAllowFree = (dPriority >= dPriorityNeeded);
-
- if (fSendFreeTransactions)
- if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
- nPayFee = 0;
-
if (nPayAmount > 0)
{
nChange = nAmount - nPayAmount;
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 8be4a955b3..093e644bdc 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -645,7 +645,7 @@
<item>
<widget class="QPushButton" name="btnClearTrafficGraph">
<property name="text">
- <string>&amp;Clear</string>
+ <string>&amp;Reset</string>
</property>
<property name="autoDefault">
<bool>false</bool>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index ca8ecffafe..cc183908d4 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>
@@ -1158,6 +1180,16 @@
</item>
</layout>
</item>
+ <item>
+ <widget class="QCheckBox" name="optInRBF">
+ <property name="text">
+ <string>Request Replace-By-Fee</string>
+ </property>
+ <property name="toolTip">
+ <string>Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed).</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -1168,8 +1200,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>800</width>
- <height>1</height>
+ <width>40</width>
+ <height>5</height>
</size>
</property>
</spacer>
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 1c0ed663c1..ed7eab03f3 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>
@@ -113,6 +114,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p
ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true);
ui->customFee->setValue(settings.value("nTransactionFee").toLongLong());
ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool());
+ ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked);
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
}
@@ -246,6 +248,8 @@ void SendCoinsDialog::on_sendButton_clicked()
else
ctrl.nConfirmTarget = 0;
+ ctrl.signalRbf = ui->optInRBF->isChecked();
+
prepareStatus = model->prepareTransaction(currentTransaction, &ctrl);
// process prepareStatus and on error generate message shown to user
@@ -325,6 +329,13 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
.arg(alternativeUnits.join(" " + tr("or") + "<br />")));
+ if (ui->optInRBF->isChecked())
+ {
+ questionString.append("<hr /><span>");
+ questionString.append(tr("This transaction signals replaceability (optin-RBF)."));
+ questionString.append("</span>");
+ }
+
SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
confirmationDialog.exec();
@@ -656,6 +667,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 +679,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/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index bd496f149c..a7b82117d8 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -148,9 +148,13 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif
+ UnloadBlockIndex();
delete pcoinsTip;
+ pcoinsTip = nullptr;
delete pcoinsdbview;
+ pcoinsdbview = nullptr;
delete pblocktree;
+ pblocktree = nullptr;
boost::filesystem::remove_all(boost::filesystem::path(path));
}
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index d44d711315..d8bcfedb7c 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -7,7 +7,6 @@
#endif
#include "chainparams.h"
-#include "key.h"
#include "rpcnestedtests.h"
#include "util.h"
#include "uritests.h"
@@ -15,20 +14,31 @@
#ifdef ENABLE_WALLET
#include "paymentservertests.h"
+#include "wallettests.h"
#endif
-#include <QCoreApplication>
+#include <QApplication>
#include <QObject>
#include <QTest>
#include <openssl/ssl.h>
-#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000
+#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
+#if QT_VERSION < 0x050000
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
+#else
+#if defined(QT_QPA_PLATFORM_XCB)
+Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
+#elif defined(QT_QPA_PLATFORM_WINDOWS)
+Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
+#elif defined(QT_QPA_PLATFORM_COCOA)
+Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
+#endif
+#endif
#endif
extern void noui_connect();
@@ -36,7 +46,6 @@ extern void noui_connect();
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
- ECC_Start();
SetupEnvironment();
SetupNetworking();
SelectParams(CBaseChainParams::MAIN);
@@ -45,27 +54,36 @@ int main(int argc, char *argv[])
bool fInvalid = false;
// Don't remove this, it's needed to access
- // QCoreApplication:: in the tests
- QCoreApplication app(argc, argv);
+ // QApplication:: and QCoreApplication:: in the tests
+ QApplication app(argc, argv);
app.setApplicationName("Bitcoin-Qt-test");
SSL_library_init();
URITests test1;
- if (QTest::qExec(&test1) != 0)
+ if (QTest::qExec(&test1) != 0) {
fInvalid = true;
+ }
#ifdef ENABLE_WALLET
PaymentServerTests test2;
- if (QTest::qExec(&test2) != 0)
+ if (QTest::qExec(&test2) != 0) {
fInvalid = true;
+ }
#endif
RPCNestedTests test3;
- if (QTest::qExec(&test3) != 0)
+ if (QTest::qExec(&test3) != 0) {
fInvalid = true;
+ }
CompatTests test4;
- if (QTest::qExec(&test4) != 0)
+ if (QTest::qExec(&test4) != 0) {
fInvalid = true;
+ }
+#ifdef ENABLE_WALLET
+ WalletTests test5;
+ if (QTest::qExec(&test5) != 0) {
+ fInvalid = true;
+ }
+#endif
- ECC_Stop();
return fInvalid;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
new file mode 100644
index 0000000000..2bb7f01fdd
--- /dev/null
+++ b/src/qt/test/wallettests.cpp
@@ -0,0 +1,104 @@
+#include "wallettests.h"
+
+#include "qt/bitcoinamountfield.h"
+#include "qt/optionsmodel.h"
+#include "qt/platformstyle.h"
+#include "qt/qvalidatedlineedit.h"
+#include "qt/sendcoinsdialog.h"
+#include "qt/sendcoinsentry.h"
+#include "qt/transactiontablemodel.h"
+#include "qt/walletmodel.h"
+#include "test/test_bitcoin.h"
+#include "validation.h"
+#include "wallet/wallet.h"
+
+#include <QAbstractButton>
+#include <QApplication>
+#include <QTimer>
+#include <QVBoxLayout>
+
+namespace
+{
+//! Press "Yes" button in modal send confirmation dialog.
+void ConfirmSend()
+{
+ QTimer::singleShot(0, Qt::PreciseTimer, []() {
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
+ if (widget->inherits("SendConfirmationDialog")) {
+ SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
+ QAbstractButton* button = dialog->button(QMessageBox::Yes);
+ button->setEnabled(true);
+ button->click();
+ }
+ }
+ });
+}
+
+//! Send coins to address and return txid.
+uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount)
+{
+ QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
+ SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
+ entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString()));
+ entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
+ uint256 txid;
+ boost::signals2::scoped_connection c = wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
+ if (status == CT_NEW) txid = hash;
+ });
+ ConfirmSend();
+ QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
+ return txid;
+}
+
+//! Find index of txid in transaction list.
+QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
+{
+ QString hash = QString::fromStdString(txid.ToString());
+ int rows = model.rowCount({});
+ for (int row = 0; row < rows; ++row) {
+ QModelIndex index = model.index(row, 0, {});
+ if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
+ return index;
+ }
+ }
+ return {};
+}
+}
+
+//! Simple qt wallet tests.
+void WalletTests::walletTests()
+{
+ // Set up wallet and chain with 101 blocks (1 mature block for spending).
+ TestChain100Setup test;
+ test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
+ bitdb.MakeMock();
+ CWallet wallet("wallet_test.dat");
+ bool firstRun;
+ wallet.LoadWallet(firstRun);
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
+ wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
+ }
+ wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
+ wallet.SetBroadcastTransactions(true);
+
+ // Create widgets for sending coins and listing transactions.
+ std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
+ SendCoinsDialog sendCoinsDialog(platformStyle.get());
+ OptionsModel optionsModel;
+ WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
+ sendCoinsDialog.setModel(&walletModel);
+
+ // Send two transactions, and verify they are added to transaction list.
+ TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
+ QCOMPARE(transactionTableModel->rowCount({}), 101);
+ uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN);
+ uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN);
+ QCOMPARE(transactionTableModel->rowCount({}), 103);
+ QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
+ QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
+
+ bitdb.Flush(true);
+ bitdb.Reset();
+}
diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h
new file mode 100644
index 0000000000..342f7916c3
--- /dev/null
+++ b/src/qt/test/wallettests.h
@@ -0,0 +1,15 @@
+#ifndef BITCOIN_QT_TEST_WALLETTESTS_H
+#define BITCOIN_QT_TEST_WALLETTESTS_H
+
+#include <QObject>
+#include <QTest>
+
+class WalletTests : public QObject
+{
+ Q_OBJECT
+
+private Q_SLOTS:
+ void walletTests();
+};
+
+#endif // BITCOIN_QT_TEST_WALLETTESTS_H
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 0a5a7c3e9f..ebcac53c25 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;
@@ -706,3 +706,8 @@ int WalletModel::getDefaultConfirmTarget() const
{
return nTxConfirmTarget;
}
+
+bool WalletModel::getDefaultWalletRbf() const
+{
+ return fWalletRbf;
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index cd7585635f..78e45dc369 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -213,6 +213,8 @@ public:
int getDefaultConfirmTarget() const;
+ bool getDefaultWalletRbf() const;
+
private:
CWallet *wallet;
bool fHaveWatchOnly;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 6826ce4a79..96254a8cb9 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -28,7 +28,6 @@
#include <mutex>
#include <condition_variable>
-using namespace std;
struct CUpdatedBlock
{
@@ -154,7 +153,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
UniValue getblockcount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getblockcount\n"
"\nReturns the number of blocks in the longest blockchain.\n"
"\nResult:\n"
@@ -171,7 +170,7 @@ UniValue getblockcount(const JSONRPCRequest& request)
UniValue getbestblockhash(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getbestblockhash\n"
"\nReturns the hash of the best (tip) block in the longest blockchain.\n"
"\nResult:\n"
@@ -198,7 +197,7 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
UniValue waitfornewblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"waitfornewblock (timeout)\n"
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n"
@@ -236,7 +235,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request)
UniValue waitforblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"waitforblock <blockhash> (timeout)\n"
"\nWaits for a specific new block and returns useful info about it.\n"
"\nReturns the current block on timeout or exit.\n"
@@ -278,7 +277,7 @@ UniValue waitforblock(const JSONRPCRequest& request)
UniValue waitforblockheight(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"waitforblockheight <height> (timeout)\n"
"\nWaits for (at least) block height and returns the height and hash\n"
"of the current tip.\n"
@@ -320,7 +319,7 @@ UniValue waitforblockheight(const JSONRPCRequest& request)
UniValue getdifficulty(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getdifficulty\n"
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
"\nResult:\n"
@@ -341,8 +340,6 @@ std::string EntryDescriptionString()
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
- " \"startingpriority\" : n, (numeric) DEPRECATED. Priority when transaction entered pool\n"
- " \"currentpriority\" : n, (numeric) DEPRECATED. Transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
" \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n"
" \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
@@ -363,8 +360,6 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee())));
info.push_back(Pair("time", e.GetTime()));
info.push_back(Pair("height", (int)e.GetHeight()));
- info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
- info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
info.push_back(Pair("descendantcount", e.GetCountWithDescendants()));
info.push_back(Pair("descendantsize", e.GetSizeWithDescendants()));
info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants()));
@@ -372,7 +367,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors()));
info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors()));
const CTransaction& tx = e.GetTx();
- set<string> setDepends;
+ std::set<std::string> setDepends;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (mempool.exists(txin.prevout.hash))
@@ -380,7 +375,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
}
UniValue depends(UniValue::VARR);
- BOOST_FOREACH(const string& dep, setDepends)
+ BOOST_FOREACH(const std::string& dep, setDepends)
{
depends.push_back(dep);
}
@@ -405,7 +400,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
}
else
{
- vector<uint256> vtxid;
+ std::vector<uint256> vtxid;
mempool.queryHashes(vtxid);
UniValue a(UniValue::VARR);
@@ -419,7 +414,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
UniValue getrawmempool(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
"\nArguments:\n"
@@ -450,7 +445,7 @@ UniValue getrawmempool(const JSONRPCRequest& request)
UniValue getmempoolancestors(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw runtime_error(
+ throw std::runtime_error(
"getmempoolancestors txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
"\nArguments:\n"
@@ -514,7 +509,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request)
UniValue getmempooldescendants(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw runtime_error(
+ throw std::runtime_error(
"getmempooldescendants txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool descendants.\n"
"\nArguments:\n"
@@ -578,7 +573,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request)
UniValue getmempoolentry(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
- throw runtime_error(
+ throw std::runtime_error(
"getmempoolentry txid\n"
"\nReturns mempool data for given transaction\n"
"\nArguments:\n"
@@ -611,7 +606,7 @@ UniValue getmempoolentry(const JSONRPCRequest& request)
UniValue getblockhash(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getblockhash height\n"
"\nReturns hash of block in best-block-chain at height provided.\n"
"\nArguments:\n"
@@ -636,7 +631,7 @@ UniValue getblockhash(const JSONRPCRequest& request)
UniValue getblockheader(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getblockheader \"hash\" ( verbose )\n"
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
"If verbose is true, returns an Object with information about blockheader <hash>.\n"
@@ -695,7 +690,7 @@ UniValue getblockheader(const JSONRPCRequest& request)
UniValue getblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getblock \"blockhash\" ( verbose )\n"
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
"If verbose is true, returns an Object with information about block <hash>.\n"
@@ -749,10 +744,15 @@ UniValue getblock(const JSONRPCRequest& request)
CBlockIndex* pblockindex = mapBlockIndex[hash];
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
- if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
+ if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
+ // Block not found on disk. This could be because we have the block
+ // header in our index but don't have the block (for example if a
+ // non-whitelisted node sends us an unrequested long chain of valid
+ // blocks, we add the headers to our index, but don't accept the
+ // block).
+ throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
if (!fVerbose)
{
@@ -822,7 +822,7 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
UniValue pruneblockchain(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"pruneblockchain\n"
"\nArguments:\n"
"1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n"
@@ -834,7 +834,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
+ HelpExampleRpc("pruneblockchain", "1000"));
if (!fPruneMode)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode.");
+ throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
LOCK(cs_main);
@@ -846,9 +846,9 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
// too low to be a block time (corresponds to timestamp from Sep 2001).
if (heightParam > 1000000000) {
// Add a 2 hour buffer to include blocks which might have had old timestamps
- CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - 7200);
+ CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW);
if (!pindex) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp.");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
}
heightParam = pindex->nHeight;
}
@@ -856,7 +856,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
unsigned int height = (unsigned int) heightParam;
unsigned int chainHeight = (unsigned int) chainActive.Height();
if (chainHeight < Params().PruneAfterHeight())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning.");
+ throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
else if (height > chainHeight)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
@@ -871,7 +871,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request)
UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"gettxoutsetinfo\n"
"\nReturns statistics about the unspent transaction output set.\n"
"Note this call may take some time.\n"
@@ -911,7 +911,7 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
UniValue gettxout(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"gettxout \"txid\" n ( include_mempool )\n"
"\nReturns details about an unspent transaction output.\n"
"\nArguments:\n"
@@ -993,7 +993,7 @@ UniValue verifychain(const JSONRPCRequest& request)
int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
if (request.fHelp || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"verifychain ( checklevel nblocks )\n"
"\nVerifies blockchain database.\n"
"\nArguments:\n"
@@ -1079,7 +1079,7 @@ void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name,
UniValue getblockchaininfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getblockchaininfo\n"
"Returns an object containing various state info regarding blockchain processing.\n"
"\nResult:\n"
@@ -1172,7 +1172,7 @@ struct CompareBlocksByHeight
UniValue getchaintips(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getchaintips\n"
"Return information about all known tips in the block tree,"
" including the main chain as well as orphaned branches.\n"
@@ -1205,7 +1205,7 @@ UniValue getchaintips(const JSONRPCRequest& request)
LOCK(cs_main);
/*
- * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them.
+ * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them.
* Algorithm:
* - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
* - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
@@ -1244,7 +1244,7 @@ UniValue getchaintips(const JSONRPCRequest& request)
const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
obj.push_back(Pair("branchlen", branchLen));
- string status;
+ std::string status;
if (chainActive.Contains(block)) {
// This block is part of the currently active chain.
status = "active";
@@ -1288,7 +1288,7 @@ UniValue mempoolInfoToJSON()
UniValue getmempoolinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getmempoolinfo\n"
"\nReturns details on the active state of the TX memory pool.\n"
"\nResult:\n"
@@ -1310,7 +1310,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request)
UniValue preciousblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"preciousblock \"blockhash\"\n"
"\nTreats a block as if it were received before others with the same work.\n"
"\nA later preciousblock call can override the effect of an earlier one.\n"
@@ -1348,7 +1348,7 @@ UniValue preciousblock(const JSONRPCRequest& request)
UniValue invalidateblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"invalidateblock \"blockhash\"\n"
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
"\nArguments:\n"
@@ -1386,7 +1386,7 @@ UniValue invalidateblock(const JSONRPCRequest& request)
UniValue reconsiderblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"reconsiderblock \"blockhash\"\n"
"\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
"This can be used to undo the effects of invalidateblock.\n"
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 29bdb37682..2cb250a198 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -13,8 +13,6 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <univalue.h>
-using namespace std;
-
class CRPCConvertParam
{
public:
@@ -107,11 +105,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "keypoolrefill", 0, "newsize" },
{ "getrawmempool", 0, "verbose" },
{ "estimatefee", 0, "nblocks" },
- { "estimatepriority", 0, "nblocks" },
{ "estimatesmartfee", 0, "nblocks" },
- { "estimatesmartpriority", 0, "nblocks" },
- { "prioritisetransaction", 1, "priority_delta" },
- { "prioritisetransaction", 2, "fee_delta" },
+ { "prioritisetransaction", 1, "fee_delta" },
{ "setban", 2, "bantime" },
{ "setban", 3, "absolute" },
{ "setnetworkactive", 0, "state" },
@@ -171,7 +166,7 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal)
UniValue jVal;
if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
!jVal.isArray() || jVal.size()!=1)
- throw runtime_error(string("Error parsing JSON:")+strVal);
+ throw std::runtime_error(std::string("Error parsing JSON:")+strVal);
return jVal[0];
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 7708771d00..4db8ffaa7d 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -30,8 +30,6 @@
#include <univalue.h>
-using namespace std;
-
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
@@ -77,7 +75,7 @@ UniValue GetNetworkHashPS(int lookup, int height) {
UniValue getnetworkhashps(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getnetworkhashps ( nblocks height )\n"
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
@@ -149,7 +147,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
UniValue generate(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"generate nblocks ( maxtries )\n"
"\nMine up to nblocks blocks immediately (before the RPC call returns)\n"
"\nArguments:\n"
@@ -185,7 +183,7 @@ UniValue generate(const JSONRPCRequest& request)
UniValue generatetoaddress(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"generatetoaddress nblocks address (maxtries)\n"
"\nMine blocks immediately to a specified address (before the RPC call returns)\n"
"\nArguments:\n"
@@ -208,7 +206,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
-
+
boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
@@ -218,7 +216,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
UniValue getmininginfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getmininginfo\n"
"\nReturns a json object containing mining-related information."
"\nResult:\n"
@@ -258,31 +256,28 @@ UniValue getmininginfo(const JSONRPCRequest& request)
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
UniValue prioritisetransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 3)
- throw runtime_error(
- "prioritisetransaction <txid> <priority delta> <fee delta>\n"
+ if (request.fHelp || request.params.size() != 2)
+ throw std::runtime_error(
+ "prioritisetransaction <txid> <fee delta>\n"
"Accepts the transaction into mined blocks at a higher (or lower) priority\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id.\n"
- "2. priority_delta (numeric, required) The priority to add or subtract.\n"
- " The transaction selection algorithm considers the tx as it would have a higher priority.\n"
- " (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n"
- "3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
+ "2. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee.\n"
"\nResult:\n"
"true (boolean) Returns true\n"
"\nExamples:\n"
- + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
- + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
+ + HelpExampleCli("prioritisetransaction", "\"txid\" 10000")
+ + HelpExampleRpc("prioritisetransaction", "\"txid\", 10000")
);
LOCK(cs_main);
uint256 hash = ParseHashStr(request.params[0].get_str(), "txid");
- CAmount nAmount = request.params[2].get_int64();
+ CAmount nAmount = request.params[1].get_int64();
- mempool.PrioritiseTransaction(hash, request.params[1].get_real(), nAmount);
+ mempool.PrioritiseTransaction(hash, nAmount);
return true;
}
@@ -318,7 +313,7 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
UniValue getblocktemplate(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getblocktemplate ( TemplateRequest )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
@@ -519,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;
@@ -533,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");
@@ -556,7 +562,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
UniValue transactions(UniValue::VARR);
- map<uint256, int64_t> setTxIndex;
+ std::map<uint256, int64_t> setTxIndex;
int i = 0;
for (const auto& it : pblock->vtx) {
const CTransaction& tx = *it;
@@ -686,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())));
}
@@ -715,7 +720,7 @@ protected:
UniValue submitblock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"submitblock \"hexdata\" ( \"jsonparametersobject\" )\n"
"\nAttempts to submit new block to network.\n"
"The 'jsonparametersobject' parameter is currently ignored.\n"
@@ -780,7 +785,7 @@ UniValue submitblock(const JSONRPCRequest& request)
UniValue estimatefee(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"estimatefee nblocks\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within nblocks blocks. Uses virtual transaction size of transaction\n"
@@ -811,37 +816,10 @@ UniValue estimatefee(const JSONRPCRequest& request)
return ValueFromAmount(feeRate.GetFeePerK());
}
-UniValue estimatepriority(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "estimatepriority nblocks\n"
- "\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n"
- "confirmation within nblocks blocks.\n"
- "\nArguments:\n"
- "1. nblocks (numeric, required)\n"
- "\nResult:\n"
- "n (numeric) estimated priority\n"
- "\n"
- "A negative value is returned if not enough transactions and blocks\n"
- "have been observed to make an estimate.\n"
- "\nExample:\n"
- + HelpExampleCli("estimatepriority", "6")
- );
-
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = request.params[0].get_int();
- if (nBlocks < 1)
- nBlocks = 1;
-
- return mempool.estimatePriority(nBlocks);
-}
-
UniValue estimatesmartfee(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"estimatesmartfee nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
@@ -875,48 +853,12 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
return result;
}
-UniValue estimatesmartpriority(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
- "estimatesmartpriority nblocks\n"
- "\nDEPRECATED. WARNING: This interface is unstable and may disappear or change!\n"
- "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
- "confirmation within nblocks blocks if possible and return the number of blocks\n"
- "for which the estimate is valid.\n"
- "\nArguments:\n"
- "1. nblocks (numeric, required)\n"
- "\nResult:\n"
- "{\n"
- " \"priority\" : x.x, (numeric) estimated priority\n"
- " \"blocks\" : n (numeric) block number where estimate was found\n"
- "}\n"
- "\n"
- "A negative value is returned if not enough transactions and blocks\n"
- "have been observed to make an estimate for any number of blocks.\n"
- "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n"
- "\nExample:\n"
- + HelpExampleCli("estimatesmartpriority", "6")
- );
-
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
-
- int nBlocks = request.params[0].get_int();
-
- UniValue result(UniValue::VOBJ);
- int answerFound;
- double priority = mempool.estimateSmartPriority(nBlocks, &answerFound);
- result.push_back(Pair("priority", priority));
- result.push_back(Pair("blocks", answerFound));
- return result;
-}
-
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ----------
{ "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
{ "mining", "getmininginfo", &getmininginfo, true, {} },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","priority_delta","fee_delta"} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","fee_delta"} },
{ "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
{ "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} },
@@ -924,9 +866,7 @@ static const CRPCCommand commands[] =
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
- { "util", "estimatepriority", &estimatepriority, true, {"nblocks"} },
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} },
- { "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 23515f116f..2a8f95b615 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -25,8 +25,6 @@
#include <univalue.h>
-using namespace std;
-
/**
* @note Do not add or change anything in the information returned by this
* method. `getinfo` exists for backwards-compatibility only. It combines
@@ -43,7 +41,7 @@ using namespace std;
UniValue getinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getinfo\n"
"\nDEPRECATED. Returns an object containing various state info.\n"
"\nResult:\n"
@@ -62,7 +60,7 @@ UniValue getinfo(const JSONRPCRequest& request)
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
- " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
+ " \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
@@ -94,7 +92,7 @@ UniValue getinfo(const JSONRPCRequest& request)
obj.push_back(Pair("timeoffset", GetTimeOffset()));
if(g_connman)
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
- obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
+ obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
@@ -159,7 +157,7 @@ public:
UniValue validateaddress(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"validateaddress \"address\"\n"
"\nReturn information about the given bitcoin address.\n"
"\nArguments:\n"
@@ -200,7 +198,7 @@ UniValue validateaddress(const JSONRPCRequest& request)
if (isValid)
{
CTxDestination dest = address.Get();
- string currentAddress = address.ToString();
+ std::string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
CScript scriptPubKey = GetScriptForDestination(dest);
@@ -248,13 +246,13 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa
// Gather public keys
if (nRequired < 1)
- throw runtime_error("a multisignature address must require at least one key to redeem");
+ throw std::runtime_error("a multisignature address must require at least one key to redeem");
if ((int)keys.size() < nRequired)
- throw runtime_error(
+ throw std::runtime_error(
strprintf("not enough keys supplied "
"(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
if (keys.size() > 16)
- throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
+ throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
std::vector<CPubKey> pubkeys;
pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++)
@@ -266,15 +264,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa
if (pwallet && address.IsValid()) {
CKeyID keyID;
if (!address.GetKeyID(keyID))
- throw runtime_error(
+ throw std::runtime_error(
strprintf("%s does not refer to a key",ks));
CPubKey vchPubKey;
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
- throw runtime_error(
+ throw std::runtime_error(
strprintf("no full public key for address %s",ks));
}
if (!vchPubKey.IsFullyValid())
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
}
@@ -285,18 +283,18 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa
{
CPubKey vchPubKey(ParseHex(ks));
if (!vchPubKey.IsFullyValid())
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey;
}
else
{
- throw runtime_error(" Invalid public key: "+ks);
+ throw std::runtime_error(" Invalid public key: "+ks);
}
}
CScript result = GetScriptForMultisig(nRequired, pubkeys);
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
- throw runtime_error(
+ throw std::runtime_error(
strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
return result;
@@ -312,7 +310,7 @@ UniValue createmultisig(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
{
- string msg = "createmultisig nrequired [\"key\",...]\n"
+ std::string msg = "createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys required.\n"
"It returns a json object with the address and redeemScript.\n"
@@ -336,7 +334,7 @@ UniValue createmultisig(const JSONRPCRequest& request)
"\nAs a json rpc call\n"
+ HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
// Construct using pay-to-script-hash:
@@ -354,7 +352,7 @@ UniValue createmultisig(const JSONRPCRequest& request)
UniValue verifymessage(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3)
- throw runtime_error(
+ throw std::runtime_error(
"verifymessage \"address\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
@@ -376,9 +374,9 @@ UniValue verifymessage(const JSONRPCRequest& request)
LOCK(cs_main);
- string strAddress = request.params[0].get_str();
- string strSign = request.params[1].get_str();
- string strMessage = request.params[2].get_str();
+ std::string strAddress = request.params[0].get_str();
+ std::string strSign = request.params[1].get_str();
+ std::string strMessage = request.params[2].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
@@ -389,7 +387,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
bool fInvalid = false;
- vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
+ std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
if (fInvalid)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
@@ -408,7 +406,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
"\nArguments:\n"
@@ -425,8 +423,8 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
);
- string strPrivkey = request.params[0].get_str();
- string strMessage = request.params[1].get_str();
+ std::string strPrivkey = request.params[0].get_str();
+ std::string strMessage = request.params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strPrivkey);
@@ -440,7 +438,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
ss << strMessageMagic;
ss << strMessage;
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
@@ -450,7 +448,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request)
UniValue setmocktime(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
@@ -459,7 +457,7 @@ UniValue setmocktime(const JSONRPCRequest& request)
);
if (!Params().MineBlocksOnDemand())
- throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+ throw std::runtime_error("setmocktime for regression testing (-regtest mode) only");
// For now, don't change mocktime if we're in the middle of validation, as
// this could have an effect on mempool time-based eviction, as well as
@@ -493,7 +491,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
* as users will undoubtedly confuse it with the other "memory pool"
*/
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getmemoryinfo\n"
"Returns an object containing information about memory usage.\n"
"\nResult:\n"
@@ -519,7 +517,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
UniValue echo(const JSONRPCRequest& request)
{
if (request.fHelp)
- throw runtime_error(
+ throw std::runtime_error(
"echo|echojson \"message\" ...\n"
"\nSimply echo back the input arguments. This command is for testing.\n"
"\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in"
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index f590db5efa..44c6e6d308 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -23,12 +23,10 @@
#include <univalue.h>
-using namespace std;
-
UniValue getconnectioncount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getconnectioncount\n"
"\nReturns the number of connections to other nodes.\n"
"\nResult:\n"
@@ -47,7 +45,7 @@ UniValue getconnectioncount(const JSONRPCRequest& request)
UniValue ping(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"ping\n"
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
@@ -70,7 +68,7 @@ UniValue ping(const JSONRPCRequest& request)
UniValue getpeerinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getpeerinfo\n"
"\nReturns data about each connected network node as a json array of objects.\n"
"\nResult:\n"
@@ -102,7 +100,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
" ],\n"
- " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
+ " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
" \"bytessent_per_msg\": {\n"
" \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
" ...\n"
@@ -122,7 +120,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- vector<CNodeStats> vstats;
+ std::vector<CNodeStats> vstats;
g_connman->GetNodeStats(vstats);
UniValue ret(UniValue::VARR);
@@ -191,12 +189,12 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
UniValue addnode(const JSONRPCRequest& request)
{
- string strCommand;
+ std::string strCommand;
if (request.params.size() == 2)
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
- throw runtime_error(
+ throw std::runtime_error(
"addnode \"node\" \"add|remove|onetry\"\n"
"\nAttempts add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
@@ -211,7 +209,7 @@ UniValue addnode(const JSONRPCRequest& request)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- string strNode = request.params[0].get_str();
+ std::string strNode = request.params[0].get_str();
if (strCommand == "onetry")
{
@@ -237,7 +235,7 @@ UniValue addnode(const JSONRPCRequest& request)
UniValue disconnectnode(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"disconnectnode \"node\" \n"
"\nImmediately disconnects from the specified node.\n"
"\nArguments:\n"
@@ -260,7 +258,7 @@ UniValue disconnectnode(const JSONRPCRequest& request)
UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaddednodeinfo ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n"
@@ -328,7 +326,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
UniValue getnettotals(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0)
- throw runtime_error(
+ throw std::runtime_error(
"getnettotals\n"
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n"
@@ -384,7 +382,7 @@ static UniValue GetNetworksInfo()
obj.push_back(Pair("name", GetNetworkName(network)));
obj.push_back(Pair("limited", IsLimited(network)));
obj.push_back(Pair("reachable", IsReachable(network)));
- obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()));
+ obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()));
obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials));
networks.push_back(obj);
}
@@ -394,7 +392,7 @@ static UniValue GetNetworksInfo()
UniValue getnetworkinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getnetworkinfo\n"
"Returns an object containing various state info regarding P2P networking.\n"
"\nResult:\n"
@@ -417,7 +415,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
" ],\n"
- " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
+ " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"incrementalfee\": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
@@ -469,12 +467,12 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue setban(const JSONRPCRequest& request)
{
- string strCommand;
+ std::string strCommand;
if (request.params.size() >= 2)
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
- throw runtime_error(
+ throw std::runtime_error(
"setban \"subnet\" \"add|remove\" (bantime) (absolute)\n"
"\nAttempts add or remove a IP/Subnet from the banned list.\n"
"\nArguments:\n"
@@ -494,7 +492,7 @@ UniValue setban(const JSONRPCRequest& request)
CNetAddr netAddr;
bool isSubnet = false;
- if (request.params[0].get_str().find("/") != string::npos)
+ if (request.params[0].get_str().find("/") != std::string::npos)
isSubnet = true;
if (!isSubnet) {
@@ -506,7 +504,7 @@ UniValue setban(const JSONRPCRequest& request)
LookupSubNet(request.params[0].get_str().c_str(), subNet);
if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
- throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
+ throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet");
if (strCommand == "add")
{
@@ -526,7 +524,7 @@ UniValue setban(const JSONRPCRequest& request)
else if(strCommand == "remove")
{
if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
- throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
+ throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
}
return NullUniValue;
}
@@ -534,7 +532,7 @@ UniValue setban(const JSONRPCRequest& request)
UniValue listbanned(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"listbanned\n"
"\nList all banned IPs/Subnets.\n"
"\nExamples:\n"
@@ -567,7 +565,7 @@ UniValue listbanned(const JSONRPCRequest& request)
UniValue clearbanned(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"clearbanned\n"
"\nClear all banned IPs.\n"
"\nExamples:\n"
@@ -585,7 +583,7 @@ UniValue clearbanned(const JSONRPCRequest& request)
UniValue setnetworkactive(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
- throw runtime_error(
+ throw std::runtime_error(
"setnetworkactive true|false\n"
"\nDisable/enable all p2p network activity.\n"
"\nArguments:\n"
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index dc710d939f..2be1edb5a6 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -15,8 +15,6 @@
#include <stdint.h>
#include <fstream>
-using namespace std;
-
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
* but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
@@ -26,7 +24,7 @@ using namespace std;
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
-UniValue JSONRPCRequestObj(const string& strMethod, const UniValue& params, const UniValue& id)
+UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
{
UniValue request(UniValue::VOBJ);
request.push_back(Pair("method", strMethod));
@@ -47,13 +45,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
return reply;
}
-string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
+std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
UniValue reply = JSONRPCReplyObj(result, error, id);
return reply.write() + "\n";
}
-UniValue JSONRPCError(int code, const string& message)
+UniValue JSONRPCError(int code, const std::string& message)
{
UniValue error(UniValue::VOBJ);
error.push_back(Pair("code", code));
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 47e56e712b..85bc4db101 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -31,9 +31,15 @@ enum HTTPStatusCode
enum RPCErrorCode
{
//! Standard JSON-RPC 2.0 errors
+ // RPC_INVALID_REQUEST is internally mapped to HTTP_BAD_REQUEST (400).
+ // It should not be used for application-layer errors.
RPC_INVALID_REQUEST = -32600,
+ // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404).
+ // It should not be used for application-layer errors.
RPC_METHOD_NOT_FOUND = -32601,
RPC_INVALID_PARAMS = -32602,
+ // RPC_INTERNAL_ERROR should only be used for genuine errors in bitcoind
+ // (for example datadir corruption).
RPC_INTERNAL_ERROR = -32603,
RPC_PARSE_ERROR = -32700,
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 79b27d0475..c438d90a47 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -34,12 +34,10 @@
#include <univalue.h>
-using namespace std;
-
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
{
txnouttype type;
- vector<CTxDestination> addresses;
+ std::vector<CTxDestination> addresses;
int nRequired;
out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey)));
@@ -127,7 +125,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
UniValue getrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
"\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n"
@@ -215,7 +213,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
}
else {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean.");
- }
+ }
}
CTransactionRef tx;
@@ -225,7 +223,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
: "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
". Use gettransaction for wallet transactions.");
- string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
if (!fVerbose)
return strHex;
@@ -239,7 +237,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
UniValue gettxoutproof(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
- throw runtime_error(
+ throw std::runtime_error(
"gettxoutproof [\"txid\",...] ( blockhash )\n"
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
"\nNOTE: By default this function only works sometimes. This is when there is an\n"
@@ -257,16 +255,16 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
);
- set<uint256> setTxids;
+ std::set<uint256> setTxids;
uint256 oneTxid;
UniValue txids = request.params[0].get_array();
for (unsigned int idx = 0; idx < txids.size(); idx++) {
const UniValue& txid = txids[idx];
if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str());
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str());
uint256 hash(uint256S(txid.get_str()));
if (setTxids.count(hash))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str());
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str());
setTxids.insert(hash);
oneTxid = hash;
}
@@ -319,7 +317,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request)
UniValue verifytxoutproof(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"verifytxoutproof \"proof\"\n"
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
"and throwing an RPC error if the block is not in our best chain\n"
@@ -335,8 +333,8 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
UniValue res(UniValue::VARR);
- vector<uint256> vMatch;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatch;
+ std::vector<unsigned int> vIndex;
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot)
return res;
@@ -353,7 +351,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request)
UniValue createrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
"Outputs can be addresses or data.\n"
@@ -434,9 +432,9 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
rawTx.vin.push_back(in);
}
- set<CBitcoinAddress> setAddress;
- vector<string> addrList = sendTo.getKeys();
- BOOST_FOREACH(const string& name_, addrList) {
+ std::set<CBitcoinAddress> setAddress;
+ std::vector<std::string> addrList = sendTo.getKeys();
+ BOOST_FOREACH(const std::string& name_, addrList) {
if (name_ == "data") {
std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
@@ -446,10 +444,10 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
} else {
CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
@@ -466,7 +464,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
UniValue decoderawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"decoderawtransaction \"hexstring\"\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
@@ -535,7 +533,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
UniValue decodescript(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"decodescript \"hexstring\"\n"
"\nDecode a hex-encoded script.\n"
"\nArguments:\n"
@@ -562,7 +560,7 @@ UniValue decodescript(const JSONRPCRequest& request)
UniValue r(UniValue::VOBJ);
CScript script;
if (request.params[0].get_str().size() > 0){
- vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
+ std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
script = CScript(scriptData.begin(), scriptData.end());
} else {
// Empty scripts are valid
@@ -600,7 +598,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
"The second optional argument (may be null) is an array of previous transaction outputs that\n"
@@ -665,9 +663,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
- vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
+ std::vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
- vector<CMutableTransaction> txVariants;
+ std::vector<CMutableTransaction> txVariants;
while (!ssData.empty()) {
try {
CMutableTransaction tx;
@@ -750,13 +748,13 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
if (nOut < 0)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
- vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
+ std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
CScript scriptPubKey(pkData.begin(), pkData.end());
{
CCoinsModifier coins = view.ModifyCoins(txid);
if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
- string err("Previous output scriptPubKey mismatch:\n");
+ std::string err("Previous output scriptPubKey mismatch:\n");
err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
@@ -782,7 +780,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
});
UniValue v = find_value(prevOut, "redeemScript");
if (!v.isNull()) {
- vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
+ std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
@@ -798,16 +796,16 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
int nHashType = SIGHASH_ALL;
if (request.params.size() > 3 && !request.params[3].isNull()) {
- static map<string, int> mapSigHashValues =
+ static std::map<std::string, int> mapSigHashValues =
boost::assign::map_list_of
- (string("ALL"), int(SIGHASH_ALL))
- (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
- (string("NONE"), int(SIGHASH_NONE))
- (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
- (string("SINGLE"), int(SIGHASH_SINGLE))
- (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
+ (std::string("ALL"), int(SIGHASH_ALL))
+ (std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
+ (std::string("NONE"), int(SIGHASH_NONE))
+ (std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
+ (std::string("SINGLE"), int(SIGHASH_SINGLE))
+ (std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
;
- string strHashType = request.params[3].get_str();
+ std::string strHashType = request.params[3].get_str();
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
@@ -867,7 +865,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
UniValue sendrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"sendrawtransaction \"hexstring\" ( allowhighfees )\n"
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nAlso see createrawtransaction and signrawtransaction calls.\n"
@@ -897,7 +895,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const uint256& hashTx = tx->GetHash();
- bool fLimitFree = false;
+ bool fLimitFree = true;
CAmount nMaxRawTxFee = maxTxFee;
if (request.params.size() > 1 && request.params[1].get_bool())
nMaxRawTxFee = 0;
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index f418d71e71..9b0699afcc 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -26,9 +26,6 @@
#include <memory> // for unique_ptr
#include <unordered_map>
-using namespace RPCServer;
-using namespace std;
-
static bool fRPCRunning = false;
static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
@@ -43,7 +40,6 @@ static struct CRPCSignals
boost::signals2::signal<void ()> Started;
boost::signals2::signal<void ()> Stopped;
boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
- boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
} g_rpcSignals;
void RPCServer::OnStarted(boost::function<void ()> slot)
@@ -61,13 +57,8 @@ void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
}
-void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
-{
- g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
-}
-
void RPCTypeCheck(const UniValue& params,
- const list<UniValue::VType>& typesExpected,
+ const std::list<UniValue::VType>& typesExpected,
bool fAllowNull)
{
unsigned int i = 0;
@@ -92,7 +83,7 @@ void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
}
void RPCTypeCheckObj(const UniValue& o,
- const map<string, UniValueType>& typesExpected,
+ const std::map<std::string, UniValueType>& typesExpected,
bool fAllowNull,
bool fStrict)
{
@@ -102,7 +93,7 @@ void RPCTypeCheckObj(const UniValue& o,
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
- string err = strprintf("Expected type %s for %s, got %s",
+ std::string err = strprintf("Expected type %s for %s, got %s",
uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
@@ -110,11 +101,11 @@ void RPCTypeCheckObj(const UniValue& o,
if (fStrict)
{
- BOOST_FOREACH(const string& k, o.getKeys())
+ BOOST_FOREACH(const std::string& k, o.getKeys())
{
if (typesExpected.count(k) == 0)
{
- string err = strprintf("Unexpected key %s", k);
+ std::string err = strprintf("Unexpected key %s", k);
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
@@ -143,9 +134,9 @@ UniValue ValueFromAmount(const CAmount& amount)
strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
-uint256 ParseHashV(const UniValue& v, string strName)
+uint256 ParseHashV(const UniValue& v, std::string strName)
{
- string strHex;
+ std::string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
@@ -156,20 +147,20 @@ uint256 ParseHashV(const UniValue& v, string strName)
result.SetHex(strHex);
return result;
}
-uint256 ParseHashO(const UniValue& o, string strKey)
+uint256 ParseHashO(const UniValue& o, std::string strKey)
{
return ParseHashV(find_value(o, strKey), strKey);
}
-vector<unsigned char> ParseHexV(const UniValue& v, string strName)
+std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
{
- string strHex;
+ std::string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
return ParseHex(strHex);
}
-vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
+std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
{
return ParseHexV(find_value(o, strKey), strKey);
}
@@ -180,12 +171,12 @@ vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
{
- string strRet;
- string category;
- set<rpcfn_type> setDone;
- vector<pair<string, const CRPCCommand*> > vCommands;
+ std::string strRet;
+ std::string category;
+ std::set<rpcfn_type> setDone;
+ std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
- for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
+ for (std::map<std::string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
sort(vCommands.begin(), vCommands.end());
@@ -193,10 +184,10 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
jreq.fHelp = true;
jreq.params = UniValue();
- BOOST_FOREACH(const PAIRTYPE(string, const CRPCCommand*)& command, vCommands)
+ BOOST_FOREACH(const PAIRTYPE(std::string, const CRPCCommand*)& command, vCommands)
{
const CRPCCommand *pcmd = command.second;
- string strMethod = pcmd->name;
+ std::string strMethod = pcmd->name;
if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
continue;
jreq.strMethod = strMethod;
@@ -209,10 +200,10 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
catch (const std::exception& e)
{
// Help text is returned in an exception
- string strHelp = string(e.what());
+ std::string strHelp = std::string(e.what());
if (strCommand == "")
{
- if (strHelp.find('\n') != string::npos)
+ if (strHelp.find('\n') != std::string::npos)
strHelp = strHelp.substr(0, strHelp.find('\n'));
if (category != pcmd->category)
@@ -220,7 +211,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
if (!category.empty())
strRet += "\n";
category = pcmd->category;
- string firstLetter = category.substr(0,1);
+ std::string firstLetter = category.substr(0,1);
boost::to_upper(firstLetter);
strRet += "== " + firstLetter + category.substr(1) + " ==\n";
}
@@ -237,7 +228,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
UniValue help(const JSONRPCRequest& jsonRequest)
{
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"help ( \"command\" )\n"
"\nList all commands, or get help for a specified command.\n"
"\nArguments:\n"
@@ -246,7 +237,7 @@ UniValue help(const JSONRPCRequest& jsonRequest)
"\"text\" (string) The help text\n"
);
- string strCommand;
+ std::string strCommand;
if (jsonRequest.params.size() > 0)
strCommand = jsonRequest.params[0].get_str();
@@ -258,7 +249,7 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"stop\n"
"\nStop Bitcoin server.");
// Event loop will exit after current HTTP requests have been handled, so
@@ -292,7 +283,7 @@ CRPCTable::CRPCTable()
const CRPCCommand *CRPCTable::operator[](const std::string &name) const
{
- map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+ std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
return NULL;
return (*it).second;
@@ -304,7 +295,7 @@ bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
return false;
// don't allow overwriting for now
- map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
+ std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it != mapCommands.end())
return false;
@@ -494,8 +485,6 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
-
- g_rpcSignals.PostCommand(*pcmd);
}
std::vector<std::string> CRPCTable::listCommands() const
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index b01170074d..861c1a0220 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -104,20 +104,20 @@ void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::t
newTaskScheduled.notify_one();
}
-void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds)
+void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaMilliSeconds)
{
- schedule(f, boost::chrono::system_clock::now() + boost::chrono::seconds(deltaSeconds));
+ schedule(f, boost::chrono::system_clock::now() + boost::chrono::milliseconds(deltaMilliSeconds));
}
-static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds)
+static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaMilliSeconds)
{
f();
- s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaSeconds), deltaSeconds);
+ s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaMilliSeconds), deltaMilliSeconds);
}
-void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds)
+void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaMilliSeconds)
{
- scheduleFromNow(boost::bind(&Repeat, this, f, deltaSeconds), deltaSeconds);
+ scheduleFromNow(boost::bind(&Repeat, this, f, deltaMilliSeconds), deltaMilliSeconds);
}
size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
diff --git a/src/scheduler.h b/src/scheduler.h
index 436659e58b..613fc1653f 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -10,7 +10,6 @@
// boost::thread / boost::function / boost::chrono should be ported to
// std::thread / std::function / std::chrono when we support C++11.
//
-#include <boost/function.hpp>
#include <boost/chrono/chrono.hpp>
#include <boost/thread.hpp>
#include <map>
@@ -23,7 +22,7 @@
//
// CScheduler* s = new CScheduler();
// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { }
-// s->scheduleFromNow(boost::bind(Class::func, this, argument), 3);
+// s->scheduleFromNow(std::bind(Class::func, this, argument), 3);
// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s));
//
// ... then at program shutdown, clean up the thread running serviceQueue:
@@ -39,20 +38,20 @@ public:
CScheduler();
~CScheduler();
- typedef boost::function<void(void)> Function;
+ typedef std::function<void(void)> Function;
// Call func at/after time t
void schedule(Function f, boost::chrono::system_clock::time_point t);
// Convenience method: call f once deltaSeconds from now
- void scheduleFromNow(Function f, int64_t deltaSeconds);
+ void scheduleFromNow(Function f, int64_t deltaMilliSeconds);
// Another convenience method: call f approximately
// every deltaSeconds forever, starting deltaSeconds from now.
// To be more precise: every time f is finished, it
// is rescheduled to run deltaSeconds later. If you
// need more accurate scheduling, don't use this method.
- void scheduleEvery(Function f, int64_t deltaSeconds);
+ void scheduleEvery(Function f, int64_t deltaMilliSeconds);
// To keep things as simple as possible, there is no unschedule.
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index f9b7835882..8ecf0bbdac 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -13,9 +13,7 @@
#include "script/script.h"
#include "uint256.h"
-using namespace std;
-
-typedef vector<unsigned char> valtype;
+typedef std::vector<unsigned char> valtype;
namespace {
@@ -56,10 +54,10 @@ bool CastToBool(const valtype& vch)
*/
#define stacktop(i) (stack.at(stack.size()+(i)))
#define altstacktop(i) (altstack.at(altstack.size()+(i)))
-static inline void popstack(vector<valtype>& stack)
+static inline void popstack(std::vector<valtype>& stack)
{
if (stack.empty())
- throw runtime_error("popstack(): stack empty");
+ throw std::runtime_error("popstack(): stack empty");
stack.pop_back();
}
@@ -194,7 +192,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
return true;
}
-bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
+bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
// Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
if (vchSig.size() == 0) {
@@ -245,7 +243,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
-bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
+bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@@ -260,8 +258,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
CScript::const_iterator pbegincodehash = script.begin();
opcodetype opcode;
valtype vchPushValue;
- vector<bool> vfExec;
- vector<valtype> altstack;
+ std::vector<bool> vfExec;
+ std::vector<valtype> altstack;
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if (script.size() > MAX_SCRIPT_SIZE)
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
@@ -1250,14 +1248,14 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha
return pubkey.Verify(sighash, vchSig);
}
-bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
+bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;
// Hash type is one byte tacked on to the end of the signature
- vector<unsigned char> vchSig(vchSigIn);
+ std::vector<unsigned char> vchSig(vchSigIn);
if (vchSig.empty())
return false;
int nHashType = vchSig.back();
@@ -1355,7 +1353,7 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
- vector<vector<unsigned char> > stack;
+ std::vector<std::vector<unsigned char> > stack;
CScript scriptPubKey;
if (witversion == 0) {
@@ -1420,7 +1418,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
}
- vector<vector<unsigned char> > stack, stackCopy;
+ std::vector<std::vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror))
// serror is set
return false;
@@ -1558,7 +1556,7 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) {
CScript::const_iterator pc = scriptSig.begin();
- vector<unsigned char> data;
+ std::vector<unsigned char> data;
while (pc < scriptSig.end()) {
opcodetype opcode;
scriptSig.GetOp(pc, opcode, data);
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 608a8de8f5..a4743281b1 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -13,11 +13,9 @@
#include <boost/foreach.hpp>
-using namespace std;
+typedef std::vector<unsigned char> valtype;
-typedef vector<unsigned char> valtype;
-
-unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
+unsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
{
unsigned int nResult = 0;
BOOST_FOREACH(const valtype& pubkey, pubkeys)
@@ -49,7 +47,7 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i
isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)
{
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
if (keystore.HaveWatchOnly(scriptPubKey))
@@ -132,7 +130,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
// partially owned (somebody else has a key that can spend
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
- vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+ std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
if (sigversion != SIGVERSION_BASE) {
for (size_t i = 0; i < keys.size(); i++) {
if (keys[i].size() != 33) {
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 01180a7d6d..70eb8a139b 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -8,8 +8,6 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
-using namespace std;
-
const char* GetOpName(opcodetype opcode)
{
switch (opcode)
@@ -186,7 +184,7 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
// get the last item that the scriptSig
// pushes onto the stack:
const_iterator pc = scriptSig.begin();
- vector<unsigned char> vData;
+ std::vector<unsigned char> vData;
while (pc < scriptSig.end())
{
opcodetype opcode;
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index b008df2591..5682418546 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -14,8 +14,6 @@
#include <boost/foreach.hpp>
-using namespace std;
-
typedef std::vector<unsigned char> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
@@ -39,14 +37,14 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!creator.CreateSig(vchSig, address, scriptCode, sigversion))
return false;
ret.push_back(vchSig);
return true;
}
-static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
+static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
@@ -73,7 +71,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
uint160 h160;
ret.clear();
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
return false;
@@ -125,7 +123,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
}
}
-static CScript PushAll(const vector<valtype>& values)
+static CScript PushAll(const std::vector<valtype>& values)
{
CScript result;
BOOST_FOREACH(const valtype& v, values) {
@@ -228,12 +226,12 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType);
}
-static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const vector<valtype>& vSolutions,
- const vector<valtype>& sigs1, const vector<valtype>& sigs2, SigVersion sigversion)
+static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
+ const std::vector<valtype>& vSolutions,
+ const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion)
{
// Combine all the signatures we've got:
- set<valtype> allsigs;
+ std::set<valtype> allsigs;
BOOST_FOREACH(const valtype& v, sigs1)
{
if (!v.empty())
@@ -249,7 +247,7 @@ static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSi
assert(vSolutions.size() > 1);
unsigned int nSigsRequired = vSolutions.front()[0];
unsigned int nPubKeys = vSolutions.size()-2;
- map<valtype, valtype> sigs;
+ std::map<valtype, valtype> sigs;
BOOST_FOREACH(const valtype& sig, allsigs)
{
for (unsigned int i = 0; i < nPubKeys; i++)
@@ -306,7 +304,7 @@ struct Stacks
}
static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
- const txnouttype txType, const vector<valtype>& vSolutions,
+ const txnouttype txType, const std::vector<valtype>& vSolutions,
Stacks sigs1, Stacks sigs2, SigVersion sigversion)
{
switch (txType)
@@ -340,7 +338,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
CScript pubKey2(spk.begin(), spk.end());
txnouttype txType2;
- vector<vector<unsigned char> > vSolutions2;
+ std::vector<std::vector<unsigned char> > vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.script.pop_back();
sigs2.script.pop_back();
@@ -360,7 +358,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
// Recur to combine:
CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end());
txnouttype txType2;
- vector<valtype> vSolutions2;
+ std::vector<valtype> vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.witness.pop_back();
sigs1.script = sigs1.witness;
@@ -383,7 +381,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature
const SignatureData& scriptSig1, const SignatureData& scriptSig2)
{
txnouttype txType;
- vector<vector<unsigned char> > vSolutions;
+ std::vector<std::vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions);
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output();
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 4b9bec9aa1..63f20b0993 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -12,9 +12,7 @@
#include <boost/foreach.hpp>
-using namespace std;
-
-typedef vector<unsigned char> valtype;
+typedef std::vector<unsigned char> valtype;
bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
@@ -40,20 +38,20 @@ const char* GetTxnOutputType(txnouttype t)
/**
* Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
*/
-bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
+bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
{
// Templates
- static multimap<txnouttype, CScript> mTemplates;
+ static std::multimap<txnouttype, CScript> mTemplates;
if (mTemplates.empty())
{
// Standard tx, sender provides pubkey, receiver adds signature
- mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
+ mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
- mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
+ mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
// Sender provides N pubkeys, receivers provides M signatures
- mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
+ mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
}
vSolutionsRet.clear();
@@ -63,7 +61,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
if (scriptPubKey.IsPayToScriptHash())
{
typeRet = TX_SCRIPTHASH;
- vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
+ std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
vSolutionsRet.push_back(hashBytes);
return true;
}
@@ -102,7 +100,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
vSolutionsRet.clear();
opcodetype opcode1, opcode2;
- vector<unsigned char> vch1, vch2;
+ std::vector<unsigned char> vch1, vch2;
// Compare
CScript::const_iterator pc1 = script1.begin();
@@ -181,7 +179,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
@@ -209,11 +207,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
return false;
}
-bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
+bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
typeRet = TX_NONSTANDARD;
- vector<valtype> vSolutions;
+ std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, typeRet, vSolutions))
return false;
if (typeRet == TX_NULL_DATA){
diff --git a/src/test/bctest.py b/src/test/bctest.py
index adc5d0e418..c69f52afc3 100644
--- a/src/test/bctest.py
+++ b/src/test/bctest.py
@@ -10,6 +10,7 @@ import sys
import binascii
import difflib
import logging
+import pprint
def parse_output(a, fmt):
"""Parse the output according to specified format.
@@ -65,6 +66,7 @@ def bctest(testDir, testObj, exeext):
raise
if outputData:
+ data_mismatch, formatting_mismatch = False, False
# Parse command output and expected output
try:
a_parsed = parse_output(outs[0], outputType)
@@ -79,7 +81,7 @@ def bctest(testDir, testObj, exeext):
# Compare data
if a_parsed != b_parsed:
logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")")
- raise Exception
+ data_mismatch = True
# Compare formatting
if outs[0] != outputData:
error_message = "Output formatting mismatch for " + outputFn + ":\n"
@@ -88,7 +90,9 @@ def bctest(testDir, testObj, exeext):
fromfile=outputFn,
tofile="returned"))
logging.error(error_message)
- raise Exception
+ formatting_mismatch = True
+
+ assert not data_mismatch and not formatting_mismatch
# Compare the return code to the expected return code
wantRC = 0
@@ -115,7 +119,9 @@ def bctester(testDir, input_basename, buildenv):
failed_testcases.append(testObj["description"])
if failed_testcases:
- logging.error("FAILED TESTCASES: [" + ", ".join(failed_testcases) + "]")
+ error_message = "FAILED_TESTCASES:\n"
+ error_message += pprint.pformat(failed_testcases, width=400)
+ logging.error(error_message)
sys.exit(1)
else:
sys.exit(0)
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 311ac024f3..9e4a56919d 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -57,7 +57,7 @@ static CBlock BuildBlockTestCase() {
BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
@@ -156,7 +156,7 @@ public:
BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
CBlock block(BuildBlockTestCase());
@@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
CMutableTransaction coinbase;
coinbase.vin.resize(1);
coinbase.vin[0].scriptSig.resize(10);
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/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 91f549fe48..51b28d09fa 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
}
- CTxMemPool testPool(CFeeRate(0));
+ CTxMemPool testPool;
// Nothing in pool, remove should do nothing:
unsigned int poolSize = testPool.size();
@@ -118,7 +118,7 @@ void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
/* 3rd highest fee */
@@ -126,28 +126,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
/* highest fee */
CMutableTransaction tx2 = CMutableTransaction();
tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx2.vout[0].nValue = 2 * COIN;
- pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
/* lowest fee */
CMutableTransaction tx3 = CMutableTransaction();
tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx3.vout[0].nValue = 5 * COIN;
- pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
/* 2nd highest fee */
CMutableTransaction tx4 = CMutableTransaction();
tx4.vout.resize(1);
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx4.vout[0].nValue = 6 * COIN;
- pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
/* equal fee rate to tx1, but newer */
CMutableTransaction tx5 = CMutableTransaction();
@@ -155,7 +155,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx5.vout[0].nValue = 11 * COIN;
entry.nTime = 1;
- entry.dPriority = 10.0;
pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
BOOST_CHECK_EQUAL(pool.size(), 5);
@@ -320,7 +319,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
{
- CTxMemPool pool(CFeeRate(0));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
/* 3rd highest fee */
@@ -328,14 +327,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1));
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
/* highest fee */
CMutableTransaction tx2 = CMutableTransaction();
tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx2.vout[0].nValue = 2 * COIN;
- pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2));
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
uint64_t tx2Size = GetVirtualTransactionSize(tx2);
/* lowest fee */
@@ -343,14 +342,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx3.vout[0].nValue = 5 * COIN;
- pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3));
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
/* 2nd highest fee */
CMutableTransaction tx4 = CMutableTransaction();
tx4.vout.resize(1);
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx4.vout[0].nValue = 6 * COIN;
- pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4));
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
/* equal fee rate to tx1, but newer */
CMutableTransaction tx5 = CMutableTransaction();
@@ -408,7 +407,6 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
/* set the fee to just below tx2's feerate when including ancestor */
CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
- //CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true);
pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));
BOOST_CHECK_EQUAL(pool.size(), 7);
sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
@@ -432,9 +430,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
{
- CTxMemPool pool(CFeeRate(1000));
+ CTxMemPool pool;
TestMemPoolEntryHelper entry;
- entry.dPriority = 10.0;
CMutableTransaction tx1 = CMutableTransaction();
tx1.vin.resize(1);
@@ -442,7 +439,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool));
+ pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
CMutableTransaction tx2 = CMutableTransaction();
tx2.vin.resize(1);
@@ -450,7 +447,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
tx2.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool));
+ pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2));
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
BOOST_CHECK(pool.exists(tx1.GetHash()));
@@ -460,7 +457,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx1.GetHash()));
BOOST_CHECK(!pool.exists(tx2.GetHash()));
- pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool));
+ pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2));
CMutableTransaction tx3 = CMutableTransaction();
tx3.vin.resize(1);
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
@@ -468,7 +465,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
tx3.vout[0].nValue = 10 * COIN;
- pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool));
+ pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
BOOST_CHECK(!pool.exists(tx1.GetHash()));
@@ -531,10 +528,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[1].nValue = 10 * COIN;
- pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool));
- pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
- pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool));
- pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
+ pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4));
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
+ pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6));
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
// we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that
pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
@@ -543,8 +540,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(tx7.GetHash()));
if (!pool.exists(tx5.GetHash()))
- pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
- pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
BOOST_CHECK(pool.exists(tx4.GetHash()));
@@ -552,8 +549,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx6.GetHash()));
BOOST_CHECK(!pool.exists(tx7.GetHash()));
- pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
- pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
+ pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
+ pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
std::vector<CTransactionRef> vtx;
SetMockTime(42);
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 5dbbb1b634..41f42c7b88 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -88,7 +88,6 @@ bool TestSequenceLocks(const CTransaction &tx, int flags)
// Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case,
// to allow reusing the blockchain created in CreateNewBlock_validity.
-// Note that this test assumes blockprioritysize is 0.
void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst)
{
// Test the ancestor feerate transaction selection.
@@ -203,7 +202,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
uint256 hash;
TestMemPoolEntryHelper entry;
entry.nFee = 11;
- entry.dPriority = 111.0;
entry.nHeight = 11;
LOCK(cs_main);
@@ -308,7 +306,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
- // child with higher priority than parent
+ // child with higher feerate than parent
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 0c060801bc..bc2f49ef3f 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -16,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
{
- CTxMemPool mpool(CFeeRate(1000));
+ CTxMemPool mpool;
TestMemPoolEntryHelper entry;
CAmount basefee(2000);
CAmount deltaFee(100);
@@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
uint256 hash = tx.GetHash();
- mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
@@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
- mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash);
}
}
@@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash();
- mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
CTransactionRef ptx = mpool.get(hash);
if (ptx)
block.push_back(ptx);
@@ -185,15 +185,13 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
}
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
- // and that estimateSmartPriority returns essentially an infinite value
- mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
+ mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
mpool.TrimToSize(1);
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
for (int i = 1; i < 10; i++) {
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
- BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY);
}
}
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 6039424480..abaec45cd7 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -2,8 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#define BOOST_TEST_MODULE Bitcoin Test Suite
-
#include "test_bitcoin.h"
#include "chainparams.h"
@@ -27,10 +25,8 @@
#include <memory>
#include <boost/filesystem.hpp>
-#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
-std::unique_ptr<CConnman> g_connman;
FastRandomContext insecure_rand_ctx(true);
extern bool fPrintToConsole;
@@ -69,11 +65,14 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
pblocktree = new CBlockTreeDB(1 << 20, true);
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
- BOOST_REQUIRE(InitBlockIndex(chainparams));
+ if (!InitBlockIndex(chainparams)) {
+ throw std::runtime_error("InitBlockIndex failed.");
+ }
{
CValidationState state;
- bool ok = ActivateBestChain(state, chainparams);
- BOOST_REQUIRE(ok);
+ if (!ActivateBestChain(state, chainparams)) {
+ throw std::runtime_error("ActivateBestChain failed.");
+ }
}
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
@@ -141,30 +140,12 @@ TestChain100Setup::~TestChain100Setup()
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) {
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
CTransaction txn(tx);
- return FromTx(txn, pool);
-}
-
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) {
- // Hack to assume either it's completely dependent on other mempool txs or not at all
- CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : 0;
-
- return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
- inChainValue, spendsCoinbase, sigOpCost, lp);
-}
-
-void Shutdown(void* parg)
-{
- exit(EXIT_SUCCESS);
-}
-
-void StartShutdown()
-{
- exit(EXIT_SUCCESS);
+ return FromTx(txn);
}
-bool ShutdownRequested()
-{
- return false;
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
+ return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
+ spendsCoinbase, sigOpCost, lp);
}
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 5ef6fa764f..a593f136eb 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -61,30 +61,27 @@ struct TestChain100Setup : public TestingSetup {
};
class CTxMemPoolEntry;
-class CTxMemPool;
struct TestMemPoolEntryHelper
{
// Default values
CAmount nFee;
int64_t nTime;
- double dPriority;
unsigned int nHeight;
bool spendsCoinbase;
unsigned int sigOpCost;
LockPoints lp;
TestMemPoolEntryHelper() :
- nFee(0), nTime(0), dPriority(0.0), nHeight(1),
+ nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { }
- CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = NULL);
- CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = NULL);
+ CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
+ CTxMemPoolEntry FromTx(const CTransaction &tx);
// Change the default value
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; }
- TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
new file mode 100644
index 0000000000..34beef5539
--- /dev/null
+++ b/src/test/test_bitcoin_main.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) 2011-2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#define BOOST_TEST_MODULE Bitcoin Test Suite
+
+#include "net.h"
+
+#include <boost/test/unit_test.hpp>
+
+std::unique_ptr<CConnman> g_connman;
+
+void Shutdown(void* parg)
+{
+ exit(EXIT_SUCCESS);
+}
+
+void StartShutdown()
+{
+ exit(EXIT_SUCCESS);
+}
+
+bool ShutdownRequested()
+{
+ return false;
+}
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 374423179c..3b5da4980b 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -189,7 +189,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
- ScriptError err;
+ // Initialize to SCRIPT_ERR_OK. The tests expect err to be changed to a
+ // value other than SCRIPT_ERR_OK.
+ ScriptError err = SCRIPT_ERR_OK;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
std::string strTest = test.write();
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 641655621c..79d02257fa 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -321,7 +321,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(ParseInt32("1234", &n) && n == 1234);
BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal
BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647);
- BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
+ BOOST_CHECK(ParseInt32("-2147483648", &n) && n == (-2147483647 - 1)); // (-2147483647 - 1) equals INT_MIN
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
// Invalid values
BOOST_CHECK(!ParseInt32("", &n));
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/txmempool.cpp b/src/txmempool.cpp
index 942a6fcce7..fb58208774 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -19,22 +19,17 @@
#include "version.h"
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
- int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
- CAmount _inChainInputValue,
+ int64_t _nTime, unsigned int _entryHeight,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp):
- tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
- inChainInputValue(_inChainInputValue),
+ tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight),
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp)
{
nTxWeight = GetTransactionWeight(*tx);
- nModSize = tx->CalculateModifiedSize(GetTxSize());
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize();
nModFeesWithDescendants = nFee;
- CAmount nValueIn = tx->GetValueOut()+nFee;
- assert(inChainInputValue <= nValueIn);
feeDelta = 0;
@@ -49,16 +44,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
*this = other;
}
-double
-CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
-{
- double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize;
- double dResult = entryPriority + deltaPriority;
- if (dResult < 0) // This should only happen if it was called with a height below entry height
- dResult = 0;
- return dResult;
-}
-
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
nModFeesWithDescendants += newFeeDelta - feeDelta;
@@ -348,7 +333,7 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
assert(int(nSigOpCostWithAncestors) >= 0);
}
-CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
+CTxMemPool::CTxMemPool() :
nTransactionsUpdated(0)
{
_clear(); //lock free clear
@@ -358,7 +343,7 @@ CTxMemPool::CTxMemPool(const CFeeRate& _minReasonableRelayFee) :
// of transactions in the pool
nCheckFrequency = 0;
- minerPolicyEstimator = new CBlockPolicyEstimator(_minReasonableRelayFee);
+ minerPolicyEstimator = new CBlockPolicyEstimator();
}
CTxMemPool::~CTxMemPool()
@@ -404,11 +389,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
// Update transaction for any feeDelta created by PrioritiseTransaction
// TODO: refactor so that the fee delta is calculated before inserting
// into mapTx.
- std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+ std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos != mapDeltas.end()) {
- const std::pair<double, CAmount> &deltas = pos->second;
- if (deltas.second) {
- mapTx.modify(newit, update_fee_delta(deltas.second));
+ const CAmount &delta = pos->second;
+ if (delta) {
+ mapTx.modify(newit, update_fee_delta(delta));
}
}
@@ -875,16 +860,6 @@ CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) con
LOCK(cs);
return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this);
}
-double CTxMemPool::estimatePriority(int nBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimatePriority(nBlocks);
-}
-double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const
-{
- LOCK(cs);
- return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, *this);
-}
bool
CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
@@ -920,16 +895,15 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
return true;
}
-void CTxMemPool::PrioritiseTransaction(const uint256& hash, double dPriorityDelta, const CAmount& nFeeDelta)
+void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
{
{
LOCK(cs);
- std::pair<double, CAmount> &deltas = mapDeltas[hash];
- deltas.first += dPriorityDelta;
- deltas.second += nFeeDelta;
+ CAmount &delta = mapDeltas[hash];
+ delta += nFeeDelta;
txiter it = mapTx.find(hash);
if (it != mapTx.end()) {
- mapTx.modify(it, update_fee_delta(deltas.second));
+ mapTx.modify(it, update_fee_delta(delta));
// Now update all ancestors' modified fees with descendants
setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
@@ -940,18 +914,17 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, double dPriorityDelt
}
}
}
- LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", hash.ToString(), dPriorityDelta, FormatMoney(nFeeDelta));
+ LogPrintf("PrioritiseTransaction: %s feerate += %s\n", hash.ToString(), FormatMoney(nFeeDelta));
}
-void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const
+void CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const
{
LOCK(cs);
- std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+ std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos == mapDeltas.end())
return;
- const std::pair<double, CAmount> &deltas = pos->second;
- dPriorityDelta += deltas.first;
- nFeeDelta += deltas.second;
+ const CAmount &delta = pos->second;
+ nFeeDelta += delta;
}
void CTxMemPool::ClearPrioritisation(const uint256 hash)
diff --git a/src/txmempool.h b/src/txmempool.h
index 8a8039ded1..f9a9d088d0 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -29,18 +29,6 @@
class CAutoFile;
class CBlockIndex;
-inline double AllowFreeThreshold()
-{
- return COIN * 144 / 250;
-}
-
-inline bool AllowFree(double dPriority)
-{
- // Large (in bytes) low-priority (new, small-coin) transactions
- // need a fee.
- return dPriority > AllowFreeThreshold();
-}
-
/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
@@ -84,12 +72,9 @@ private:
CTransactionRef tx;
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
- size_t nModSize; //!< ... and modified size for priority
size_t nUsageSize; //!< ... and total memory usage
int64_t nTime; //!< Local time when entering the mempool
- double entryPriority; //!< Priority when entering the mempool
unsigned int entryHeight; //!< Chain height when entering the mempool
- CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain
bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
int64_t sigOpCost; //!< Total sigop cost
int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block
@@ -112,19 +97,14 @@ private:
public:
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
- int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
- CAmount _inChainInputValue, bool spendsCoinbase,
+ int64_t _nTime, unsigned int _entryHeight,
+ bool spendsCoinbase,
int64_t nSigOpsCost, LockPoints lp);
CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
- /**
- * Fast calculation of lower bound of current priority as update
- * from entry priority. Only inputs that were originally in-chain will age.
- */
- double GetPriority(unsigned int currentHeight) const;
const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const;
size_t GetTxWeight() const { return nTxWeight; }
@@ -512,11 +492,11 @@ private:
public:
indirectmap<COutPoint, const CTransaction*> mapNextTx;
- std::map<uint256, std::pair<double, CAmount> > mapDeltas;
+ std::map<uint256, CAmount> mapDeltas;
/** Create a new CTxMemPool.
*/
- CTxMemPool(const CFeeRate& _minReasonableRelayFee);
+ CTxMemPool();
~CTxMemPool();
/**
@@ -554,8 +534,8 @@ public:
bool HasNoInputsOf(const CTransaction& tx) const;
/** Affect CreateNewBlock prioritisation of transactions */
- void PrioritiseTransaction(const uint256& hash, double dPriorityDelta, const CAmount& nFeeDelta);
- void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const;
+ void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);
+ void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
void ClearPrioritisation(const uint256 hash);
public:
@@ -647,15 +627,6 @@ public:
/** Estimate fee rate needed to get into the next nBlocks */
CFeeRate estimateFee(int nBlocks) const;
- /** Estimate priority needed to get into the next nBlocks
- * If no answer can be given at nBlocks, return an estimate
- * at the lowest number of blocks where one can be given
- */
- double estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks = NULL) const;
-
- /** Estimate priority needed to get into the next nBlocks */
- double estimatePriority(int nBlocks) const;
-
/** Write/Read estimates to disk */
bool WriteFeeEstimates(CAutoFile& fileout) const;
bool ReadFeeEstimates(CAutoFile& filein);
@@ -719,17 +690,4 @@ public:
bool HaveCoins(const uint256 &txid) const;
};
-// We want to sort transactions by coin age priority
-typedef std::pair<double, CTxMemPool::txiter> TxCoinAgePriority;
-
-struct TxCoinAgePriorityCompare
-{
- bool operator()(const TxCoinAgePriority& a, const TxCoinAgePriority& b)
- {
- if (a.first == b.first)
- return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); //Reverse order to make sort less than
- return a.first < b.first;
- }
-};
-
#endif // BITCOIN_TXMEMPOOL_H
diff --git a/src/util.cpp b/src/util.cpp
index 78c353dfe5..486df772fb 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -97,15 +97,15 @@ namespace boost {
} // namespace boost
-using namespace std;
+
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
CCriticalSection cs_args;
-map<string, string> mapArgs;
-static map<string, vector<string> > _mapMultiArgs;
-const map<string, vector<string> >& mapMultiArgs = _mapMultiArgs;
+std::map<std::string, std::string> mapArgs;
+static std::map<std::string, std::vector<std::string> > _mapMultiArgs;
+const std::map<std::string, std::vector<std::string> >& mapMultiArgs = _mapMultiArgs;
bool fDebug = false;
bool fPrintToConsole = false;
bool fPrintToDebugLog = true;
@@ -191,7 +191,7 @@ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
*/
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
-static list<string> *vMsgsBeforeOpenLog;
+static std::list<std::string>* vMsgsBeforeOpenLog;
static int FileWriteStr(const std::string &str, FILE *fp)
{
@@ -202,7 +202,7 @@ static void DebugPrintInit()
{
assert(mutexDebugLog == NULL);
mutexDebugLog = new boost::mutex();
- vMsgsBeforeOpenLog = new list<string>;
+ vMsgsBeforeOpenLog = new std::list<std::string>;
}
void OpenDebugLog()
@@ -238,22 +238,22 @@ bool LogAcceptCategory(const char* category)
// This helps prevent issues debugging global destructors,
// where mapMultiArgs might be deleted before another
// global destructor calls LogPrint()
- static boost::thread_specific_ptr<set<string> > ptrCategory;
+ static boost::thread_specific_ptr<std::set<std::string> > ptrCategory;
if (ptrCategory.get() == NULL)
{
if (mapMultiArgs.count("-debug")) {
- const vector<string>& categories = mapMultiArgs.at("-debug");
- ptrCategory.reset(new set<string>(categories.begin(), categories.end()));
+ const std::vector<std::string>& categories = mapMultiArgs.at("-debug");
+ ptrCategory.reset(new std::set<std::string>(categories.begin(), categories.end()));
// thread_specific_ptr automatically deletes the set when the thread ends.
} else
- ptrCategory.reset(new set<string>());
+ ptrCategory.reset(new std::set<std::string>());
}
- const set<string>& setCategories = *ptrCategory.get();
+ const std::set<std::string>& setCategories = *ptrCategory;
// if not debugging everything and not debugging specific category, LogPrint does nothing.
- if (setCategories.count(string("")) == 0 &&
- setCategories.count(string("1")) == 0 &&
- setCategories.count(string(category)) == 0)
+ if (setCategories.count(std::string("")) == 0 &&
+ setCategories.count(std::string("1")) == 0 &&
+ setCategories.count(std::string(category)) == 0)
return false;
}
return true;
@@ -266,7 +266,7 @@ bool LogAcceptCategory(const char* category)
*/
static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
{
- string strStamped;
+ std::string strStamped;
if (!fLogTimestamps)
return str;
@@ -293,7 +293,7 @@ int LogPrintStr(const std::string &str)
int ret = 0; // Returns total number of characters written
static std::atomic_bool fStartedNewLine(true);
- string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
+ std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
if (fPrintToConsole)
{
@@ -561,14 +561,14 @@ void ReadConfigFile(const std::string& confPath)
{
LOCK(cs_args);
- set<string> setOptions;
+ std::set<std::string> setOptions;
setOptions.insert("*");
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
- string strKey = string("-") + it->string_key;
- string strValue = it->value[0];
+ std::string strKey = std::string("-") + it->string_key;
+ std::string strValue = it->value[0];
InterpretNegativeSetting(strKey, strValue);
if (mapArgs.count(strKey) == 0)
mapArgs[strKey] = strValue;
@@ -839,4 +839,4 @@ std::string CopyrightHolders(const std::string& strPrefix)
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
-} \ No newline at end of file
+}
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/utilmoneystr.cpp b/src/utilmoneystr.cpp
index bebe56130d..6e6e33184e 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -9,8 +9,6 @@
#include "tinyformat.h"
#include "utilstrencodings.h"
-using namespace std;
-
std::string FormatMoney(const CAmount& n)
{
// Note: not using straight sprintf here because we do NOT want
@@ -18,7 +16,7 @@ std::string FormatMoney(const CAmount& n)
int64_t n_abs = (n > 0 ? n : -n);
int64_t quotient = n_abs/COIN;
int64_t remainder = n_abs%COIN;
- string str = strprintf("%d.%08d", quotient, remainder);
+ std::string str = strprintf("%d.%08d", quotient, remainder);
// Right-trim excess zeros before the decimal point:
int nTrim = 0;
@@ -33,14 +31,14 @@ std::string FormatMoney(const CAmount& n)
}
-bool ParseMoney(const string& str, CAmount& nRet)
+bool ParseMoney(const std::string& str, CAmount& nRet)
{
return ParseMoney(str.c_str(), nRet);
}
bool ParseMoney(const char* pszIn, CAmount& nRet)
{
- string strWhole;
+ std::string strWhole;
int64_t nUnits = 0;
const char* p = pszIn;
while (isspace(*p))
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 29ae57940f..74bf66fbf6 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -12,20 +12,18 @@
#include <errno.h>
#include <limits>
-using namespace std;
+static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-
-static const string SAFE_CHARS[] =
+static const std::string SAFE_CHARS[] =
{
CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
};
-string SanitizeString(const string& str, int rule)
+std::string SanitizeString(const std::string& str, int rule)
{
- string strResult;
+ std::string strResult;
for (std::string::size_type i = 0; i < str.size(); i++)
{
if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
@@ -57,7 +55,7 @@ signed char HexDigit(char c)
return p_util_hexdigit[(unsigned char)c];
}
-bool IsHex(const string& str)
+bool IsHex(const std::string& str)
{
for(std::string::const_iterator it(str.begin()); it != str.end(); ++it)
{
@@ -67,10 +65,10 @@ bool IsHex(const string& str)
return (str.size() > 0) && (str.size()%2 == 0);
}
-vector<unsigned char> ParseHex(const char* psz)
+std::vector<unsigned char> ParseHex(const char* psz)
{
// convert hex dump to vector
- vector<unsigned char> vch;
+ std::vector<unsigned char> vch;
while (true)
{
while (isspace(*psz))
@@ -88,16 +86,16 @@ vector<unsigned char> ParseHex(const char* psz)
return vch;
}
-vector<unsigned char> ParseHex(const string& str)
+std::vector<unsigned char> ParseHex(const std::string& str)
{
return ParseHex(str.c_str());
}
-string EncodeBase64(const unsigned char* pch, size_t len)
+std::string EncodeBase64(const unsigned char* pch, size_t len)
{
static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- string strRet="";
+ std::string strRet = "";
strRet.reserve((len+2)/3*4);
int mode=0, left=0;
@@ -139,12 +137,12 @@ string EncodeBase64(const unsigned char* pch, size_t len)
return strRet;
}
-string EncodeBase64(const string& str)
+std::string EncodeBase64(const std::string& str)
{
return EncodeBase64((const unsigned char*)str.c_str(), str.size());
}
-vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
+std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
{
static const int decode64_table[256] =
{
@@ -166,7 +164,7 @@ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
if (pfInvalid)
*pfInvalid = false;
- vector<unsigned char> vchRet;
+ std::vector<unsigned char> vchRet;
vchRet.reserve(strlen(p)*3/4);
int mode = 0;
@@ -227,17 +225,17 @@ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
return vchRet;
}
-string DecodeBase64(const string& str)
+std::string DecodeBase64(const std::string& str)
{
- vector<unsigned char> vchRet = DecodeBase64(str.c_str());
- return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
+ std::vector<unsigned char> vchRet = DecodeBase64(str.c_str());
+ return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());
}
-string EncodeBase32(const unsigned char* pch, size_t len)
+std::string EncodeBase32(const unsigned char* pch, size_t len)
{
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
- string strRet="";
+ std::string strRet="";
strRet.reserve((len+4)/5*8);
int mode=0, left=0;
@@ -292,12 +290,12 @@ string EncodeBase32(const unsigned char* pch, size_t len)
return strRet;
}
-string EncodeBase32(const string& str)
+std::string EncodeBase32(const std::string& str)
{
return EncodeBase32((const unsigned char*)str.c_str(), str.size());
}
-vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
+std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
{
static const int decode32_table[256] =
{
@@ -319,7 +317,7 @@ vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
if (pfInvalid)
*pfInvalid = false;
- vector<unsigned char> vchRet;
+ std::vector<unsigned char> vchRet;
vchRet.reserve((strlen(p))*5/8);
int mode = 0;
@@ -414,10 +412,10 @@ vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
return vchRet;
}
-string DecodeBase32(const string& str)
+std::string DecodeBase32(const std::string& str)
{
- vector<unsigned char> vchRet = DecodeBase32(str.c_str());
- return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
+ std::vector<unsigned char> vchRet = DecodeBase32(str.c_str());
+ return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size());
}
static bool ParsePrechecks(const std::string& str)
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index c7b3e4f168..a9936a645a 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -12,8 +12,6 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
static int64_t nMockTime = 0; //!< For unit testing
int64_t GetTime()
diff --git a/src/validation.cpp b/src/validation.cpp
index e84b1a7281..be82026b3c 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -81,7 +81,7 @@ uint256 hashAssumeValid;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
-CTxMemPool mempool(::minRelayTxFee);
+CTxMemPool mempool;
static void CheckBlockIndex(const Consensus::Params& consensusParams);
@@ -720,11 +720,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CAmount nFees = nValueIn-nValueOut;
// nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees;
- double nPriorityDummy = 0;
- pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
-
- CAmount inChainInputValue;
- double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
+ pool.ApplyDelta(hash, nModifiedFees);
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
@@ -737,8 +733,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
}
- CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(),
- inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp);
+ CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(),
+ fSpendsCoinbase, nSigOpsCost, lp);
unsigned int nSize = entry.GetTxSize();
// Check that the transaction doesn't have an excessive number of
@@ -753,32 +749,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
- } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
- // Require that free transactions have sufficient priority to be mined in the next block.
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
- // Continuously rate-limit free (really, very-low-fee) transactions
- // This mitigates 'penny-flooding' -- sending thousands of free transactions just to
- // be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
- {
- static CCriticalSection csFreeLimiter;
- static double dFreeCount;
- static int64_t nLastTime;
- int64_t nNow = GetTime();
-
- LOCK(csFreeLimiter);
-
- // Use an exponentially decaying ~10-minute window:
- dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
- nLastTime = nNow;
- // -limitfreerelay unit is thousand-bytes-per-minute
- // At default rate it would take over a month to fill 1GB
- if (dFreeCount + nSize >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000)
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
- LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
- dFreeCount += nSize;
+ // No transactions are allowed below minRelayTxFee except from disconnected blocks
+ if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
}
if (nAbsurdFee && nFees > nAbsurdFee)
@@ -1739,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
@@ -2973,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");
@@ -2983,7 +2962,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
// Check timestamp
- if (block.GetBlockTime() > nAdjustedTime + 2 * 60 * 60)
+ if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
@@ -4205,7 +4184,6 @@ bool LoadMempool(void)
}
uint64_t num;
file >> num;
- double prioritydummy = 0;
while (num--) {
CTransactionRef tx;
int64_t nTime;
@@ -4216,7 +4194,7 @@ bool LoadMempool(void)
CAmount amountdelta = nFeeDelta;
if (amountdelta) {
- mempool.PrioritiseTransaction(tx->GetHash(), prioritydummy, amountdelta);
+ mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
CValidationState state;
if (nTime + nExpiryTimeout > nNow) {
@@ -4237,7 +4215,7 @@ bool LoadMempool(void)
file >> mapDeltas;
for (const auto& i : mapDeltas) {
- mempool.PrioritiseTransaction(i.first, prioritydummy, i.second);
+ mempool.PrioritiseTransaction(i.first, i.second);
}
} catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
@@ -4258,7 +4236,7 @@ void DumpMempool(void)
{
LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) {
- mapDeltas[i.first] = i.second.second;
+ mapDeltas[i.first] = i.second;
}
vinfo = mempool.infoAll();
}
diff --git a/src/validation.h b/src/validation.h
index 9c606f2419..43f0dbae34 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -122,8 +122,6 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
-static const unsigned int DEFAULT_LIMITFREERELAY = 0;
-static const bool DEFAULT_RELAYPRIORITY = true;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
/** Maximum age of our tip in seconds for us to be considered current for fee estimation */
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;
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/coincontrol.h b/src/wallet/coincontrol.h
index eaf4ff8062..4e93e929be 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -6,6 +6,7 @@
#define BITCOIN_WALLET_COINCONTROL_H
#include "primitives/transaction.h"
+#include "wallet/wallet.h"
/** Coin Control Features. */
class CCoinControl
@@ -24,6 +25,8 @@ public:
CFeeRate nFeeRate;
//! Override the default confirmation target, 0 = use default
int nConfirmTarget;
+ //! Signal BIP-125 replace by fee.
+ bool signalRbf;
CCoinControl()
{
@@ -40,6 +43,7 @@ public:
nFeeRate = CFeeRate(0);
fOverrideFeeRate = false;
nConfirmTarget = 0;
+ signalRbf = fWalletRbf;
}
bool HasSelected() const
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 7d1b429b30..80c42bd91b 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -18,12 +18,10 @@
#endif
#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
#include <boost/thread.hpp>
#include <boost/version.hpp>
-using namespace std;
-
-
//
// CDB
//
@@ -116,7 +114,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
void CDBEnv::MakeMock()
{
if (fDbEnvInit)
- throw runtime_error("CDBEnv::MakeMock: Already initialized");
+ throw std::runtime_error("CDBEnv::MakeMock: Already initialized");
boost::this_thread::interruption_point();
@@ -139,13 +137,13 @@ void CDBEnv::MakeMock()
DB_PRIVATE,
S_IRUSR | S_IWUSR);
if (ret > 0)
- throw runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret));
+ throw std::runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret));
fDbEnvInit = true;
fMockDb = true;
}
-CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile))
+CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(const std::string& strFile))
{
LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0);
@@ -158,10 +156,134 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu
return RECOVER_FAIL;
// Try to recover:
- bool fRecovered = (*recoverFunc)(*this, strFile);
+ bool fRecovered = (*recoverFunc)(strFile);
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
}
+bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue))
+{
+ // Recovery procedure:
+ // move wallet file to wallet.timestamp.bak
+ // Call Salvage with fAggressive=true to
+ // get as much data as possible.
+ // Rewrite salvaged data to fresh wallet file
+ // Set -rescan so any missing transactions will be
+ // found.
+ int64_t now = GetTime();
+ std::string newFilename = strprintf("wallet.%d.bak", now);
+
+ int result = bitdb.dbenv->dbrename(NULL, filename.c_str(), NULL,
+ newFilename.c_str(), DB_AUTO_COMMIT);
+ if (result == 0)
+ LogPrintf("Renamed %s to %s\n", filename, newFilename);
+ else
+ {
+ LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
+ return false;
+ }
+
+ std::vector<CDBEnv::KeyValPair> salvagedData;
+ bool fSuccess = bitdb.Salvage(newFilename, true, salvagedData);
+ if (salvagedData.empty())
+ {
+ LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
+ return false;
+ }
+ LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
+
+ std::unique_ptr<Db> pdbCopy(new Db(bitdb.dbenv, 0));
+ int ret = pdbCopy->open(NULL, // Txn pointer
+ filename.c_str(), // Filename
+ "main", // Logical db name
+ DB_BTREE, // Database type
+ DB_CREATE, // Flags
+ 0);
+ if (ret > 0)
+ {
+ LogPrintf("Cannot create database file %s\n", filename);
+ return false;
+ }
+
+ DbTxn* ptxn = bitdb.TxnBegin();
+ BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
+ {
+ if (recoverKVcallback)
+ {
+ CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
+ CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
+ std::string strType, strErr;
+ if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue))
+ continue;
+ }
+ Dbt datKey(&row.first[0], row.first.size());
+ Dbt datValue(&row.second[0], row.second.size());
+ int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
+ if (ret2 > 0)
+ fSuccess = false;
+ }
+ ptxn->commit(0);
+ pdbCopy->close(0);
+
+ return fSuccess;
+}
+
+bool CDB::VerifyEnvironment(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& errorStr)
+{
+ LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
+ LogPrintf("Using wallet %s\n", walletFile);
+
+ // Wallet file must be a plain filename without a directory
+ if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile))
+ {
+ errorStr = strprintf(_("Wallet %s resides outside data directory %s"), walletFile, dataDir.string());
+ return false;
+ }
+
+ if (!bitdb.Open(dataDir))
+ {
+ // try moving the database env out of the way
+ boost::filesystem::path pathDatabase = dataDir / "database";
+ boost::filesystem::path pathDatabaseBak = dataDir / strprintf("database.%d.bak", GetTime());
+ try {
+ boost::filesystem::rename(pathDatabase, pathDatabaseBak);
+ LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
+ } catch (const boost::filesystem::filesystem_error&) {
+ // failure is ok (well, not really, but it's not worse than what we started with)
+ }
+
+ // try again
+ if (!bitdb.Open(dataDir)) {
+ // if it still fails, it probably means we can't even create the database env
+ errorStr = strprintf(_("Error initializing wallet database environment %s!"), GetDataDir());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CDB::VerifyDatabaseFile(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& warningStr, std::string& errorStr, bool (*recoverFunc)(const std::string& strFile))
+{
+ if (boost::filesystem::exists(dataDir / walletFile))
+ {
+ CDBEnv::VerifyResult r = bitdb.Verify(walletFile, recoverFunc);
+ if (r == CDBEnv::RECOVER_OK)
+ {
+ warningStr = strprintf(_("Warning: Wallet file corrupt, data salvaged!"
+ " Original %s saved as %s in %s; if"
+ " your balance or transactions are incorrect you should"
+ " restore from a backup."),
+ walletFile, "wallet.{timestamp}.bak", dataDir);
+ }
+ if (r == CDBEnv::RECOVER_FAIL)
+ {
+ errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile);
+ return false;
+ }
+ }
+ // also return true if files does not exists
+ return true;
+}
+
/* End of headers, beginning of key/value data */
static const char *HEADER_END = "HEADER=END";
/* End of key/value data */
@@ -176,7 +298,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
if (fAggressive)
flags |= DB_AGGRESSIVE;
- stringstream strDump;
+ std::stringstream strDump;
Db db(dbenv, 0);
int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
@@ -200,7 +322,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
// ... repeated
// DATA=END
- string strLine;
+ std::string strLine;
while (!strDump.eof() && strLine != HEADER_END)
getline(strDump, strLine); // Skip past header
@@ -253,7 +375,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
{
LOCK(bitdb.cs_db);
if (!bitdb.Open(GetDataDir()))
- throw runtime_error("CDB: Failed to open database environment.");
+ throw std::runtime_error("CDB: Failed to open database environment.");
strFile = strFilename;
++bitdb.mapFileUseCount[strFile];
@@ -266,7 +388,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
DbMpoolFile* mpf = pdb->get_mpf();
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
if (ret != 0)
- throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
+ throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
}
ret = pdb->open(NULL, // Txn pointer
@@ -281,10 +403,10 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose
pdb = NULL;
--bitdb.mapFileUseCount[strFile];
strFile = "";
- throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
+ throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
}
- if (fCreate && !Exists(string("version"))) {
+ if (fCreate && !Exists(std::string("version"))) {
bool fTmp = fReadOnly;
fReadOnly = false;
WriteVersion(CLIENT_VERSION);
@@ -327,7 +449,7 @@ void CDB::Close()
}
}
-void CDBEnv::CloseDb(const string& strFile)
+void CDBEnv::CloseDb(const std::string& strFile)
{
{
LOCK(cs_db);
@@ -341,7 +463,7 @@ void CDBEnv::CloseDb(const string& strFile)
}
}
-bool CDBEnv::RemoveDb(const string& strFile)
+bool CDBEnv::RemoveDb(const std::string& strFile)
{
this->CloseDb(strFile);
@@ -350,7 +472,7 @@ bool CDBEnv::RemoveDb(const string& strFile)
return (rc == 0);
}
-bool CDB::Rewrite(const string& strFile, const char* pszSkip)
+bool CDB::Rewrite(const std::string& strFile, const char* pszSkip)
{
while (true) {
{
@@ -363,7 +485,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
bool fSuccess = true;
LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile);
- string strFileRes = strFile + ".rewrite";
+ std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
CDB db(strFile.c_str(), "r");
Db* pdbCopy = new Db(bitdb.dbenv, 0);
@@ -443,9 +565,9 @@ void CDBEnv::Flush(bool fShutdown)
return;
{
LOCK(cs_db);
- map<string, int>::iterator mi = mapFileUseCount.begin();
+ std::map<std::string, int>::iterator mi = mapFileUseCount.begin();
while (mi != mapFileUseCount.end()) {
- string strFile = (*mi).first;
+ std::string strFile = (*mi).first;
int nRefCount = (*mi).second;
LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
if (nRefCount == 0) {
@@ -473,3 +595,41 @@ void CDBEnv::Flush(bool fShutdown)
}
}
}
+
+bool CDB::PeriodicFlush(std::string strFile)
+{
+ bool ret = false;
+ TRY_LOCK(bitdb.cs_db,lockDb);
+ if (lockDb)
+ {
+ // Don't do this if any databases are in use
+ int nRefCount = 0;
+ std::map<std::string, int>::iterator mi = bitdb.mapFileUseCount.begin();
+ while (mi != bitdb.mapFileUseCount.end())
+ {
+ nRefCount += (*mi).second;
+ mi++;
+ }
+
+ if (nRefCount == 0)
+ {
+ boost::this_thread::interruption_point();
+ std::map<std::string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
+ if (mi != bitdb.mapFileUseCount.end())
+ {
+ LogPrint("db", "Flushing %s\n", strFile);
+ int64_t nStart = GetTimeMillis();
+
+ // Flush wallet file so it's self contained
+ bitdb.CloseDb(strFile);
+ bitdb.CheckpointLSN(strFile);
+
+ bitdb.mapFileUseCount.erase(mi++);
+ LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
+ ret = true;
+ }
+ }
+ }
+
+ return ret;
+}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index b4ce044e7f..19c54e314c 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -56,7 +56,7 @@ public:
enum VerifyResult { VERIFY_OK,
RECOVER_OK,
RECOVER_FAIL };
- VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile));
+ VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(const std::string& strFile));
/**
* Salvage data from a file that Verify says is bad.
* fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation).
@@ -104,6 +104,15 @@ protected:
public:
void Flush();
void Close();
+ static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
+
+ /* flush the wallet passively (TRY_LOCK)
+ ideal to be called periodically */
+ static bool PeriodicFlush(std::string strFile);
+ /* verifies the database environment */
+ static bool VerifyEnvironment(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& errorStr);
+ /* verifies the database file */
+ static bool VerifyDatabaseFile(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& warningStr, std::string& errorStr, bool (*recoverFunc)(const std::string& strFile));
private:
CDB(const CDB&);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 218a8aefb4..7ff9e7ae58 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -29,8 +29,6 @@
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
-using namespace std;
-
std::string static EncodeDumpTime(int64_t nTime) {
return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
}
@@ -82,7 +80,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
"\nArguments:\n"
@@ -106,8 +104,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- string strSecret = request.params[0].get_str();
- string strLabel = "";
+ std::string strSecret = request.params[0].get_str();
+ std::string strLabel = "";
if (request.params.size() > 1)
strLabel = request.params[1].get_str();
@@ -156,8 +154,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
return NullUniValue;
}
-void ImportAddress(CWallet*, const CBitcoinAddress& address, const string& strLabel);
-void ImportScript(CWallet * const pwallet, const CScript& script, const string& strLabel, bool isRedeemScript)
+void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
+void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
{
if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -182,7 +180,7 @@ void ImportScript(CWallet * const pwallet, const CScript& script, const string&
}
}
-void ImportAddress(CWallet * const pwallet, const CBitcoinAddress& address, const string& strLabel)
+void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel)
{
CScript script = GetScriptForDestination(address.Get());
ImportScript(pwallet, script, strLabel, false);
@@ -199,7 +197,7 @@ UniValue importaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"importaddress \"address\" ( \"label\" rescan p2sh )\n"
"\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n"
"\nArguments:\n"
@@ -221,7 +219,7 @@ UniValue importaddress(const JSONRPCRequest& request)
);
- string strLabel = "";
+ std::string strLabel = "";
if (request.params.size() > 1)
strLabel = request.params[1].get_str();
@@ -269,7 +267,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"importprunedfunds\n"
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
"\nArguments:\n"
@@ -288,8 +286,8 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
ssMB >> merkleBlock;
//Search partial merkle tree in proof for our transaction and index in valid block
- vector<uint256> vMatch;
- vector<unsigned int> vIndex;
+ std::vector<uint256> vMatch;
+ std::vector<unsigned int> vIndex;
unsigned int txnIndex = 0;
if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) {
@@ -298,7 +296,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()]))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
- vector<uint256>::const_iterator it;
+ std::vector<uint256>::const_iterator it;
if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
}
@@ -330,7 +328,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"removeprunedfunds \"txid\"\n"
"\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n"
"\nArguments:\n"
@@ -345,16 +343,16 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
uint256 hash;
hash.SetHex(request.params[0].get_str());
- vector<uint256> vHash;
+ std::vector<uint256> vHash;
vHash.push_back(hash);
- vector<uint256> vHashOut;
+ std::vector<uint256> vHashOut;
if (pwallet->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction.");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction.");
}
if(vHashOut.empty()) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet.");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
}
return NullUniValue;
@@ -368,7 +366,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n"
"\nArguments:\n"
@@ -386,7 +384,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
);
- string strLabel = "";
+ std::string strLabel = "";
if (request.params.size() > 1)
strLabel = request.params[1].get_str();
@@ -428,7 +426,7 @@ UniValue importwallet(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"importwallet \"filename\"\n"
"\nImports keys from a wallet dump file (see dumpwallet).\n"
"\nArguments:\n"
@@ -449,7 +447,7 @@ UniValue importwallet(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- ifstream file;
+ std::ifstream file;
file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
@@ -513,7 +511,7 @@ UniValue importwallet(const JSONRPCRequest& request)
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
CBlockIndex *pindex = chainActive.Tip();
- while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
+ while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - TIMESTAMP_WINDOW)
pindex = pindex->pprev;
pwallet->UpdateTimeFirstKey(nTimeBegin);
@@ -536,7 +534,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"dumpprivkey \"address\"\n"
"\nReveals the private key corresponding to 'address'.\n"
"Then the importprivkey can be used with this output\n"
@@ -554,7 +552,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- string strAddress = request.params[0].get_str();
+ std::string strAddress = request.params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -577,7 +575,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"dumpwallet \"filename\"\n"
"\nDumps all wallet keys in a human-readable format.\n"
"\nArguments:\n"
@@ -591,7 +589,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- ofstream file;
+ std::ofstream file;
file.open(request.params[0].get_str().c_str());
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
@@ -675,16 +673,16 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// Optional fields.
- const string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
+ const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false;
const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
- const string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
+ const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
bool isP2SH = strRedeemScript.length() > 0;
- const string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
+ const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
// Parse the output.
CScript script;
@@ -774,7 +772,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
// Import private keys.
if (keys.size()) {
for (size_t i = 0; i < keys.size(); i++) {
- const string& privkey = keys[i].get_str();
+ const std::string& privkey = keys[i].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(privkey);
@@ -814,7 +812,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
} else {
// Import public keys.
if (pubKeys.size() && keys.size() == 0) {
- const string& strPubKey = pubKeys[0].get_str();
+ const std::string& strPubKey = pubKeys[0].get_str();
if (!IsHex(strPubKey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
@@ -882,7 +880,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
// Import private keys.
if (keys.size()) {
- const string& strPrivkey = keys[0].get_str();
+ const std::string& strPrivkey = keys[0].get_str();
// Checks.
CBitcoinSecret vchSecret;
@@ -1001,7 +999,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
// clang-format off
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"importmulti \"requests\" \"options\"\n\n"
"Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n"
"Arguments:\n"
@@ -1095,7 +1093,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
if (fRescan && fRunScan && requests.size()) {
- CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - 7200, 0)) : chainActive.Genesis();
+ CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis();
CBlockIndex* scannedRange = nullptr;
if (pindex) {
scannedRange = pwallet->ScanForWalletTransactions(pindex, true);
@@ -1112,7 +1110,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
// range, or if the import result already has an error set, let
// the result stand unmodified. Otherwise replace the result
// with an error message.
- if (GetImportTimestamp(request, now) - 7200 >= scannedRange->GetBlockTimeMax() || results.at(i).exists("error")) {
+ if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW >= scannedRange->GetBlockTimeMax() || results.at(i).exists("error")) {
response.push_back(results.at(i));
} else {
UniValue result = UniValue(UniValue::VOBJ);
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 5ef93ac532..84e7eb60d7 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -27,8 +27,6 @@
#include <univalue.h>
-using namespace std;
-
CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
{
return pwalletMain;
@@ -94,13 +92,13 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
}
entry.push_back(Pair("bip125-replaceable", rbfStatus));
- BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
+ BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wtx.mapValue)
entry.push_back(Pair(item.first, item.second));
}
-string AccountFromValue(const UniValue& value)
+std::string AccountFromValue(const UniValue& value)
{
- string strAccount = value.get_str();
+ std::string strAccount = value.get_str();
if (strAccount == "*")
throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
return strAccount;
@@ -114,7 +112,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getnewaddress ( \"account\" )\n"
"\nReturns a new Bitcoin address for receiving payments.\n"
"If 'account' is specified (DEPRECATED), it is added to the address book \n"
@@ -131,7 +129,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
// Parse the account first so we don't generate a key if there's an error
- string strAccount;
+ std::string strAccount;
if (request.params.size() > 0)
strAccount = AccountFromValue(request.params[0]);
@@ -152,7 +150,7 @@ UniValue getnewaddress(const JSONRPCRequest& request)
}
-CBitcoinAddress GetAccountAddress(CWallet * const pwallet, string strAccount, bool bForceNew=false)
+CBitcoinAddress GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
{
CPubKey pubKey;
if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) {
@@ -170,7 +168,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaccountaddress \"account\"\n"
"\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
"\nArguments:\n"
@@ -187,7 +185,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
// Parse the account first so we don't generate a key if there's an error
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
UniValue ret(UniValue::VSTR);
@@ -204,7 +202,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"getrawchangeaddress\n"
"\nReturns a new Bitcoin address, for receiving change.\n"
"This is for use with raw transactions, NOT normal use.\n"
@@ -242,7 +240,7 @@ UniValue setaccount(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"setaccount \"address\" \"account\"\n"
"\nDEPRECATED. Sets the account associated with the given address.\n"
"\nArguments:\n"
@@ -259,7 +257,7 @@ UniValue setaccount(const JSONRPCRequest& request)
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- string strAccount;
+ std::string strAccount;
if (request.params.size() > 1)
strAccount = AccountFromValue(request.params[1]);
@@ -267,7 +265,7 @@ UniValue setaccount(const JSONRPCRequest& request)
if (IsMine(*pwallet, address.Get())) {
// Detect when changing the account of an address that is the 'unused current key' of another account:
if (pwallet->mapAddressBook.count(address.Get())) {
- string strOldAccount = pwallet->mapAddressBook[address.Get()].name;
+ std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name;
if (address == GetAccountAddress(pwallet, strOldAccount)) {
GetAccountAddress(pwallet, strOldAccount, true);
}
@@ -289,7 +287,7 @@ UniValue getaccount(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaccount \"address\"\n"
"\nDEPRECATED. Returns the account associated with the given address.\n"
"\nArguments:\n"
@@ -307,8 +305,8 @@ UniValue getaccount(const JSONRPCRequest& request)
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- string strAccount;
- map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get());
+ std::string strAccount;
+ std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get());
if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
strAccount = (*mi).second.name;
}
@@ -324,7 +322,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"getaddressesbyaccount \"account\"\n"
"\nDEPRECATED. Returns the list of addresses for the given account.\n"
"\nArguments:\n"
@@ -341,13 +339,13 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
const CBitcoinAddress& address = item.first;
- const string& strName = item.second.name;
+ const std::string& strName = item.second.name;
if (strName == strAccount)
ret.push_back(address.ToString());
}
@@ -376,7 +374,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
CReserveKey reservekey(pwallet);
CAmount nFeeRequired;
std::string strError;
- vector<CRecipient> vecSend;
+ std::vector<CRecipient> vecSend;
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@@ -400,7 +398,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
- throw runtime_error(
+ throw std::runtime_error(
"sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n"
"\nSend an amount to a given address.\n"
+ HelpRequiringPassphrase(pwallet) +
@@ -460,7 +458,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
}
if (request.fHelp)
- throw runtime_error(
+ throw std::runtime_error(
"listaddressgroupings\n"
"\nLists groups of addresses which have had their common ownership\n"
"made public by common use as inputs or as the resulting change\n"
@@ -485,8 +483,8 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
- map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
- for (set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
+ std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
+ for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
BOOST_FOREACH(CTxDestination address, grouping)
{
@@ -513,7 +511,7 @@ UniValue signmessage(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 2)
- throw runtime_error(
+ throw std::runtime_error(
"signmessage \"address\" \"message\"\n"
"\nSign a message with the private key of an address"
+ HelpRequiringPassphrase(pwallet) + "\n"
@@ -537,8 +535,8 @@ UniValue signmessage(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- string strAddress = request.params[0].get_str();
- string strMessage = request.params[1].get_str();
+ std::string strAddress = request.params[0].get_str();
+ std::string strMessage = request.params[1].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
@@ -557,7 +555,7 @@ UniValue signmessage(const JSONRPCRequest& request)
ss << strMessageMagic;
ss << strMessage;
- vector<unsigned char> vchSig;
+ std::vector<unsigned char> vchSig;
if (!key.SignCompact(ss.GetHash(), vchSig))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
@@ -572,7 +570,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getreceivedbyaddress \"address\" ( minconf )\n"
"\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n"
"\nArguments:\n"
@@ -632,7 +630,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"getreceivedbyaccount \"account\" ( minconf )\n"
"\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
"\nArguments:\n"
@@ -659,8 +657,8 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
nMinDepth = request.params[1].get_int();
// Get the set of pub keys assigned to account
- string strAccount = AccountFromValue(request.params[0]);
- set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount);
+ std::string strAccount = AccountFromValue(request.params[0]);
+ std::set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount);
// Tally
CAmount nAmount = 0;
@@ -691,7 +689,7 @@ UniValue getbalance(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"getbalance ( \"account\" minconf include_watchonly )\n"
"\nIf account is not specified, returns the server's total available balance.\n"
"If account is specified (DEPRECATED), returns the balance in the account.\n"
@@ -750,9 +748,9 @@ UniValue getbalance(const JSONRPCRequest& request)
continue;
CAmount allFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
+ std::string strSentAccount;
+ std::list<COutputEntry> listReceived;
+ std::list<COutputEntry> listSent;
wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (wtx.GetDepthInMainChain() >= nMinDepth)
{
@@ -766,7 +764,7 @@ UniValue getbalance(const JSONRPCRequest& request)
return ValueFromAmount(nBalance);
}
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter);
@@ -781,7 +779,7 @@ UniValue getunconfirmedbalance(const JSONRPCRequest &request)
}
if (request.fHelp || request.params.size() > 0)
- throw runtime_error(
+ throw std::runtime_error(
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
@@ -799,7 +797,7 @@ UniValue movecmd(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 3 || request.params.size() > 5)
- throw runtime_error(
+ throw std::runtime_error(
"move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
"\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
"\nArguments:\n"
@@ -821,15 +819,15 @@ UniValue movecmd(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- string strFrom = AccountFromValue(request.params[0]);
- string strTo = AccountFromValue(request.params[1]);
+ std::string strFrom = AccountFromValue(request.params[0]);
+ std::string strTo = AccountFromValue(request.params[1]);
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
if (request.params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)request.params[3].get_int();
- string strComment;
+ std::string strComment;
if (request.params.size() > 4)
strComment = request.params[4].get_str();
@@ -849,7 +847,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)
- throw runtime_error(
+ throw std::runtime_error(
"sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n"
"\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address."
+ HelpRequiringPassphrase(pwallet) + "\n"
@@ -879,7 +877,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -918,7 +916,7 @@ UniValue sendmany(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
- throw runtime_error(
+ throw std::runtime_error(
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
+ HelpRequiringPassphrase(pwallet) + "\n"
@@ -959,7 +957,7 @@ UniValue sendmany(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
- string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = AccountFromValue(request.params[0]);
UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
if (request.params.size() > 2)
@@ -974,19 +972,19 @@ UniValue sendmany(const JSONRPCRequest& request)
if (request.params.size() > 4)
subtractFeeFromAmount = request.params[4].get_array();
- set<CBitcoinAddress> setAddress;
- vector<CRecipient> vecSend;
+ std::set<CBitcoinAddress> setAddress;
+ std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
- vector<string> keys = sendTo.getKeys();
- BOOST_FOREACH(const string& name_, keys)
+ std::vector<std::string> keys = sendTo.getKeys();
+ BOOST_FOREACH(const std::string& name_, keys)
{
CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
@@ -1017,7 +1015,7 @@ UniValue sendmany(const JSONRPCRequest& request)
CReserveKey keyChange(pwallet);
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
- string strFailReason;
+ std::string strFailReason;
bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
@@ -1042,7 +1040,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
{
- string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
+ std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
"\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n"
@@ -1065,12 +1063,12 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
"\nAs json rpc call\n"
+ HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount;
+ std::string strAccount;
if (request.params.size() > 2)
strAccount = AccountFromValue(request.params[2]);
@@ -1140,7 +1138,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
{
- string msg = "addwitnessaddress \"address\"\n"
+ std::string msg = "addwitnessaddress \"address\"\n"
"\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
"It returns the witness script.\n"
@@ -1151,7 +1149,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
"\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
"}\n"
;
- throw runtime_error(msg);
+ throw std::runtime_error(msg);
}
{
@@ -1181,7 +1179,7 @@ struct tallyitem
{
CAmount nAmount;
int nConf;
- vector<uint256> txids;
+ std::vector<uint256> txids;
bool fIsWatchonly;
tallyitem()
{
@@ -1209,7 +1207,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
filter = filter | ISMINE_WATCH_ONLY;
// Tally
- map<CBitcoinAddress, tallyitem> mapTally;
+ std::map<CBitcoinAddress, tallyitem> mapTally;
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
@@ -1232,7 +1230,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
tallyitem& item = mapTally[address];
item.nAmount += txout.nValue;
- item.nConf = min(item.nConf, nDepth);
+ item.nConf = std::min(item.nConf, nDepth);
item.txids.push_back(wtx.GetHash());
if (mine & ISMINE_WATCH_ONLY)
item.fIsWatchonly = true;
@@ -1241,11 +1239,11 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
// Reply
UniValue ret(UniValue::VARR);
- map<string, tallyitem> mapAccountTally;
+ std::map<std::string, tallyitem> mapAccountTally;
for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
const CBitcoinAddress& address = item.first;
- const string& strAccount = item.second.name;
- map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
+ const std::string& strAccount = item.second.name;
+ std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@@ -1263,7 +1261,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
{
tallyitem& _item = mapAccountTally[strAccount];
_item.nAmount += nAmount;
- _item.nConf = min(_item.nConf, nConf);
+ _item.nConf = std::min(_item.nConf, nConf);
_item.fIsWatchonly = fIsWatchonly;
}
else
@@ -1292,7 +1290,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
if (fByAccounts)
{
- for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
+ for (std::map<std::string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it)
{
CAmount nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
@@ -1317,7 +1315,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"listreceivedbyaddress ( minconf include_empty include_watchonly)\n"
"\nList balances by receiving address.\n"
"\nArguments:\n"
@@ -1361,7 +1359,7 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 3)
- throw runtime_error(
+ throw std::runtime_error(
"listreceivedbyaccount ( minconf include_empty include_watchonly)\n"
"\nDEPRECATED. List balances by account.\n"
"\nArguments:\n"
@@ -1399,16 +1397,16 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
entry.push_back(Pair("address", addr.ToString()));
}
-void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
+void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
+ std::string strSentAccount;
+ std::list<COutputEntry> listReceived;
+ std::list<COutputEntry> listSent;
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter);
- bool fAllAccounts = (strAccount == string("*"));
+ bool fAllAccounts = (strAccount == std::string("*"));
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
// Sent
@@ -1441,7 +1439,7 @@ void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const strin
{
BOOST_FOREACH(const COutputEntry& r, listReceived)
{
- string account;
+ std::string account;
if (pwallet->mapAddressBook.count(r.destination)) {
account = pwallet->mapAddressBook[r.destination].name;
}
@@ -1479,9 +1477,9 @@ void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const strin
}
}
-void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
+void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret)
{
- bool fAllAccounts = (strAccount == string("*"));
+ bool fAllAccounts = (strAccount == std::string("*"));
if (fAllAccounts || acentry.strAccount == strAccount)
{
@@ -1504,7 +1502,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"listtransactions ( \"account\" count skip include_watchonly)\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
"\nArguments:\n"
@@ -1565,7 +1563,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- string strAccount = "*";
+ std::string strAccount = "*";
if (request.params.size() > 0)
strAccount = request.params[0].get_str();
int nCount = 10;
@@ -1607,11 +1605,11 @@ UniValue listtransactions(const JSONRPCRequest& request)
if ((nFrom + nCount) > (int)ret.size())
nCount = ret.size() - nFrom;
- vector<UniValue> arrTmp = ret.getValues();
+ std::vector<UniValue> arrTmp = ret.getValues();
- vector<UniValue>::iterator first = arrTmp.begin();
+ std::vector<UniValue>::iterator first = arrTmp.begin();
std::advance(first, nFrom);
- vector<UniValue>::iterator last = arrTmp.begin();
+ std::vector<UniValue>::iterator last = arrTmp.begin();
std::advance(last, nFrom+nCount);
if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
@@ -1634,7 +1632,7 @@ UniValue listaccounts(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"listaccounts ( minconf include_watchonly)\n"
"\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
"\nArguments:\n"
@@ -1666,7 +1664,7 @@ UniValue listaccounts(const JSONRPCRequest& request)
if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
- map<string, CAmount> mapAccountBalances;
+ std::map<std::string, CAmount> mapAccountBalances;
for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me
mapAccountBalances[entry.second.name] = 0;
@@ -1676,9 +1674,9 @@ UniValue listaccounts(const JSONRPCRequest& request)
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
CAmount nFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
+ std::string strSentAccount;
+ std::list<COutputEntry> listReceived;
+ std::list<COutputEntry> listSent;
int nDepth = wtx.GetDepthInMainChain();
if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0)
continue;
@@ -1697,12 +1695,12 @@ UniValue listaccounts(const JSONRPCRequest& request)
}
}
- const list<CAccountingEntry> & acentries = pwallet->laccentries;
+ const std::list<CAccountingEntry>& acentries = pwallet->laccentries;
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
UniValue ret(UniValue::VOBJ);
- BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
+ BOOST_FOREACH(const PAIRTYPE(std::string, CAmount)& accountBalance, mapAccountBalances) {
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
}
return ret;
@@ -1716,7 +1714,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
}
if (request.fHelp)
- throw runtime_error(
+ throw std::runtime_error(
"listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n"
"\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
"\nArguments:\n"
@@ -1823,7 +1821,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"gettransaction \"txid\" ( include_watchonly )\n"
"\nGet detailed information about in-wallet transaction <txid>\n"
"\nArguments:\n"
@@ -1898,7 +1896,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -1912,7 +1910,7 @@ UniValue abandontransaction(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"abandontransaction \"txid\"\n"
"\nMark in-wallet transaction <txid> as abandoned\n"
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
@@ -1951,7 +1949,7 @@ UniValue backupwallet(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 1)
- throw runtime_error(
+ throw std::runtime_error(
"backupwallet \"destination\"\n"
"\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n"
"\nArguments:\n"
@@ -1963,7 +1961,7 @@ UniValue backupwallet(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- string strDest = request.params[0].get_str();
+ std::string strDest = request.params[0].get_str();
if (!pwallet->BackupWallet(strDest)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
}
@@ -1980,7 +1978,7 @@ UniValue keypoolrefill(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"keypoolrefill ( newsize )\n"
"\nFills the keypool."
+ HelpRequiringPassphrase(pwallet) + "\n"
@@ -2027,7 +2025,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
}
if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
- throw runtime_error(
+ throw std::runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
"This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
@@ -2069,7 +2067,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
}
}
else
- throw runtime_error(
+ throw std::runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
@@ -2091,7 +2089,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
}
if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
- throw runtime_error(
+ throw std::runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
"\nArguments:\n"
@@ -2122,7 +2120,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
strNewWalletPass = request.params[1].get_str().c_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
- throw runtime_error(
+ throw std::runtime_error(
"walletpassphrasechange <oldpassphrase> <newpassphrase>\n"
"Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.");
@@ -2142,7 +2140,7 @@ UniValue walletlock(const JSONRPCRequest& request)
}
if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) {
- throw runtime_error(
+ throw std::runtime_error(
"walletlock\n"
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
"After calling this method, you will need to call walletpassphrase again\n"
@@ -2182,7 +2180,7 @@ UniValue encryptwallet(const JSONRPCRequest& request)
}
if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) {
- throw runtime_error(
+ throw std::runtime_error(
"encryptwallet \"passphrase\"\n"
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
"After this, any calls that interact with private keys such as sending or signing \n"
@@ -2221,7 +2219,7 @@ UniValue encryptwallet(const JSONRPCRequest& request)
strWalletPass = request.params[0].get_str().c_str();
if (strWalletPass.length() < 1)
- throw runtime_error(
+ throw std::runtime_error(
"encryptwallet <passphrase>\n"
"Encrypts the wallet with <passphrase>.");
@@ -2244,7 +2242,7 @@ UniValue lockunspent(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n"
"\nUpdates list of temporarily unspendable outputs.\n"
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
@@ -2308,7 +2306,7 @@ UniValue lockunspent(const JSONRPCRequest& request)
{"vout", UniValueType(UniValue::VNUM)},
});
- string txid = find_value(o, "txid").get_str();
+ std::string txid = find_value(o, "txid").get_str();
if (!IsHex(txid))
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
@@ -2335,7 +2333,7 @@ UniValue listlockunspent(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 0)
- throw runtime_error(
+ throw std::runtime_error(
"listlockunspent\n"
"\nReturns list of temporarily unspendable outputs.\n"
"See the lockunspent call to lock and unlock transactions for spending.\n"
@@ -2362,7 +2360,7 @@ UniValue listlockunspent(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- vector<COutPoint> vOutpts;
+ std::vector<COutPoint> vOutpts;
pwallet->ListLockedCoins(vOutpts);
UniValue ret(UniValue::VARR);
@@ -2386,7 +2384,7 @@ UniValue settxfee(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
- throw runtime_error(
+ throw std::runtime_error(
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
"\nArguments:\n"
@@ -2415,7 +2413,7 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"getwalletinfo\n"
"Returns an object containing various wallet state info.\n"
"\nResult:\n"
@@ -2464,7 +2462,7 @@ UniValue resendwallettransactions(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() != 0)
- throw runtime_error(
+ throw std::runtime_error(
"resendwallettransactions\n"
"Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
"Intended only for testing; the wallet code periodically re-broadcasts\n"
@@ -2494,7 +2492,7 @@ UniValue listunspent(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() > 4)
- throw runtime_error(
+ throw std::runtime_error(
"listunspent ( minconf maxconf [\"addresses\",...] [include_unsafe] )\n"
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
@@ -2508,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"
@@ -2523,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"
@@ -2546,7 +2545,7 @@ UniValue listunspent(const JSONRPCRequest& request)
nMaxDepth = request.params[1].get_int();
}
- set<CBitcoinAddress> setAddress;
+ std::set<CBitcoinAddress> setAddress;
if (request.params.size() > 2 && !request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
@@ -2554,9 +2553,9 @@ UniValue listunspent(const JSONRPCRequest& request)
const UniValue& input = inputs[idx];
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str());
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str());
setAddress.insert(address);
}
}
@@ -2568,7 +2567,7 @@ UniValue listunspent(const JSONRPCRequest& request)
}
UniValue results(UniValue::VARR);
- vector<COutput> vecOutputs;
+ std::vector<COutput> vecOutputs;
assert(pwallet != NULL);
LOCK2(cs_main, pwallet->cs_wallet);
pwallet->AvailableCoins(vecOutputs, !include_unsafe, NULL, true);
@@ -2608,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);
}
@@ -2622,7 +2622,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw runtime_error(
+ throw std::runtime_error(
"fundrawtransaction \"hexstring\" ( options )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
@@ -2679,7 +2679,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
CFeeRate feeRate = CFeeRate(0);
bool overrideEstimatedFeerate = false;
UniValue subtractFeeFromOutputs;
- set<int> setSubtractFeeFromOutputs;
+ std::set<int> setSubtractFeeFromOutputs;
if (request.params.size() > 1) {
if (request.params[1].type() == UniValue::VBOOL) {
@@ -2707,7 +2707,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
CBitcoinAddress address(options["changeAddress"].get_str());
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address");
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
changeAddress = address.Get();
}
@@ -2758,10 +2758,10 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
}
CAmount nFeeOut;
- string strFailReason;
+ std::string strFailReason;
if (!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
+ throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
UniValue result(UniValue::VOBJ);
@@ -2782,14 +2782,14 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, CWallet &wallet)
{
CMutableTransaction txNew(tx);
- std::vector<pair<CWalletTx *, unsigned int>> vCoins;
+ std::vector<std::pair<CWalletTx*, unsigned int>> vCoins;
// Look up the inputs. We should have already checked that this transaction
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
// wallet, with a valid index into the vout array.
for (auto& input : tx.vin) {
const auto mi = wallet.mapWallet.find(input.prevout.hash);
assert(mi != wallet.mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
- vCoins.emplace_back(make_pair(&(mi->second), input.prevout.n));
+ vCoins.emplace_back(std::make_pair(&(mi->second), input.prevout.n));
}
if (!wallet.DummySignTx(txNew, vCoins)) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
@@ -2807,7 +2807,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
return NullUniValue;
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw runtime_error(
+ throw std::runtime_error(
"bumpfee \"txid\" ( options ) \n"
"\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
"An opt-in RBF transaction with the given txid must be in the wallet.\n"
@@ -2862,33 +2862,33 @@ UniValue bumpfee(const JSONRPCRequest& request)
CWalletTx& wtx = pwallet->mapWallet[hash];
if (pwallet->HasWalletSpend(hash)) {
- throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the wallet");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the wallet");
}
{
LOCK(mempool.cs);
auto it = mempool.mapTx.find(hash);
if (it != mempool.mapTx.end() && it->GetCountWithDescendants() > 1) {
- throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the mempool");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the mempool");
}
}
if (wtx.GetDepthInMainChain() != 0) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction has been mined, or is conflicted with a mined transaction");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has been mined, or is conflicted with a mined transaction");
}
if (!SignalsOptInRBF(wtx)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction is not BIP 125 replaceable");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is not BIP 125 replaceable");
}
if (wtx.mapValue.count("replaced_by_txid")) {
- throw JSONRPCError(RPC_INVALID_REQUEST, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid")));
+ throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid")));
}
// check that original tx consists entirely of our inputs
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
if (!pwallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that don't belong to this wallet");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction contains inputs that don't belong to this wallet");
}
// figure out which output was change
@@ -2897,13 +2897,13 @@ UniValue bumpfee(const JSONRPCRequest& request)
for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
if (pwallet->IsChange(wtx.tx->vout[i])) {
if (nOutput != -1) {
- throw JSONRPCError(RPC_MISC_ERROR, "Transaction has multiple change outputs");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has multiple change outputs");
}
nOutput = i;
}
}
if (nOutput == -1) {
- throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not have a change output");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Transaction does not have a change output");
}
// Calculate the expected size of the new transaction.
@@ -2994,7 +2994,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
// Check that in all cases the new fee doesn't violate maxTxFee
if (nNewFee > maxTxFee) {
- throw JSONRPCError(RPC_MISC_ERROR,
+ throw JSONRPCError(RPC_WALLET_ERROR,
strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
FormatMoney(nNewFee), FormatMoney(maxTxFee)));
}
@@ -3006,7 +3006,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
// moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
- throw JSONRPCError(RPC_MISC_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
+ throw JSONRPCError(RPC_WALLET_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
}
// Now modify the output to increase the fee.
@@ -3016,7 +3016,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
CMutableTransaction tx(*(wtx.tx));
CTxOut* poutput = &(tx.vout[nOutput]);
if (poutput->nValue < nDelta) {
- throw JSONRPCError(RPC_MISC_ERROR, "Change output is too small to bump the fee");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Change output is too small to bump the fee");
}
// If the output would become dust, discard it (converting the dust to fee)
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 294920add9..67e5e90224 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -27,16 +27,14 @@ extern UniValue importmulti(const JSONRPCRequest& request);
// we repeat those tests this many times and only complain if all iterations of the test fail
#define RANDOM_REPEATS 5
-using namespace std;
-
std::vector<std::unique_ptr<CWalletTx>> wtxn;
-typedef set<pair<const CWalletTx*,unsigned int> > CoinSet;
+typedef std::set<std::pair<const CWalletTx*,unsigned int> > CoinSet;
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
static const CWallet testWallet;
-static vector<COutput> vCoins;
+static std::vector<COutput> vCoins;
static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0)
{
@@ -56,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));
}
@@ -69,7 +67,7 @@ static void empty_wallet(void)
static bool equal_sets(CoinSet a, CoinSet b)
{
- pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin());
+ std::pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin());
return ret.first == a.end() && ret.second == b.end();
}
@@ -415,7 +413,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
CKey futureKey;
futureKey.MakeNewKey(true);
key.pushKV("scriptPubKey", HexStr(GetScriptForRawPubKey(futureKey.GetPubKey())));
- key.pushKV("timestamp", newTip->GetBlockTimeMax() + 7200);
+ key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW);
key.pushKV("internal", UniValue(true));
keys.push_back(key);
JSONRPCRequest request;
@@ -453,4 +451,57 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
BOOST_CHECK_EQUAL(wtx.GetImmatureCredit(), 50*COIN);
}
+static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
+{
+ CMutableTransaction tx;
+ tx.nLockTime = lockTime;
+ SetMockTime(mockTime);
+ CBlockIndex* block = nullptr;
+ if (blockTime > 0) {
+ auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
+ assert(inserted.second);
+ const uint256& hash = inserted.first->first;
+ block = inserted.first->second;
+ block->nTime = blockTime;
+ block->phashBlock = &hash;
+ }
+
+ CWalletTx wtx(&wallet, MakeTransactionRef(tx));
+ if (block) {
+ wtx.SetMerkleBranch(block, 0);
+ }
+ wallet.AddToWallet(wtx);
+ return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
+}
+
+// Simple test to verify assignment of CWalletTx::nSmartTime value. Could be
+// expanded to cover more corner cases of smart time logic.
+BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
+{
+ CWallet wallet;
+
+ // New transaction should use clock time if lower than block time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 1, 100, 120), 100);
+
+ // Test that updating existing transaction does not change smart time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 1, 200, 220), 100);
+
+ // New transaction should use clock time if there's no block time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 2, 300, 0), 300);
+
+ // New transaction should use block time if lower than clock time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 3, 420, 400), 400);
+
+ // New transaction should use latest entry time if higher than
+ // min(block time, clock time).
+ BOOST_CHECK_EQUAL(AddTx(wallet, 4, 500, 390), 400);
+
+ // If there are future entries, new transaction should use time of the
+ // newest entry that is no more than 300 seconds ahead of the clock time.
+ BOOST_CHECK_EQUAL(AddTx(wallet, 5, 50, 600), 300);
+
+ // Reset mock time for other tests.
+ SetMockTime(0);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index ce3f1fb549..445e40b043 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -20,6 +20,7 @@
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
+#include "scheduler.h"
#include "timedata.h"
#include "txmempool.h"
#include "util.h"
@@ -32,14 +33,11 @@
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
CWallet* pwalletMain = NULL;
/** Transaction fee set by the user */
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
-bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
bool fWalletRbf = DEFAULT_WALLET_RBF;
const char * DEFAULT_WALLET_DAT = "wallet.dat";
@@ -66,8 +64,8 @@ const uint256 CMerkleTx::ABANDON_HASH(uint256S("00000000000000000000000000000000
struct CompareValueOnly
{
- bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1,
- const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const
+ bool operator()(const std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> >& t1,
+ const std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> >& t2) const
{
return t1.first < t2.first;
}
@@ -186,7 +184,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
}
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
- const vector<unsigned char> &vchCryptedSecret)
+ const std::vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
@@ -404,9 +402,9 @@ bool CWallet::SetMaxVersion(int nVersion)
return true;
}
-set<uint256> CWallet::GetConflicts(const uint256& txid) const
+std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
{
- set<uint256> result;
+ std::set<uint256> result;
AssertLockHeld(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
@@ -444,61 +442,34 @@ bool CWallet::Verify()
if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
return true;
- LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
- std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
-
- LogPrintf("Using wallet %s\n", walletFile);
uiInterface.InitMessage(_("Verifying wallet..."));
+ std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
- // Wallet file must be a plain filename without a directory
- if (walletFile != boost::filesystem::basename(walletFile) + boost::filesystem::extension(walletFile))
- return InitError(strprintf(_("Wallet %s resides outside data directory %s"), walletFile, GetDataDir().string()));
+ std::string strError;
+ if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError))
+ return InitError(strError);
- if (!bitdb.Open(GetDataDir()))
- {
- // try moving the database env out of the way
- boost::filesystem::path pathDatabase = GetDataDir() / "database";
- boost::filesystem::path pathDatabaseBak = GetDataDir() / strprintf("database.%d.bak", GetTime());
- try {
- boost::filesystem::rename(pathDatabase, pathDatabaseBak);
- LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
- } catch (const boost::filesystem::filesystem_error&) {
- // failure is ok (well, not really, but it's not worse than what we started with)
- }
-
- // try again
- if (!bitdb.Open(GetDataDir())) {
- // if it still fails, it probably means we can't even create the database env
- return InitError(strprintf(_("Error initializing wallet database environment %s!"), GetDataDir()));
- }
- }
-
if (GetBoolArg("-salvagewallet", false))
{
// Recover readable keypairs:
- if (!CWalletDB::Recover(bitdb, walletFile, true))
+ CWallet dummyWallet;
+ if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter))
return false;
}
-
- if (boost::filesystem::exists(GetDataDir() / walletFile))
+
+ std::string strWarning;
+ bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
+ if (!strWarning.empty())
+ InitWarning(strWarning);
+ if (!dbV)
{
- CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
- if (r == CDBEnv::RECOVER_OK)
- {
- InitWarning(strprintf(_("Warning: Wallet file corrupt, data salvaged!"
- " Original %s saved as %s in %s; if"
- " your balance or transactions are incorrect you should"
- " restore from a backup."),
- walletFile, "wallet.{timestamp}.bak", GetDataDir()));
- }
- if (r == CDBEnv::RECOVER_FAIL)
- return InitError(strprintf(_("%s corrupt, salvage failed"), walletFile));
+ InitError(strError);
+ return false;
}
-
return true;
}
-void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
+void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
{
// We want all the wallet transactions in range to have the same metadata as
// the oldest (smallest nOrderPos).
@@ -542,7 +513,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
{
const COutPoint outpoint(hash, n);
- pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range;
range = mapTxSpends.equal_range(outpoint);
for (TxSpends::const_iterator it = range.first; it != range.second; ++it)
@@ -560,9 +531,9 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const
void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
{
- mapTxSpends.insert(make_pair(outpoint, wtxid));
+ mapTxSpends.insert(std::make_pair(outpoint, wtxid));
- pair<TxSpends::iterator, TxSpends::iterator> range;
+ std::pair<TxSpends::iterator, TxSpends::iterator> range;
range = mapTxSpends.equal_range(outpoint);
SyncMetaData(range);
}
@@ -688,20 +659,20 @@ DBErrors CWallet::ReorderTransactions()
// Probably a bad idea to change the output of this
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
- typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
- typedef multimap<int64_t, TxPair > TxItems;
+ typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
+ typedef std::multimap<int64_t, TxPair > TxItems;
TxItems txByTime;
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
CWalletTx* wtx = &((*it).second);
- txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
+ txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
}
- list<CAccountingEntry> acentries;
+ std::list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit("", acentries);
BOOST_FOREACH(CAccountingEntry& entry, acentries)
{
- txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
+ txByTime.insert(std::make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
}
nOrderPosNext = 0;
@@ -815,7 +786,7 @@ bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bFo
else {
// Check if the current key has been used
CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID());
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin();
+ for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin();
it != mapWallet.end() && account.vchPubKey.IsValid();
++it)
BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout)
@@ -887,7 +858,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
uint256 hash = wtxIn.GetHash();
// Inserts only if not already there, returns tx inserted or tx found
- pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
+ std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
wtx.BindWallet(this);
bool fInsertedNew = ret.second;
@@ -895,52 +866,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
wtx.nTimeReceived = GetAdjustedTime();
wtx.nOrderPos = IncOrderPosNext(&walletdb);
- wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
-
- wtx.nTimeSmart = wtx.nTimeReceived;
- if (!wtxIn.hashUnset())
- {
- if (mapBlockIndex.count(wtxIn.hashBlock))
- {
- int64_t latestNow = wtx.nTimeReceived;
- int64_t latestEntry = 0;
- {
- // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
- int64_t latestTolerated = latestNow + 300;
- const TxItems & txOrdered = wtxOrdered;
- for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
- {
- CWalletTx *const pwtx = (*it).second.first;
- if (pwtx == &wtx)
- continue;
- CAccountingEntry *const pacentry = (*it).second.second;
- int64_t nSmartTime;
- if (pwtx)
- {
- nSmartTime = pwtx->nTimeSmart;
- if (!nSmartTime)
- nSmartTime = pwtx->nTimeReceived;
- }
- else
- nSmartTime = pacentry->nTime;
- if (nSmartTime <= latestTolerated)
- {
- latestEntry = nSmartTime;
- if (nSmartTime > latestNow)
- latestNow = nSmartTime;
- break;
- }
- }
- }
-
- int64_t blocktime = mapBlockIndex[wtxIn.hashBlock]->GetBlockTime();
- wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
- }
- else
- LogPrintf("AddToWallet(): found %s in block %s not in index\n",
- wtxIn.GetHash().ToString(),
- wtxIn.hashBlock.ToString());
- }
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ wtx.nTimeSmart = ComputeTimeSmart(wtx);
AddToSpends(hash);
}
@@ -1004,7 +931,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
mapWallet[hash] = wtxIn;
CWalletTx& wtx = mapWallet[hash];
wtx.BindWallet(this);
- wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
+ wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0)));
AddToSpends(hash);
BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) {
if (mapWallet.count(txin.prevout.hash)) {
@@ -1203,7 +1130,7 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
LOCK(cs_wallet);
- map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
@@ -1220,7 +1147,7 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
- map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
@@ -1394,13 +1321,13 @@ bool CWallet::SetHDChain(const CHDChain& chain, bool memonly)
{
LOCK(cs_wallet);
if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain))
- throw runtime_error(std::string(__func__) + ": writing chain failed");
+ throw std::runtime_error(std::string(__func__) + ": writing chain failed");
hdChain = chain;
return true;
}
-bool CWallet::IsHDEnabled()
+bool CWallet::IsHDEnabled() const
{
return !hdChain.masterKeyID.IsNull();
}
@@ -1422,7 +1349,7 @@ int CWalletTx::GetRequestCount() const
// Generated block
if (!hashUnset())
{
- map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
+ std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
if (mi != pwallet->mapRequestCount.end())
nRequests = (*mi).second;
}
@@ -1430,7 +1357,7 @@ int CWalletTx::GetRequestCount() const
else
{
// Did anyone request this transaction?
- map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
+ std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
if (mi != pwallet->mapRequestCount.end())
{
nRequests = (*mi).second;
@@ -1438,7 +1365,7 @@ int CWalletTx::GetRequestCount() const
// How about the block it's in?
if (nRequests == 0 && !hashUnset())
{
- map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
+ std::map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock);
if (_mi != pwallet->mapRequestCount.end())
nRequests = (*_mi).second;
else
@@ -1450,8 +1377,8 @@ int CWalletTx::GetRequestCount() const
return nRequests;
}
-void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
- list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const
+void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
+ std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const
{
nFee = 0;
listReceived.clear();
@@ -1506,15 +1433,15 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
}
-void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
+void CWalletTx::GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const
{
nReceived = nSent = nFee = 0;
CAmount allFee;
- string strSentAccount;
- list<COutputEntry> listReceived;
- list<COutputEntry> listSent;
+ std::string strSentAccount;
+ std::list<COutputEntry> listReceived;
+ std::list<COutputEntry> listSent;
GetAmounts(listReceived, listSent, allFee, strSentAccount, filter);
if (strAccount == strSentAccount)
@@ -1529,7 +1456,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived,
{
if (pwallet->mapAddressBook.count(r.destination))
{
- map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
+ std::map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination);
if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount)
nReceived += r.amount;
}
@@ -1562,7 +1489,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
- while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - 7200)))
+ while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - TIMESTAMP_WINDOW)))
pindex = chainActive.Next(pindex);
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
@@ -1650,9 +1577,9 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman)
return false;
}
-set<uint256> CWalletTx::GetConflicts() const
+std::set<uint256> CWalletTx::GetConflicts() const
{
- set<uint256> result;
+ std::set<uint256> result;
if (pwallet != NULL)
{
uint256 myHash = GetHash();
@@ -1877,14 +1804,14 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CCon
LOCK(cs_wallet);
// Sort them in chronological order
- multimap<unsigned int, CWalletTx*> mapSorted;
+ std::multimap<unsigned int, CWalletTx*> mapSorted;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
// Don't rebroadcast if newer than nTime:
if (wtx.nTimeReceived > nTime)
continue;
- mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
+ mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx));
}
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
@@ -1934,7 +1861,7 @@ CAmount CWallet::GetBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsTrusted())
@@ -1950,7 +1877,7 @@ CAmount CWallet::GetUnconfirmedBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
@@ -1965,7 +1892,7 @@ CAmount CWallet::GetImmatureBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureCredit();
@@ -1979,7 +1906,7 @@ CAmount CWallet::GetWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (pcoin->IsTrusted())
@@ -1995,7 +1922,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool())
@@ -2010,7 +1937,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
CAmount nTotal = 0;
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
nTotal += pcoin->GetImmatureWatchOnlyCredit();
@@ -2019,13 +1946,13 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const
return nTotal;
}
-void CWallet::AvailableCoins(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();
{
LOCK2(cs_main, cs_wallet);
- for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
@@ -2033,9 +1960,6 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (!CheckFinalTx(*pcoin))
continue;
- if (fOnlyConfirmed && !pcoin->IsTrusted())
- continue;
-
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
@@ -2048,6 +1972,8 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth == 0 && !pcoin->InMempool())
continue;
+ bool safeTx = pcoin->IsTrusted();
+
// We should not consider coins from transactions that are replacing
// other transactions.
//
@@ -2063,8 +1989,8 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
// 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
@@ -2075,7 +2001,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
// 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;
}
@@ -2087,16 +2017,16 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
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));
}
}
}
}
-static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
- vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
+static void ApproximateBestSubset(std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue,
+ std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000)
{
- vector<char> vfIncluded;
+ std::vector<char> vfIncluded;
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
@@ -2139,17 +2069,17 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
-bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector<COutput> vCoins,
- set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
+bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector<COutput> vCoins,
+ std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const
{
setCoinsRet.clear();
nValueRet = 0;
// List of values less than target
- pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
+ std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > coinLowestLarger;
coinLowestLarger.first = std::numeric_limits<CAmount>::max();
coinLowestLarger.second.first = NULL;
- vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue;
+ std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > > vValue;
CAmount nTotalLower = 0;
random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
@@ -2170,7 +2100,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
int i = output.i;
CAmount n = pcoin->tx->vout[i].nValue;
- pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
+ std::pair<CAmount,std::pair<const CWalletTx*,unsigned int> > coin = std::make_pair(n,std::make_pair(pcoin, i));
if (n == nTargetValue)
{
@@ -2211,7 +2141,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
// Solve subset sum by stochastic approximation
std::sort(vValue.begin(), vValue.end(), CompareValueOnly());
std::reverse(vValue.begin(), vValue.end());
- vector<char> vfBest;
+ std::vector<char> vfBest;
CAmount nBest;
ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);
@@ -2244,9 +2174,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin
return true;
}
-bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
+bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const
{
- vector<COutput> vCoins(vAvailableCoins);
+ std::vector<COutput> vCoins(vAvailableCoins);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
@@ -2256,13 +2186,13 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
if (!out.fSpendable)
continue;
nValueRet += out.tx->tx->vout[out.i].nValue;
- setCoinsRet.insert(make_pair(out.tx, out.i));
+ setCoinsRet.insert(std::make_pair(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
}
// calculate value from preset inputs and store them
- set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
+ std::set<std::pair<const CWalletTx*, uint32_t> > setPresetCoins;
CAmount nValueFromPresetInputs = 0;
std::vector<COutPoint> vPresetInputs;
@@ -2270,7 +2200,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
coinControl->ListSelected(vPresetInputs);
BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
{
- map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
+ std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
if (it != mapWallet.end())
{
const CWalletTx* pcoin = &it->second;
@@ -2278,15 +2208,15 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
if (pcoin->tx->vout.size() <= outpoint.n)
return false;
nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
- setPresetCoins.insert(make_pair(pcoin, outpoint.n));
+ setPresetCoins.insert(std::make_pair(pcoin, outpoint.n));
} else
return false; // TODO: Allow non-wallet inputs
}
// remove preset inputs from vCoins
- for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
+ for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
{
- if (setPresetCoins.count(make_pair(it->tx, it->i)))
+ if (setPresetCoins.count(std::make_pair(it->tx, it->i)))
it = vCoins.erase(it);
else
++it;
@@ -2315,7 +2245,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange)
{
- vector<CRecipient> vecSend;
+ std::vector<CRecipient> vecSend;
// Turn the txout set into a CRecipient vector
for (size_t idx = 0; idx < tx.vout.size(); idx++)
@@ -2369,7 +2299,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
return true;
}
-bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
+bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
{
CAmount nValue = 0;
@@ -2430,7 +2360,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
{
- set<pair<const CWalletTx*,unsigned int> > setCoins;
+ std::set<std::pair<const CWalletTx*,unsigned int> > setCoins;
LOCK2(cs_main, cs_wallet);
{
std::vector<COutput> vAvailableCoins;
@@ -2449,7 +2379,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CAmount nValueToSelect = nValue;
if (nSubtractFeeFromAmount == 0)
nValueToSelect += nFeeRet;
- double dPriority = 0;
// vouts to the payees
for (const auto& recipient : vecSend)
{
@@ -2490,19 +2419,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
strFailReason = _("Insufficient funds");
return false;
}
- for (const auto& pcoin : setCoins)
- {
- CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue;
- //The coin age after the next block (depth+1) is used instead of the current,
- //reflecting an assumption the user would accept a bit more delay for
- //a chance at a free transaction.
- //But mempool inputs might still be in the mempool, so their age stays 0
- int age = pcoin.first->GetDepthInMainChain();
- assert(age >= 0);
- if (age != 0)
- age += 1;
- dPriority += (double)nCredit * age;
- }
const CAmount nChange = nValueIn - nValueToSelect;
if (nChange > 0)
@@ -2584,7 +2500,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
return false;
}
- vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;
+ std::vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut;
txNew.vout.insert(position, newTxOut);
}
}
@@ -2601,9 +2517,10 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest possible change from prior
// behavior."
+ bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf;
for (const auto& coin : setCoins)
txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
- std::numeric_limits<unsigned int>::max() - (fWalletRbf ? 2 : 1)));
+ std::numeric_limits<unsigned int>::max() - (rbf ? 2 : 1)));
// Fill in dummy signatures for fee calculation.
if (!DummySignTx(txNew, setCoins)) {
@@ -2614,7 +2531,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
unsigned int nBytes = GetVirtualTransactionSize(txNew);
CTransaction txNewConst(txNew);
- dPriority = txNewConst.ComputePriority(dPriority, nBytes);
// Remove scriptSigs to eliminate the fee calculation dummy signatures
for (auto& vin : txNew.vin) {
@@ -2627,16 +2543,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget;
- // Can we complete this as a free transaction?
- if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
- {
- // Not enough fee: enough priority?
- double dPriorityNeeded = mempool.estimateSmartPriority(currentConfirmationTarget);
- // Require at least hard-coded AllowFree.
- if (dPriority >= dPriorityNeeded && AllowFree(dPriority))
- break;
- }
-
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool);
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
nFeeNeeded = coinControl->nMinimumTotalFee;
@@ -2665,7 +2571,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// to be addressed so we avoid creating too small an output.
if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded;
- vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
+ std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
change_position->nValue += extraFeePaid;
nFeeRet -= extraFeePaid;
}
@@ -2675,7 +2581,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Try to reduce change to include necessary fee
if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) {
CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet;
- vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
+ std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut;
// Only reduce change if remaining amount is still a large enough output.
if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) {
change_position->nValue -= additionalFeeNeeded;
@@ -2725,7 +2631,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp;
- CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp);
+ CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, false, 0, lp);
CTxMemPool::setEntries setAncestors;
size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
@@ -2801,7 +2707,7 @@ bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwa
laccentries.push_back(acentry);
CAccountingEntry & entry = laccentries.back();
- wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
+ wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry)));
return true;
}
@@ -2866,7 +2772,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
return DB_LOAD_OK;
}
-DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOut)
+DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
if (!fFileBacked)
return DB_LOAD_OK;
@@ -2921,7 +2827,7 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
}
-bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
+bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
{
bool fUpdated = false;
{
@@ -2950,7 +2856,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
{
// Delete destdata tuples associated with address
std::string strAddress = CBitcoinAddress(address).ToString();
- BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata)
+ BOOST_FOREACH(const PAIRTYPE(std::string, std::string) &item, mapAddressBook[address].destdata)
{
CWalletDB(strWalletFile).EraseDestData(strAddress, item.first);
}
@@ -2993,7 +2899,7 @@ bool CWallet::NewKeyPool()
if (IsLocked())
return false;
- int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0);
+ int64_t nKeys = std::max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0);
for (int i = 0; i < nKeys; i++)
{
int64_t nIndex = i+1;
@@ -3020,7 +2926,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (kpSize > 0)
nTargetSize = kpSize;
else
- nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
+ nTargetSize = std::max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0);
while (setKeyPool.size() < (nTargetSize + 1))
{
@@ -3028,7 +2934,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
- throw runtime_error(std::string(__func__) + ": writing generated key failed");
+ throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
setKeyPool.insert(nEnd);
LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size());
}
@@ -3055,9 +2961,9 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
nIndex = *(setKeyPool.begin());
setKeyPool.erase(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error(std::string(__func__) + ": read failed");
+ throw std::runtime_error(std::string(__func__) + ": read failed");
if (!HaveKey(keypool.vchPubKey.GetID()))
- throw runtime_error(std::string(__func__) + ": unknown key in key pool");
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
assert(keypool.vchPubKey.IsValid());
LogPrintf("keypool reserve %d\n", nIndex);
}
@@ -3116,14 +3022,14 @@ int64_t CWallet::GetOldestKeyPoolTime()
CWalletDB walletdb(strWalletFile);
int64_t nIndex = *(setKeyPool.begin());
if (!walletdb.ReadPool(nIndex, keypool))
- throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
+ throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
- map<CTxDestination, CAmount> balances;
+ std::map<CTxDestination, CAmount> balances;
{
LOCK(cs_wallet);
@@ -3161,11 +3067,11 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
return balances;
}
-set< set<CTxDestination> > CWallet::GetAddressGroupings()
+std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
{
AssertLockHeld(cs_wallet); // mapWallet
- set< set<CTxDestination> > groupings;
- set<CTxDestination> grouping;
+ std::set< std::set<CTxDestination> > groupings;
+ std::set<CTxDestination> grouping;
BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet)
{
@@ -3218,20 +3124,20 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
}
}
- set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
- map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it
- BOOST_FOREACH(set<CTxDestination> _grouping, groupings)
+ std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
+ std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
+ BOOST_FOREACH(std::set<CTxDestination> _grouping, groupings)
{
// make a set of all the groups hit by this new group
- set< set<CTxDestination>* > hits;
- map< CTxDestination, set<CTxDestination>* >::iterator it;
+ std::set< std::set<CTxDestination>* > hits;
+ std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
BOOST_FOREACH(CTxDestination address, _grouping)
if ((it = setmap.find(address)) != setmap.end())
hits.insert((*it).second);
// merge all hit groups into a new single group and delete old groups
- set<CTxDestination>* merged = new set<CTxDestination>(_grouping);
- BOOST_FOREACH(set<CTxDestination>* hit, hits)
+ std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
+ BOOST_FOREACH(std::set<CTxDestination>* hit, hits)
{
merged->insert(hit->begin(), hit->end());
uniqueGroupings.erase(hit);
@@ -3244,8 +3150,8 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
setmap[element] = merged;
}
- set< set<CTxDestination> > ret;
- BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings)
+ std::set< std::set<CTxDestination> > ret;
+ BOOST_FOREACH(std::set<CTxDestination>* uniqueGrouping, uniqueGroupings)
{
ret.insert(*uniqueGrouping);
delete uniqueGrouping;
@@ -3265,7 +3171,7 @@ CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAc
CAmount nBalance = 0;
// Tally wallet transactions
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
@@ -3288,11 +3194,11 @@ CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAc
std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
- set<CTxDestination> result;
+ std::set<CTxDestination> result;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
{
const CTxDestination& address = item.first;
- const string& strName = item.second.name;
+ const std::string& strName = item.second.name;
if (strName == strAccount)
result.insert(address);
}
@@ -3332,7 +3238,7 @@ void CReserveKey::ReturnKey()
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
+void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
{
setAddress.clear();
@@ -3343,11 +3249,11 @@ void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))
- throw runtime_error(std::string(__func__) + ": read failed");
+ throw std::runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
if (!HaveKey(keyID))
- throw runtime_error(std::string(__func__) + ": unknown key in key pool");
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
setAddress.insert(keyID);
}
}
@@ -3357,7 +3263,7 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
{
LOCK(cs_wallet);
// Only notify UI if this transaction is in this wallet
- map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
+ std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx);
if (mi != mapWallet.end())
NotifyTransactionChanged(this, hashTx, CT_UPDATED);
}
@@ -3495,7 +3401,72 @@ void CWallet::GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) c
// Extract block timestamps for those keys
for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->GetBlockTime() - 7200; // block times can be 2h off
+ mapKeyBirth[it->first] = it->second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+}
+
+/**
+ * Compute smart timestamp for a transaction being added to the wallet.
+ *
+ * Logic:
+ * - If sending a transaction, assign its timestamp to the current time.
+ * - If receiving a transaction outside a block, assign its timestamp to the
+ * current time.
+ * - If receiving a block with a future timestamp, assign all its (not already
+ * known) transactions' timestamps to the current time.
+ * - If receiving a block with a past timestamp, before the most recent known
+ * transaction (that we care about), assign all its (not already known)
+ * transactions' timestamps to the same timestamp as that most-recent-known
+ * transaction.
+ * - If receiving a block with a past timestamp, but after the most recent known
+ * transaction, assign all its (not already known) transactions' timestamps to
+ * the block time.
+ *
+ * For more information see CWalletTx::nTimeSmart,
+ * https://bitcointalk.org/?topic=54527, or
+ * https://github.com/bitcoin/bitcoin/pull/1393.
+ */
+unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
+{
+ unsigned int nTimeSmart = wtx.nTimeReceived;
+ if (!wtx.hashUnset()) {
+ if (mapBlockIndex.count(wtx.hashBlock)) {
+ int64_t latestNow = wtx.nTimeReceived;
+ int64_t latestEntry = 0;
+
+ // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
+ int64_t latestTolerated = latestNow + 300;
+ const TxItems& txOrdered = wtxOrdered;
+ for (auto it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) {
+ CWalletTx* const pwtx = it->second.first;
+ if (pwtx == &wtx) {
+ continue;
+ }
+ CAccountingEntry* const pacentry = it->second.second;
+ int64_t nSmartTime;
+ if (pwtx) {
+ nSmartTime = pwtx->nTimeSmart;
+ if (!nSmartTime) {
+ nSmartTime = pwtx->nTimeReceived;
+ }
+ } else {
+ nSmartTime = pacentry->nTime;
+ }
+ if (nSmartTime <= latestTolerated) {
+ latestEntry = nSmartTime;
+ if (nSmartTime > latestNow) {
+ latestNow = nSmartTime;
+ }
+ break;
+ }
+ }
+
+ int64_t blocktime = mapBlockIndex[wtx.hashBlock]->GetBlockTime();
+ nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
+ } else {
+ LogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());
+ }
+ }
+ return nTimeSmart;
}
bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@@ -3553,8 +3524,6 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
- if (showDebug)
- strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
@@ -3686,17 +3655,13 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
RegisterValidationInterface(walletInstance);
- CBlockIndex *pindexRescan = chainActive.Tip();
- if (GetBoolArg("-rescan", false))
- pindexRescan = chainActive.Genesis();
- else
+ CBlockIndex *pindexRescan = chainActive.Genesis();
+ if (!GetBoolArg("-rescan", false))
{
CWalletDB walletdb(walletFile);
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
- else
- pindexRescan = chainActive.Genesis();
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
@@ -3785,17 +3750,17 @@ bool CWallet::InitLoadWallet()
return true;
}
-std::atomic<bool> CWallet::fFlushThreadRunning(false);
+std::atomic<bool> CWallet::fFlushScheduled(false);
-void CWallet::postInitProcess(boost::thread_group& threadGroup)
+void CWallet::postInitProcess(CScheduler& scheduler)
{
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ReacceptWalletTransactions();
// Run a thread to flush wallet periodically
- if (!CWallet::fFlushThreadRunning.exchange(true)) {
- threadGroup.create_thread(ThreadFlushWalletDB);
+ if (!CWallet::fFlushScheduled.exchange(true)) {
+ scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
}
}
@@ -3879,12 +3844,8 @@ bool CWallet::ParameterInteraction()
}
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
- fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
- if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
- return InitError("Creation of free transactions with their relay disabled is not supported.");
-
return true;
}
@@ -3973,7 +3934,7 @@ int CMerkleTx::GetBlocksToMaturity() const
{
if (!IsCoinBase())
return 0;
- return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
+ return std::max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain());
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 176063c27f..ae4321eef8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -29,7 +29,6 @@
#include <vector>
#include <boost/shared_ptr.hpp>
-#include <boost/thread.hpp>
extern CWallet* pwalletMain;
@@ -39,7 +38,6 @@ extern CWallet* pwalletMain;
extern CFeeRate payTxFee;
extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
-extern bool fSendFreeTransactions;
extern bool fWalletRbf;
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
@@ -57,16 +55,12 @@ static const CAmount MIN_CHANGE = CENT;
static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2;
//! Default for -spendzeroconfchange
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
-//! Default for -sendfreetransactions
-static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
//! Default for -walletrejectlongchains
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default
static const bool DEFAULT_WALLET_RBF = false;
-//! Largest (in bytes) free transaction we're willing to create
-static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
//! if set, all keys will be derived by using BIP32
@@ -79,6 +73,7 @@ class CCoinControl;
class COutput;
class CReserveKey;
class CScript;
+class CScheduler;
class CTxMemPool;
class CWalletTx;
@@ -256,10 +251,44 @@ private:
const CWallet* pwallet;
public:
+ /**
+ * Key/value map with information about the transaction.
+ *
+ * The following keys can be read and written through the map and are
+ * serialized in the wallet database:
+ *
+ * "comment", "to" - comment strings provided to sendtoaddress,
+ * sendfrom, sendmany wallet RPCs
+ * "replaces_txid" - txid (as HexStr) of transaction replaced by
+ * bumpfee on transaction created by bumpfee
+ * "replaced_by_txid" - txid (as HexStr) of transaction created by
+ * bumpfee on transaction replaced by bumpfee
+ * "from", "message" - obsolete fields that could be set in UI prior to
+ * 2011 (removed in commit 4d9b223)
+ *
+ * The following keys are serialized in the wallet database, but shouldn't
+ * be read or written through the map (they will be temporarily added and
+ * removed from the map during serialization):
+ *
+ * "fromaccount" - serialized strFromAccount value
+ * "n" - serialized nOrderPos value
+ * "timesmart" - serialized nTimeSmart value
+ * "spent" - serialized vfSpent value that existed prior to
+ * 2014 (removed in commit 93a18a3)
+ */
mapValue_t mapValue;
std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; //!< time received by this node
+ /**
+ * Stable timestamp that never changes, and reflects the order a transaction
+ * was added to the wallet. Timestamp is based on the block time for a
+ * transaction added as part of a block, or else the time when the
+ * transaction was received if it wasn't part of a block, with the timestamp
+ * adjusted in both cases so timestamp order matches the order transactions
+ * were added to the wallet. More details can be found in
+ * CWallet::ComputeTimeSmart().
+ */
unsigned int nTimeSmart;
/**
* From me flag is set to 1 for transactions that were created by the wallet
@@ -369,7 +398,6 @@ public:
}
mapValue.erase("fromaccount");
- mapValue.erase("version");
mapValue.erase("spent");
mapValue.erase("n");
mapValue.erase("timesmart");
@@ -438,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;
@@ -569,7 +608,7 @@ private:
class CWallet : public CCryptoKeyStore, public CValidationInterface
{
private:
- static std::atomic<bool> fFlushThreadRunning;
+ static std::atomic<bool> fFlushScheduled;
/**
* Select a set of coins such that nValueRet >= nTargetValue and at least
@@ -686,6 +725,7 @@ public:
nLastResend = 0;
nTimeFirstKey = 0;
fBroadcastTransactions = false;
+ nRelockTime = 0;
}
std::map<uint256, CWalletTx> mapWallet;
@@ -712,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
@@ -776,6 +816,7 @@ public:
bool EncryptWallet(const SecureString& strWalletPassphrase);
void GetKeyBirthTimes(std::map<CTxDestination, int64_t> &mapKeyBirth) const;
+ unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
/**
* Increment the next transaction order id
@@ -977,7 +1018,7 @@ public:
* Wallet post-init setup
* Gives the wallet a chance to register repetitive tasks and complete post-init tasks
*/
- void postInitProcess(boost::thread_group& threadGroup);
+ void postInitProcess(CScheduler& scheduler);
/* Wallets parameter interaction */
static bool ParameterInteraction();
@@ -986,10 +1027,10 @@ public:
/* Set the HD chain model (chain child index counters) */
bool SetHDChain(const CHDChain& chain, bool memonly);
- const CHDChain& GetHDChain() { return hdChain; }
+ const CHDChain& GetHDChain() const { return hdChain; }
/* Returns true if HD is enabled */
- bool IsHDEnabled();
+ bool IsHDEnabled() const;
/* Generates a new HD master key (will not be activated) */
CPubKey GenerateNewHDMasterKey();
@@ -1012,6 +1053,10 @@ public:
pwallet = pwalletIn;
}
+ CReserveKey() = default;
+ CReserveKey(const CReserveKey&) = delete;
+ CReserveKey& operator=(const CReserveKey&) = delete;
+
~CReserveKey()
{
ReturnKey();
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 44a01d4a36..d017965385 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -22,8 +22,6 @@
#include <boost/foreach.hpp>
#include <boost/thread.hpp>
-using namespace std;
-
static uint64_t nAccountingEntryNumber = 0;
static std::atomic<unsigned int> nWalletDBUpdateCounter;
@@ -32,30 +30,30 @@ static std::atomic<unsigned int> nWalletDBUpdateCounter;
// CWalletDB
//
-bool CWalletDB::WriteName(const string& strAddress, const string& strName)
+bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
{
nWalletDBUpdateCounter++;
- return Write(make_pair(string("name"), strAddress), strName);
+ return Write(make_pair(std::string("name"), strAddress), strName);
}
-bool CWalletDB::EraseName(const string& strAddress)
+bool CWalletDB::EraseName(const std::string& strAddress)
{
// This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return.
nWalletDBUpdateCounter++;
- return Erase(make_pair(string("name"), strAddress));
+ return Erase(make_pair(std::string("name"), strAddress));
}
-bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
+bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
{
nWalletDBUpdateCounter++;
- return Write(make_pair(string("purpose"), strAddress), strPurpose);
+ return Write(make_pair(std::string("purpose"), strAddress), strPurpose);
}
-bool CWalletDB::ErasePurpose(const string& strPurpose)
+bool CWalletDB::ErasePurpose(const std::string& strPurpose)
{
nWalletDBUpdateCounter++;
- return Erase(make_pair(string("purpose"), strPurpose));
+ return Erase(make_pair(std::string("purpose"), strPurpose));
}
bool CWalletDB::WriteTx(const CWalletTx& wtx)
@@ -183,15 +181,15 @@ bool CWalletDB::WriteMinVersion(int nVersion)
return Write(std::string("minversion"), nVersion);
}
-bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
+bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
{
account.SetNull();
- return Read(make_pair(string("acc"), strAccount), account);
+ return Read(make_pair(std::string("acc"), strAccount), account);
}
-bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
+bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
{
- return Write(make_pair(string("acc"), strAccount), account);
+ return Write(make_pair(std::string("acc"), strAccount), account);
}
bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
@@ -204,9 +202,9 @@ bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
}
-CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
+CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
{
- list<CAccountingEntry> entries;
+ std::list<CAccountingEntry> entries;
ListAccountCreditDebit(strAccount, entries);
CAmount nCreditDebit = 0;
@@ -216,20 +214,20 @@ CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
return nCreditDebit;
}
-void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
+void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
{
bool fAllAccounts = (strAccount == "*");
Dbc* pcursor = GetCursor();
if (!pcursor)
- throw runtime_error(std::string(__func__) + ": cannot create DB cursor");
+ throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
bool setRange = true;
while (true)
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (setRange)
- ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
+ ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange);
setRange = false;
@@ -238,11 +236,11 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
else if (ret != 0)
{
pcursor->close();
- throw runtime_error(std::string(__func__) + ": error scanning DB");
+ throw std::runtime_error(std::string(__func__) + ": error scanning DB");
}
// Unserialize
- string strType;
+ std::string strType;
ssKey >> strType;
if (strType != "acentry")
break;
@@ -268,7 +266,7 @@ public:
bool fIsEncrypted;
bool fAnyUnordered;
int nFileVersion;
- vector<uint256> vWalletUpgrade;
+ std::vector<uint256> vWalletUpgrade;
CWalletScanState() {
nKeys = nCKeys = nWatchKeys = nKeyMeta = 0;
@@ -280,7 +278,7 @@ public:
bool
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
- CWalletScanState &wss, string& strType, string& strErr)
+ CWalletScanState &wss, std::string& strType, std::string& strErr)
{
try {
// Unserialize
@@ -289,13 +287,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> strType;
if (strType == "name")
{
- string strAddress;
+ std::string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
}
else if (strType == "purpose")
{
- string strAddress;
+ std::string strAddress;
ssKey >> strAddress;
ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
}
@@ -336,7 +334,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "acentry")
{
- string strAccount;
+ std::string strAccount;
ssKey >> strAccount;
uint64_t nNumber;
ssKey >> nNumber;
@@ -449,7 +447,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
strErr = "Error reading wallet database: CPubKey corrupt";
return false;
}
- vector<unsigned char> vchPrivKey;
+ std::vector<unsigned char> vchPrivKey;
ssValue >> vchPrivKey;
wss.nCKeys++;
@@ -546,7 +544,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
return true;
}
-static bool IsKeyType(string strType)
+bool CWalletDB::IsKeyType(const std::string& strType)
{
return (strType== "key" || strType == "wkey" ||
strType == "mkey" || strType == "ckey");
@@ -562,7 +560,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
LOCK(pwallet->cs_wallet);
try {
int nMinVersion = 0;
- if (Read((string)"minversion", nMinVersion))
+ if (Read((std::string)"minversion", nMinVersion))
{
if (nMinVersion > CLIENT_VERSION)
return DB_TOO_NEW;
@@ -592,7 +590,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
}
// Try to be tolerant of single corrupt records:
- string strType, strErr;
+ std::string strType, strErr;
if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
{
// losing keys is considered a catastrophic error, anything else
@@ -659,14 +657,14 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
return result;
}
-DBErrors CWalletDB::FindWalletTx(vector<uint256>& vTxHash, vector<CWalletTx>& vWtx)
+DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
{
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
try {
int nMinVersion = 0;
- if (Read((string)"minversion", nMinVersion))
+ if (Read((std::string)"minversion", nMinVersion))
{
if (nMinVersion > CLIENT_VERSION)
return DB_TOO_NEW;
@@ -694,7 +692,7 @@ DBErrors CWalletDB::FindWalletTx(vector<uint256>& vTxHash, vector<CWalletTx>& vW
return DB_CORRUPT;
}
- string strType;
+ std::string strType;
ssKey >> strType;
if (strType == "tx") {
uint256 hash;
@@ -722,11 +720,11 @@ DBErrors CWalletDB::FindWalletTx(vector<uint256>& vTxHash, vector<CWalletTx>& vW
return result;
}
-DBErrors CWalletDB::ZapSelectTx(vector<uint256>& vTxHashIn, vector<uint256>& vTxHashOut)
+DBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
{
// build list of wallet TXs and hashes
- vector<uint256> vTxHash;
- vector<CWalletTx> vWtx;
+ std::vector<uint256> vTxHash;
+ std::vector<CWalletTx> vWtx;
DBErrors err = FindWalletTx(vTxHash, vWtx);
if (err != DB_LOAD_OK) {
return err;
@@ -737,7 +735,7 @@ DBErrors CWalletDB::ZapSelectTx(vector<uint256>& vTxHashIn, vector<uint256>& vTx
// erase each matching wallet TX
bool delerror = false;
- vector<uint256>::iterator it = vTxHashIn.begin();
+ std::vector<uint256>::iterator it = vTxHashIn.begin();
BOOST_FOREACH (uint256 hash, vTxHash) {
while (it < vTxHashIn.end() && (*it) < hash) {
it++;
@@ -760,10 +758,10 @@ DBErrors CWalletDB::ZapSelectTx(vector<uint256>& vTxHashIn, vector<uint256>& vTx
return DB_LOAD_OK;
}
-DBErrors CWalletDB::ZapWalletTx(vector<CWalletTx>& vWtx)
+DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
// build list of wallet TXs
- vector<uint256> vTxHash;
+ std::vector<uint256> vTxHash;
DBErrors err = FindWalletTx(vTxHash, vWtx);
if (err != DB_LOAD_OK)
return err;
@@ -777,156 +775,81 @@ DBErrors CWalletDB::ZapWalletTx(vector<CWalletTx>& vWtx)
return DB_LOAD_OK;
}
-void ThreadFlushWalletDB()
+void MaybeCompactWalletDB()
{
- // Make this thread recognisable as the wallet flushing thread
- RenameThread("bitcoin-wallet");
-
- static bool fOneThread;
- if (fOneThread)
+ static std::atomic<bool> fOneThread;
+ if (fOneThread.exchange(true)) {
return;
- fOneThread = true;
- if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
+ }
+ if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
return;
+ }
- unsigned int nLastSeen = CWalletDB::GetUpdateCounter();
- unsigned int nLastFlushed = CWalletDB::GetUpdateCounter();
- int64_t nLastWalletUpdate = GetTime();
- while (true)
- {
- MilliSleep(500);
-
- if (nLastSeen != CWalletDB::GetUpdateCounter())
- {
- nLastSeen = CWalletDB::GetUpdateCounter();
- nLastWalletUpdate = GetTime();
- }
+ static unsigned int nLastSeen = CWalletDB::GetUpdateCounter();
+ static unsigned int nLastFlushed = CWalletDB::GetUpdateCounter();
+ static int64_t nLastWalletUpdate = GetTime();
- if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
- {
- TRY_LOCK(bitdb.cs_db,lockDb);
- if (lockDb)
- {
- // Don't do this if any databases are in use
- int nRefCount = 0;
- map<string, int>::iterator mi = bitdb.mapFileUseCount.begin();
- while (mi != bitdb.mapFileUseCount.end())
- {
- nRefCount += (*mi).second;
- mi++;
- }
+ if (nLastSeen != CWalletDB::GetUpdateCounter())
+ {
+ nLastSeen = CWalletDB::GetUpdateCounter();
+ nLastWalletUpdate = GetTime();
+ }
- if (nRefCount == 0)
- {
- boost::this_thread::interruption_point();
- const std::string& strFile = pwalletMain->strWalletFile;
- map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile);
- if (_mi != bitdb.mapFileUseCount.end())
- {
- LogPrint("db", "Flushing %s\n", strFile);
- nLastFlushed = CWalletDB::GetUpdateCounter();
- int64_t nStart = GetTimeMillis();
-
- // Flush wallet file so it's self contained
- bitdb.CloseDb(strFile);
- bitdb.CheckpointLSN(strFile);
-
- bitdb.mapFileUseCount.erase(_mi++);
- LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
- }
- }
- }
- }
+ if (nLastFlushed != CWalletDB::GetUpdateCounter() && GetTime() - nLastWalletUpdate >= 2)
+ {
+ const std::string& strFile = pwalletMain->strWalletFile;
+ if (CDB::PeriodicFlush(strFile))
+ nLastFlushed = CWalletDB::GetUpdateCounter();
}
+ fOneThread = false;
}
//
// Try to (very carefully!) recover wallet file if there is a problem.
//
-bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys)
-{
- // Recovery procedure:
- // move wallet file to wallet.timestamp.bak
- // Call Salvage with fAggressive=true to
- // get as much data as possible.
- // Rewrite salvaged data to fresh wallet file
- // Set -rescan so any missing transactions will be
- // found.
- int64_t now = GetTime();
- std::string newFilename = strprintf("wallet.%d.bak", now);
-
- int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL,
- newFilename.c_str(), DB_AUTO_COMMIT);
- if (result == 0)
- LogPrintf("Renamed %s to %s\n", filename, newFilename);
- else
- {
- LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
- return false;
- }
+bool CWalletDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue))
+{
+ return CDB::Recover(filename, callbackDataIn, recoverKVcallback);
+}
+
+bool CWalletDB::Recover(const std::string& filename)
+{
+ // recover without a key filter callback
+ // results in recovering all record types
+ return CWalletDB::Recover(filename, NULL, NULL);
+}
- std::vector<CDBEnv::KeyValPair> salvagedData;
- bool fSuccess = dbenv.Salvage(newFilename, true, salvagedData);
- if (salvagedData.empty())
+bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
+{
+ CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
+ CWalletScanState dummyWss;
+ std::string strType, strErr;
+ bool fReadOK;
{
- LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
- return false;
+ // Required in LoadKeyMetadata():
+ LOCK(dummyWallet->cs_wallet);
+ fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
+ dummyWss, strType, strErr);
}
- LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
-
- std::unique_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
- int ret = pdbCopy->open(NULL, // Txn pointer
- filename.c_str(), // Filename
- "main", // Logical db name
- DB_BTREE, // Database type
- DB_CREATE, // Flags
- 0);
- if (ret > 0)
+ if (!IsKeyType(strType) && strType != "hdchain")
+ return false;
+ if (!fReadOK)
{
- LogPrintf("Cannot create database file %s\n", filename);
+ LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
return false;
}
- CWallet dummyWallet;
- CWalletScanState wss;
- DbTxn* ptxn = dbenv.TxnBegin();
- BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
- {
- if (fOnlyKeys)
- {
- CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
- CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
- string strType, strErr;
- bool fReadOK;
- {
- // Required in LoadKeyMetadata():
- LOCK(dummyWallet.cs_wallet);
- fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
- wss, strType, strErr);
- }
- if (!IsKeyType(strType) && strType != "hdchain")
- continue;
- if (!fReadOK)
- {
- LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
- continue;
- }
- }
- Dbt datKey(&row.first[0], row.first.size());
- Dbt datValue(&row.second[0], row.second.size());
- int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
- if (ret2 > 0)
- fSuccess = false;
- }
- ptxn->commit(0);
- pdbCopy->close(0);
+ return true;
+}
- return fSuccess;
+bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& errorStr)
+{
+ return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);
}
-bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
+bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& warningStr, std::string& errorStr)
{
- return CWalletDB::Recover(dbenv, filename, false);
+ return CDB::VerifyDatabaseFile(walletFile, dataDir, errorStr, warningStr, CWalletDB::Recover);
}
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 2d95df91da..4d7dfb727e 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -170,8 +170,18 @@ public:
DBErrors FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
DBErrors ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut);
- static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
- static bool Recover(CDBEnv& dbenv, const std::string& filename);
+ /* Try to (very carefully!) recover wallet database (with a possible key type filter) */
+ static bool Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue));
+ /* Recover convenience-function to bypass the key filter callback, called when verify fails, recovers everything */
+ static bool Recover(const std::string& filename);
+ /* Recover filter (used as callback), will only let keys (cryptographical keys) as KV/key-type pass through */
+ static bool RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue);
+ /* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
+ static bool IsKeyType(const std::string& strType);
+ /* verifies the database environment */
+ static bool VerifyEnvironment(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& errorStr);
+ /* verifies the database file */
+ static bool VerifyDatabaseFile(const std::string& walletFile, const boost::filesystem::path& dataDir, std::string& warningStr, std::string& errorStr);
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);
@@ -183,6 +193,7 @@ private:
void operator=(const CWalletDB&);
};
-void ThreadFlushWalletDB();
+//! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
+void MaybeCompactWalletDB();
#endif // BITCOIN_WALLET_WALLETDB_H