aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--CONTRIBUTING.md4
-rw-r--r--configure.ac25
-rwxr-xr-xcontrib/devtools/check-doc.py3
-rwxr-xr-xcontrib/devtools/github-merge.py49
-rwxr-xr-xcontrib/devtools/security-check.py2
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/devtools/update-translations.py4
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml9
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml9
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml9
-rw-r--r--contrib/gitian-keys/meshcollider-key.pgp51
-rw-r--r--contrib/linearize/example-linearize.cfg7
-rwxr-xr-xcontrib/linearize/linearize-hashes.py4
-rw-r--r--contrib/rpm/bitcoin.spec4
-rwxr-xr-xcontrib/seeds/generate-seeds.py2
-rwxr-xr-xcontrib/zmq/zmq_sub.py2
-rwxr-xr-xcontrib/zmq/zmq_sub3.4.py2
-rw-r--r--doc/README.md1
-rw-r--r--doc/REST-interface.md3
-rw-r--r--doc/build-openbsd.md18
-rw-r--r--doc/build-osx.md4
-rw-r--r--doc/build-unix.md6
-rw-r--r--doc/build-windows.md5
-rw-r--r--doc/dependencies.md32
-rw-r--r--doc/developer-notes.md29
-rw-r--r--doc/init.md28
-rw-r--r--doc/zmq.md2
-rwxr-xr-xshare/qt/extract_strings_qt.py2
-rw-r--r--src/Makefile.am11
-rw-r--r--src/Makefile.qttest.include6
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/addrdb.h2
-rw-r--r--src/arith_uint256.h2
-rw-r--r--src/base58.cpp61
-rw-r--r--src/base58.h29
-rw-r--r--src/bench/checkqueue.cpp2
-rw-r--r--src/bitcoin-cli.cpp20
-rw-r--r--src/bitcoin-tx.cpp25
-rw-r--r--src/blockencodings.h6
-rw-r--r--src/chain.h2
-rw-r--r--src/chainparamsbase.cpp2
-rw-r--r--src/checkqueue.h2
-rw-r--r--src/compat/byteswap.h2
-rw-r--r--src/compat/endian.h4
-rw-r--r--src/compressor.h4
-rw-r--r--src/core_io.h2
-rw-r--r--src/core_write.cpp11
-rw-r--r--src/crypto/aes.h8
-rw-r--r--src/crypto/common.h2
-rw-r--r--src/crypto/hmac_sha256.h2
-rw-r--r--src/crypto/sha256.cpp4
-rw-r--r--src/cuckoocache.h8
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/dbwrapper.h4
-rw-r--r--src/hash.h2
-rw-r--r--src/httprpc.cpp2
-rw-r--r--src/httpserver.cpp6
-rw-r--r--src/httpserver.h2
-rw-r--r--src/init.cpp57
-rw-r--r--src/key.h2
-rw-r--r--src/keystore.h14
-rw-r--r--src/limitedmap.h2
-rw-r--r--src/miner.cpp1
-rw-r--r--src/miner.h10
-rw-r--r--src/net.cpp19
-rw-r--r--src/net.h4
-rw-r--r--src/net_processing.cpp6
-rw-r--r--src/net_processing.h2
-rw-r--r--src/netaddress.h8
-rw-r--r--src/netbase.h2
-rw-r--r--src/netmessagemaker.h2
-rw-r--r--src/policy/feerate.h1
-rw-r--r--src/policy/fees.h2
-rw-r--r--src/policy/policy.cpp33
-rw-r--r--src/prevector.h6
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/primitives/transaction.cpp8
-rw-r--r--src/primitives/transaction.h4
-rw-r--r--src/protocol.h2
-rw-r--r--src/pubkey.h4
-rw-r--r--src/qt/addresstablemodel.cpp22
-rw-r--r--src/qt/bitcoinaddressvalidator.cpp4
-rw-r--r--src/qt/bitcoingui.cpp1
-rw-r--r--src/qt/callback.h2
-rw-r--r--src/qt/coincontroldialog.cpp5
-rw-r--r--src/qt/coincontroldialog.h6
-rw-r--r--src/qt/forms/optionsdialog.ui12
-rw-r--r--src/qt/guiutil.cpp5
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/macdockiconhandler.mm8
-rw-r--r--src/qt/macnotificationhandler.mm2
-rw-r--r--src/qt/notificator.cpp2
-rw-r--r--src/qt/optionsdialog.cpp6
-rw-r--r--src/qt/overviewpage.cpp2
-rw-r--r--src/qt/paymentrequestplus.cpp2
-rw-r--r--src/qt/paymentserver.cpp15
-rw-r--r--src/qt/paymentserver.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp23
-rw-r--r--src/qt/signverifymessagedialog.cpp24
-rw-r--r--src/qt/test/rpcnestedtests.cpp10
-rw-r--r--src/qt/test/test_main.cpp6
-rw-r--r--src/qt/test/wallettests.cpp8
-rw-r--r--src/qt/transactiondesc.cpp11
-rw-r--r--src/qt/transactionrecord.cpp4
-rw-r--r--src/qt/utilitydialog.h2
-rw-r--r--src/qt/walletmodel.cpp24
-rw-r--r--src/qt/walletmodel.h2
-rw-r--r--src/random.cpp6
-rw-r--r--src/rest.cpp23
-rw-r--r--src/reverse_iterator.h2
-rw-r--r--src/rpc/blockchain.cpp94
-rw-r--r--src/rpc/mining.cpp40
-rw-r--r--src/rpc/misc.cpp165
-rw-r--r--src/rpc/net.cpp38
-rw-r--r--src/rpc/protocol.cpp21
-rw-r--r--src/rpc/protocol.h2
-rw-r--r--src/rpc/rawtransaction.cpp67
-rw-r--r--src/rpc/safemode.cpp14
-rw-r--r--src/rpc/safemode.h12
-rw-r--r--src/rpc/server.cpp15
-rw-r--r--src/rpc/server.h4
-rw-r--r--src/scheduler.cpp2
-rw-r--r--src/scheduler.h2
-rw-r--r--src/script/interpreter.h2
-rw-r--r--src/script/sign.h4
-rw-r--r--src/script/standard.cpp9
-rw-r--r--src/script/standard.h67
-rw-r--r--src/serialize.h6
-rw-r--r--src/streams.h4
-rw-r--r--src/support/lockedpool.h4
-rw-r--r--src/sync.h4
-rw-r--r--src/test/README.md5
-rw-r--r--src/test/addrman_tests.cpp2
-rw-r--r--src/test/base58_tests.cpp36
-rw-r--r--src/test/bip32_tests.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp4
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/data/tx_valid.json2
-rw-r--r--src/test/dbwrapper_tests.cpp2
-rw-r--r--src/test/key_tests.cpp27
-rw-r--r--src/test/scriptnum_tests.cpp8
-rw-r--r--src/test/sighash_tests.cpp6
-rw-r--r--src/test/test_bitcoin.cpp4
-rw-r--r--src/test/test_bitcoin.h4
-rw-r--r--src/test/test_bitcoin_main.cpp8
-rw-r--r--src/test/testutil.cpp15
-rw-r--r--src/test/testutil.h15
-rw-r--r--src/test/util_tests.cpp25
-rw-r--r--src/test/versionbits_tests.cpp8
-rw-r--r--src/tinyformat.h8
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h6
-rw-r--r--src/txmempool.cpp5
-rw-r--r--src/txmempool.h15
-rw-r--r--src/uint256.h4
-rw-r--r--src/undo.h4
-rw-r--r--src/univalue/lib/univalue_utffilter.h2
-rw-r--r--src/utilstrencodings.cpp13
-rw-r--r--src/utilstrencodings.h6
-rw-r--r--src/validation.cpp53
-rw-r--r--src/validation.h5
-rw-r--r--src/validationinterface.cpp2
-rw-r--r--src/versionbits.cpp2
-rw-r--r--src/wallet/crypter.h2
-rw-r--r--src/wallet/db.cpp2
-rw-r--r--src/wallet/feebumper.cpp14
-rw-r--r--src/wallet/fees.cpp89
-rw-r--r--src/wallet/fees.h34
-rw-r--r--src/wallet/init.cpp247
-rw-r--r--src/wallet/init.h25
-rw-r--r--src/wallet/rpcdump.cpp85
-rw-r--r--src/wallet/rpcwallet.cpp392
-rw-r--r--src/wallet/test/crypto_tests.cpp133
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp17
-rw-r--r--src/wallet/wallet.cpp440
-rw-r--r--src/wallet/wallet.h42
-rw-r--r--src/wallet/walletdb.cpp23
-rw-r--r--src/wallet/walletdb.h6
-rw-r--r--src/zmq/zmqnotificationinterface.h2
-rw-r--r--test/functional/README.md6
-rwxr-xr-xtest/functional/abandonconflict.py10
-rwxr-xr-xtest/functional/assumevalid.py12
-rwxr-xr-xtest/functional/bip65-cltv-p2p.py8
-rwxr-xr-xtest/functional/bip68-112-113-p2p.py4
-rwxr-xr-xtest/functional/bip68-sequence.py6
-rwxr-xr-xtest/functional/bip9-softforks.py6
-rwxr-xr-xtest/functional/bipdersig-p2p.py8
-rwxr-xr-xtest/functional/bitcoin_cli.py39
-rwxr-xr-xtest/functional/blockchain.py12
-rwxr-xr-xtest/functional/bumpfee.py16
-rwxr-xr-xtest/functional/create_cache.py7
-rwxr-xr-xtest/functional/dbcrash.py11
-rwxr-xr-xtest/functional/decodescript.py4
-rwxr-xr-xtest/functional/disablewallet.py5
-rwxr-xr-xtest/functional/disconnect_ban.py23
-rwxr-xr-xtest/functional/example_test.py16
-rwxr-xr-xtest/functional/forknotify.py18
-rwxr-xr-xtest/functional/fundrawtransaction.py14
-rwxr-xr-xtest/functional/getblocktemplate_longpoll.py6
-rwxr-xr-xtest/functional/getchaintips.py5
-rwxr-xr-xtest/functional/httpbasics.py4
-rwxr-xr-xtest/functional/import-rescan.py7
-rwxr-xr-xtest/functional/importmulti.py18
-rwxr-xr-xtest/functional/importprunedfunds.py10
-rwxr-xr-xtest/functional/invalidateblock.py4
-rwxr-xr-xtest/functional/invalidblockrequest.py4
-rwxr-xr-xtest/functional/invalidtxrequest.py4
-rwxr-xr-xtest/functional/keypool-topup.py9
-rwxr-xr-xtest/functional/keypool.py9
-rwxr-xr-xtest/functional/listsinceblock.py6
-rwxr-xr-xtest/functional/listtransactions.py10
-rwxr-xr-xtest/functional/maxuploadtarget.py5
-rwxr-xr-xtest/functional/mempool_limit.py4
-rwxr-xr-xtest/functional/mempool_packages.py6
-rwxr-xr-xtest/functional/mempool_persist.py50
-rwxr-xr-xtest/functional/mempool_reorg.py4
-rwxr-xr-xtest/functional/mempool_resurrect_test.py6
-rwxr-xr-xtest/functional/mempool_spendcoinbase.py5
-rwxr-xr-xtest/functional/merkle_blocks.py6
-rwxr-xr-xtest/functional/minchainwork.py81
-rwxr-xr-xtest/functional/mining.py24
-rwxr-xr-xtest/functional/multi_rpc.py5
-rwxr-xr-xtest/functional/multiwallet.py12
-rwxr-xr-xtest/functional/net.py4
-rwxr-xr-xtest/functional/nulldummy.py3
-rwxr-xr-xtest/functional/p2p-acceptblock.py3
-rwxr-xr-xtest/functional/p2p-compactblocks.py53
-rwxr-xr-xtest/functional/p2p-feefilter.py5
-rwxr-xr-xtest/functional/p2p-fullblocktest.py23
-rwxr-xr-xtest/functional/p2p-leaktests.py17
-rwxr-xr-xtest/functional/p2p-mempool.py4
-rwxr-xr-xtest/functional/p2p-segwit.py11
-rwxr-xr-xtest/functional/p2p-timeouts.py3
-rwxr-xr-xtest/functional/p2p-versionbits-warning.py10
-rwxr-xr-xtest/functional/preciousblock.py9
-rwxr-xr-xtest/functional/prioritise_transaction.py4
-rwxr-xr-xtest/functional/proxy_test.py8
-rwxr-xr-xtest/functional/pruning.py28
-rwxr-xr-xtest/functional/rawtransactions.py6
-rwxr-xr-xtest/functional/receivedby.py11
-rwxr-xr-xtest/functional/reindex.py5
-rwxr-xr-xtest/functional/replace-by-fee.py10
-rwxr-xr-xtest/functional/resendwallettransactions.py8
-rwxr-xr-xtest/functional/rest.py3
-rwxr-xr-xtest/functional/rpcbind_test.py18
-rwxr-xr-xtest/functional/rpcnamedargs.py15
-rwxr-xr-xtest/functional/segwit.py8
-rwxr-xr-xtest/functional/sendheaders.py9
-rwxr-xr-xtest/functional/signmessages.py25
-rwxr-xr-xtest/functional/signrawtransactions.py3
-rwxr-xr-xtest/functional/smartfees.py94
-rw-r--r--test/functional/test_framework/address.py10
-rw-r--r--test/functional/test_framework/bignum.py39
-rw-r--r--test/functional/test_framework/blockstore.py10
-rwxr-xr-xtest/functional/test_framework/comptool.py12
-rwxr-xr-xtest/functional/test_framework/mininode.py44
-rw-r--r--test/functional/test_framework/netutil.py20
-rw-r--r--test/functional/test_framework/script.py245
-rw-r--r--test/functional/test_framework/socks5.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py196
-rwxr-xr-xtest/functional/test_framework/test_node.py98
-rw-r--r--test/functional/test_framework/util.py51
-rwxr-xr-xtest/functional/test_runner.py3
-rwxr-xr-xtest/functional/txn_clone.py5
-rwxr-xr-xtest/functional/txn_doublespend.py5
-rwxr-xr-xtest/functional/uptime.py4
-rwxr-xr-xtest/functional/wallet-accounts.py4
-rwxr-xr-xtest/functional/wallet-dump.py12
-rwxr-xr-xtest/functional/wallet-encryption.py8
-rwxr-xr-xtest/functional/wallet-hd.py21
-rwxr-xr-xtest/functional/wallet.py94
-rwxr-xr-xtest/functional/walletbackup.py12
-rwxr-xr-xtest/functional/zapwallettxes.py10
-rwxr-xr-xtest/functional/zmq_test.py9
277 files changed, 2602 insertions, 2667 deletions
diff --git a/.travis.yml b/.travis.yml
index 12f91096cc..dadac3165e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,7 +34,7 @@ env:
# x86_64 Linux, 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"
# 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"
+ - 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 --enable-werror" OSX_SDK=10.11 GOAL="deploy"
before_install:
- export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g")
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4e67af6278..56521a5f7d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -81,6 +81,10 @@ Examples:
Qt: Add feed bump button
Trivial: Fix typo in init.cpp
+Note that translations should not be submitted as pull requests, please see
+[Translation Process](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md)
+for more information on helping with translations.
+
If a pull request is specifically not to be considered for merging (yet) please
prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists)
in the body of the pull request to indicate tasks are pending.
diff --git a/configure.ac b/configure.ac
index e5ed938947..e3e71044da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -177,14 +177,14 @@ AC_ARG_ENABLE([glibc-back-compat],
[use_glibc_compat=$enableval],
[use_glibc_compat=no])
-AC_ARG_ENABLE([experimental-asm],
- [AS_HELP_STRING([--enable-experimental-asm],
- [Enable experimental assembly routines (default is no)])],
- [experimental_asm=$enableval],
- [experimental_asm=no])
-
-if test "x$experimental_asm" = xyes; then
- AC_DEFINE(EXPERIMENTAL_ASM, 1, [Define this symbol to build in experimental assembly routines])
+AC_ARG_ENABLE([asm],
+ [AS_HELP_STRING([--enable-asm],
+ [Enable assembly routines (default is yes)])],
+ [use_asm=$enableval],
+ [use_asm=yes])
+
+if test "x$use_asm" = xyes; then
+ AC_DEFINE(USE_ASM, 1, [Define this symbol to build in assembly routines])
fi
AC_ARG_WITH([system-univalue],
@@ -827,14 +827,14 @@ TEMP_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
AC_MSG_CHECKING([for mismatched boost c++11 scoped enums])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
- #include "boost/config.hpp"
- #include "boost/version.hpp"
+ #include <boost/config.hpp>
+ #include <boost/version.hpp>
#if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700
#define BOOST_NO_SCOPED_ENUMS
#define BOOST_NO_CXX11_SCOPED_ENUMS
#define CHECK
#endif
- #include "boost/filesystem.hpp"
+ #include <boost/filesystem.hpp>
]],[[
#if defined(CHECK)
boost::filesystem::copy_file("foo", "bar");
@@ -1179,7 +1179,7 @@ AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes])
AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes])
AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes])
AM_CONDITIONAL([ENABLE_HWCRC32],[test x$enable_hwcrc32 = xyes])
-AM_CONDITIONAL([EXPERIMENTAL_ASM],[test x$experimental_asm = xyes])
+AM_CONDITIONAL([USE_ASM],[test x$use_asm = xyes])
AC_DEFINE(CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MAJOR, [Major version])
AC_DEFINE(CLIENT_VERSION_MINOR, _CLIENT_VERSION_MINOR, [Minor version])
@@ -1297,6 +1297,7 @@ echo " with zmq = $use_zmq"
echo " with test = $use_tests"
echo " with bench = $use_bench"
echo " with upnp = $use_upnp"
+echo " use asm = $use_asm"
echo " debug enabled = $enable_debug"
echo " werror = $enable_werror"
echo
diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py
index 3b7a8f9a61..3279dc3612 100755
--- a/contrib/devtools/check-doc.py
+++ b/contrib/devtools/check-doc.py
@@ -12,6 +12,7 @@ Author: @MarcoFalke
from subprocess import check_output
import re
+import sys
FOLDER_GREP = 'src'
FOLDER_TEST = 'src/test/'
@@ -39,7 +40,7 @@ def main():
print "Args unknown : %s" % len(args_unknown)
print args_unknown
- exit(len(args_need_doc))
+ sys.exit(len(args_need_doc))
if __name__ == "__main__":
main()
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index c664cf81fa..2941d2cb6d 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -20,6 +20,7 @@ from sys import stdin,stdout,stderr
import argparse
import hashlib
import subprocess
+import sys
import json,codecs
try:
from urllib.request import Request,urlopen
@@ -158,11 +159,11 @@ def main():
if repo is None:
print("ERROR: No repository configured. Use this command to set:", file=stderr)
print("git config githubmerge.repository <owner>/<repo>", file=stderr)
- exit(1)
+ sys.exit(1)
if signingkey is None:
print("ERROR: No GPG signing key set. Set one using:",file=stderr)
print("git config --global user.signingkey <key>",file=stderr)
- exit(1)
+ sys.exit(1)
host_repo = host+":"+repo # shortcut for push/pull target
@@ -173,7 +174,7 @@ def main():
# Receive pull information from github
info = retrieve_pr_info(repo,pull)
if info is None:
- exit(1)
+ sys.exit(1)
title = info['title'].strip()
body = info['body'].strip()
# precedence order for destination branch argument:
@@ -194,27 +195,23 @@ def main():
subprocess.check_call([GIT,'checkout','-q',branch])
except subprocess.CalledProcessError as e:
print("ERROR: Cannot check out branch %s." % (branch), file=stderr)
- exit(3)
+ sys.exit(3)
try:
- subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*'])
+ subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*',
+ '+refs/heads/'+branch+':refs/heads/'+base_branch])
except subprocess.CalledProcessError as e:
- print("ERROR: Cannot find pull request #%s on %s." % (pull,host_repo), file=stderr)
- exit(3)
+ print("ERROR: Cannot find pull request #%s or branch %s on %s." % (pull,branch,host_repo), file=stderr)
+ sys.exit(3)
try:
subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+head_branch], stdout=devnull, stderr=stdout)
except subprocess.CalledProcessError as e:
print("ERROR: Cannot find head of pull request #%s on %s." % (pull,host_repo), file=stderr)
- exit(3)
+ sys.exit(3)
try:
subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+merge_branch], stdout=devnull, stderr=stdout)
except subprocess.CalledProcessError as e:
print("ERROR: Cannot find merge of pull request #%s on %s." % (pull,host_repo), file=stderr)
- exit(3)
- try:
- subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/heads/'+branch+':refs/heads/'+base_branch])
- except subprocess.CalledProcessError as e:
- print("ERROR: Cannot find branch %s on %s." % (branch,host_repo), file=stderr)
- exit(3)
+ sys.exit(3)
subprocess.check_call([GIT,'checkout','-q',base_branch])
subprocess.call([GIT,'branch','-q','-D',local_merge_branch], stderr=devnull)
subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch])
@@ -236,30 +233,30 @@ def main():
except subprocess.CalledProcessError as e:
print("ERROR: Cannot be merged cleanly.",file=stderr)
subprocess.check_call([GIT,'merge','--abort'])
- exit(4)
+ sys.exit(4)
logmsg = subprocess.check_output([GIT,'log','--pretty=format:%s','-n','1']).decode('utf-8')
if logmsg.rstrip() != firstline.rstrip():
print("ERROR: Creating merge failed (already merged?).",file=stderr)
- exit(4)
+ sys.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)
+ sys.exit(4)
# Put tree SHA512 into the message
try:
first_sha512 = tree_sha512sum()
message += '\n\nTree-SHA512: ' + first_sha512
except subprocess.CalledProcessError as e:
- printf("ERROR: Unable to compute tree hash")
- exit(4)
+ print("ERROR: Unable to compute tree hash")
+ sys.exit(4)
try:
subprocess.check_call([GIT,'commit','--amend','-m',message.encode('utf-8')])
except subprocess.CalledProcessError as e:
- printf("ERROR: Cannot update message.",file=stderr)
- exit(4)
+ print("ERROR: Cannot update message.", file=stderr)
+ sys.exit(4)
print_merge_details(pull, title, branch, base_branch, head_branch)
print()
@@ -268,7 +265,7 @@ def main():
if testcmd:
if subprocess.call(testcmd,shell=True):
print("ERROR: Running %s failed." % testcmd,file=stderr)
- exit(5)
+ sys.exit(5)
# Show the created merge.
diff = subprocess.check_output([GIT,'diff',merge_branch+'..'+local_merge_branch])
@@ -279,7 +276,7 @@ def main():
if reply.lower() == 'ignore':
print("Difference with github ignored.",file=stderr)
else:
- exit(6)
+ sys.exit(6)
else:
# Verify the result manually.
print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr)
@@ -292,7 +289,7 @@ def main():
second_sha512 = tree_sha512sum()
if first_sha512 != second_sha512:
print("ERROR: Tree hash changed unexpectedly",file=stderr)
- exit(8)
+ sys.exit(8)
# Sign the merge commit.
print_merge_details(pull, title, branch, base_branch, head_branch)
@@ -306,7 +303,7 @@ def main():
print("Error while signing, asking again.",file=stderr)
elif reply == 'x':
print("Not signing off on merge, exiting.",file=stderr)
- exit(1)
+ sys.exit(1)
# Put the result in branch.
subprocess.check_call([GIT,'checkout','-q',branch])
@@ -326,7 +323,7 @@ def main():
subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch])
break
elif reply == 'x':
- exit(1)
+ sys.exit(1)
if __name__ == '__main__':
main()
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index c90541e271..6eb5667453 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -212,5 +212,5 @@ if __name__ == '__main__':
except IOError:
print('%s: cannot open' % filename)
retval = 1
- exit(retval)
+ sys.exit(retval)
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 8f8685006e..98daa1bd76 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -159,6 +159,6 @@ if __name__ == '__main__':
print('%s: NEEDED library %s is not allowed' % (filename, library_name.decode('utf-8')))
retval = 1
- exit(retval)
+ sys.exit(retval)
diff --git a/contrib/devtools/update-translations.py b/contrib/devtools/update-translations.py
index 2011841005..e1924749d2 100755
--- a/contrib/devtools/update-translations.py
+++ b/contrib/devtools/update-translations.py
@@ -36,12 +36,12 @@ def check_at_repository_root():
if not os.path.exists('.git'):
print('No .git directory found')
print('Execute this script at the root of the repository', file=sys.stderr)
- exit(1)
+ sys.exit(1)
def fetch_all_translations():
if subprocess.call([TX, 'pull', '-f', '-a']):
print('Error while fetching translations', file=sys.stderr)
- exit(1)
+ sys.exit(1)
def find_format_specifiers(s):
'''Find all format specifiers in a string.'''
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index 0569c6a771..c80e19edbb 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -132,7 +132,6 @@ script: |
export PATH=${WRAP_DIR}:${PATH}
# Create the release tarball using (arbitrarily) the first host
- export GIT_DIR="$PWD/.git"
./autogen.sh
CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/
make dist
@@ -145,6 +144,9 @@ script: |
find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
popd
+ # Workaround for tarball not building with the bare tag version (prep)
+ make -C src obj/build.h
+
ORIGPATH="$PATH"
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
@@ -155,6 +157,11 @@ script: |
mkdir -p ${INSTALLPATH}
tar --strip-components=1 -xf ../$SOURCEDIST
+ # Workaround for tarball not building with the bare tag version
+ echo '#!/bin/true' >share/genbuild.sh
+ mkdir src/obj
+ cp ../src/obj/build.h src/obj/
+
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}"
make ${MAKEOPTS}
make ${MAKEOPTS} -C src check-security
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index d315173581..cbf286d2cd 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -101,7 +101,6 @@ script: |
export PATH=${WRAP_DIR}:${PATH}
# Create the release tarball using (arbitrarily) the first host
- export GIT_DIR="$PWD/.git"
./autogen.sh
CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/
make dist
@@ -115,6 +114,9 @@ script: |
find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
popd
+ # Workaround for tarball not building with the bare tag version (prep)
+ make -C src obj/build.h
+
ORIGPATH="$PATH"
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
@@ -125,6 +127,11 @@ script: |
mkdir -p ${INSTALLPATH}
tar --strip-components=1 -xf ../$SOURCEDIST
+ # Workaround for tarball not building with the bare tag version
+ echo '#!/bin/true' >share/genbuild.sh
+ mkdir src/obj
+ cp ../src/obj/build.h src/obj/
+
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS}
make ${MAKEOPTS}
make install-strip DESTDIR=${INSTALLPATH}
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index aba46df261..95ff9759c7 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -116,7 +116,6 @@ script: |
export PATH=${WRAP_DIR}:${PATH}
# Create the release tarball using (arbitrarily) the first host
- export GIT_DIR="$PWD/.git"
./autogen.sh
CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/
make dist
@@ -132,6 +131,9 @@ script: |
cp ../$SOURCEDIST $OUTDIR/src
popd
+ # Workaround for tarball not building with the bare tag version (prep)
+ make -C src obj/build.h
+
ORIGPATH="$PATH"
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
@@ -142,6 +144,11 @@ script: |
mkdir -p ${INSTALLPATH}
tar --strip-components=1 -xf ../$SOURCEDIST
+ # Workaround for tarball not building with the bare tag version
+ echo '#!/bin/true' >share/genbuild.sh
+ mkdir src/obj
+ cp ../src/obj/build.h src/obj/
+
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}"
make ${MAKEOPTS}
make ${MAKEOPTS} -C src check-security
diff --git a/contrib/gitian-keys/meshcollider-key.pgp b/contrib/gitian-keys/meshcollider-key.pgp
new file mode 100644
index 0000000000..20963e7e25
--- /dev/null
+++ b/contrib/gitian-keys/meshcollider-key.pgp
@@ -0,0 +1,51 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBFlm5UcBEADFhn2Tcfr7gtsLRj9dzHGPoZYjc8Jy7wceqT8918lqaULJKgDW
+vkEWCVOHRlrr/h1ugldouTRv3k8cdzhCR9YBakVJ3vBmn73CvHQl57jGRSogyqm5
+hb6IXJkBdualnZVFvCDV37VYeyuSYkJ+DL3c2wEjC2gdQKUsc8ePrJZZEMJVScdD
+hoXR/sPnu8P5yHOi56XGJi9395GUmmxJKNucD4HXjSq+7yTTs5GXm4niaKfcKyBy
+kIGN4aEeV8sqzkN8JzNH9fc8i8MPDYLW7SGljpLSnIvIsdBRjXXBHwRnfmGEO7lF
+sVTyepUUYX3GhLcCNhZjoMkpagVjSpQPj1gylSM4EFkmU2AgK/iEzqB7Ay4WC8EE
+E2HrcN0ysjyhuyntFwMa1cze99vtfOIQnVJ8E58AvsOs9+xYz8DkbYntCHDD+Zcv
+y200/knT1jJSZMXkiDciLjGSeFFbh6H+VpaFUKjy3G3yJC4BTXwnACga5/WPsgmK
++Y9gpTXRsZ8Op2teiwl8wI85mNF+2QmQw3uvymfojI8YPmjx2LOCbzkFYIJt20nw
+iP1QMH3vtk+iSbcnexQlOPh03ZtDp3NbkBvBOy7cOc57Nc6IX7TllZicQj0FUjWq
+ctUAU+f5pQuVgS8H3B4XE+Pk1u6/5zX9H0sTi0LzeQ0OdWFcvmZ8mYK5lQARAQAB
+tCNNZXNoQ29sbGlkZXIgPGRvYnNvbnNhNjhAZ21haWwuY29tPokCOAQTAQgALAUC
+WWblRwkQ0wARbhyHWj0CGwMFCR4TOAACGQEECwcJAwUVCAoCAwQWAAECAABJ2Q/8
+D6FMutVLsz55vwy2FjWojcvSpk+BV50YMGYTCdnXZod7V0dP1iQ5+NMcYfpWgJKM
+YbJ2eaWpW2TgsBd12LTjA6BKX3FquN8Y3nKZiknGCLiimDiys0+VuO9ieEH0flhC
+olhGysRmPO5clNmZOzn3yiPgUekw6ejLVUEY8vPCbjojSuLZyjctQR3s/9oOMyvm
+tldJ0waLi3KSOPEDQ8gXfE0QfDf2eMTdlMkbOHS6BlDIre6P5RZ5IJaLwCdzne+W
+aS96CUqVcR3aqil4mG+T+kHf1wF99TZwY+tSXtweGENjc+QGEaR30to+catSc0nz
+KQi3dGCH2Y+rc4VHE1S2Id88M38883mHXUeDMqzV9mHwMA50r/jzcLPybrJA1Qhn
+ZQNWr8zGilmZfWnf2VyiPqZCIAEEFcwg6uNg9Rwy2N3Q/5+vhAVcVNJamMA/dpHa
+hnq8HmZjraPWHL5Q9oL3Ggtc1Jahb8skaUMV26PHkXOxNFhVynghw3ujC3mocKqQ
+stmsg+2m5Wf+TZtmbd8geMWcRpuxovYX2ZmeFPWIU+6p9XpwyiPR4mp5hWn/20dQ
+YAyN/cQhWjDRU2i/HJB1lVnQIsSVsy3eWUJk4htQNHmk8crYocsXb5hgQ2C+JZ0L
+gY2AxoGjqtzKkydTd5GbiCmqqFdW9ngmVerZ6yCbyRK5Ag0EWWblRwEQALdMSVUR
+fCXTW2zCiP7g0Aj6yvyi1Wg1zK0CeRRljXKfgFoAI6IGW9QSSpXPmdsnAQOf7L0Q
+wTTqwWNhKOLV0IWLenbpgIVwfLMkrwn71q9MBJFHiL+PgZLaRxqF5pmW34ZReUj5
+k55Bg49kB98rfyz9K6qNxKLzY0j/8zsCvCgDMpr7U61xfz8Xo3Ds8bRdaFoH3RWR
+wm3ePTe/8Rpm/LWWLlzhnfTpyZCUcOPh5+2yt0twHQ5zlzj7Gp8Il8XNlP6hvfx3
+QGDuFTQ++Utom7T3QLa5E5Yx2iTD7qaNLdpQLZmcHUvdQV0QWSILccEvSJ+vXiE0
+NvlgQIAE1pUuyTGpm97+mBeDC+4PvXUxQqFoOTJiwJxCpIAA0yvloUaZyeT0Toar
+mowVOn0JXfbZRFFdxNUXgz9RbzANB+twGJ/ySh3mQz+Mur/1HqnCpHEjy73yOA9e
+alN2LNvJt92hMdq+QU7I0bNqUS456h6Ft6mOpqG2y57qpl8ZL/MIvMaw3s45hA6p
+7gzi7/TOnoqAkDUPf7lRbYjGgLkcGlimRxyL1SAYKuFgpNnhxk6BNPKdly7MRWF5
+I+oUc5W7HkNefbHw5sdLgYZBQk8JoSwF1K/ES5gvJHWZjCiLAcbyum2W843etfU3
+Qa/3YNt4Gri5zhAoD7U2kAs1ct3hQ6cLmDrxABEBAAGJAjUEGAEIACkFAllm5UcJ
+ENMAEW4ch1o9AhsMBQkeEzgABAsHCQMFFQgKAgMEFgABAgAAWWcP/1ErBIqJ+SFZ
+bL3YyLB9iObLEAUxNQP8bEV6lI9V0XUBhReasxQrMUFEXsFoFU6i/qlyfQFsBN8J
+2QJFJT1pNE+Pleuz4yMuK5Ddcuuyl9ZklfEclmkLpSEwapFMm9IOgaGhucBMpvkC
+2FE05oc0dEyTCdt1rBppGXvx2aw1khSiuWU13bWXw4hWfJaYKDKdTQyJLsjKGe0u
+qjaR6yHWHbjlchQWKGUWLHomTKG6wZx9k5YbEy5LN7HnyCHos4SiWyaSpXSjCtNn
+15i0JdH68fpKAtaGtkUYtoEJIg8qg7u4B6wM70BK2WCZr8T5yWK0c7NrojMIYjEu
+HwEA9XPkcF9TF7V1VOZMze1ZOWSNzGOfq1yJf6hpUNrw+B3TbYsqJkuJmVSYoamH
+0QBy0sHxlUtsALMnuKIQt8Sp20bJZLwpudXF+ZSRwrjmYc2RMc5AWaBHTGz2IGte
+AvH+SOOaRWj+UvhSFZVKVOZHWqErzKG+NfqQzEaEL4h/6QU64h5GLhocYHCiCbFm
+X1t01eKoDfOhwQlSlPjpDxxr7yi60ntt1R7DpgwqMNIdyXylxsc4SCvM6NDRXVM1
+DoaPHI7GRuT1w6zEtkCGQoGsy1OBrnjeIy40mzh8L5q8L7n3jNtN/d6YCYDzP/P6
+gb52/WPhR6CJQ2/7y3Uj7u8sPNpb7BGI
+=as33
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg
index d019b06b6c..2315898bf1 100644
--- a/contrib/linearize/example-linearize.cfg
+++ b/contrib/linearize/example-linearize.cfg
@@ -3,9 +3,16 @@ rpcuser=someuser
rpcpassword=somepassword
#datadir=~/.bitcoin
host=127.0.0.1
+
+#mainnet default
port=8332
+
+#testnet default
#port=18332
+#regtest default
+#port=18443
+
# bootstrap.dat hashlist settings (linearize-hashes)
max_height=313000
diff --git a/contrib/linearize/linearize-hashes.py b/contrib/linearize/linearize-hashes.py
index db8eb7021e..58fec6dddc 100755
--- a/contrib/linearize/linearize-hashes.py
+++ b/contrib/linearize/linearize-hashes.py
@@ -87,7 +87,7 @@ def get_block_hashes(settings, max_blocks_per_call=10000):
for x,resp_obj in enumerate(reply):
if rpc.response_is_error(resp_obj):
print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
- exit(1)
+ sys.exit(1)
assert(resp_obj['id'] == x) # assume replies are in-sequence
if settings['rev_hash_bytes'] == 'true':
resp_obj['result'] = hex_switchEndian(resp_obj['result'])
@@ -140,7 +140,7 @@ if __name__ == '__main__':
if 'datadir' in settings and not use_userpass:
use_datadir = True
if not use_userpass and not use_datadir:
- print("Missing datadir or username and/or password in cfg file", file=stderr)
+ print("Missing datadir or username and/or password in cfg file", file=sys.stderr)
sys.exit(1)
settings['port'] = int(settings['port'])
diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec
index cc54fcaf3d..7c4d933ee0 100644
--- a/contrib/rpm/bitcoin.spec
+++ b/contrib/rpm/bitcoin.spec
@@ -336,6 +336,8 @@ done
%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 8333
%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18332
%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18333
+%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18443
+%{_sbindir}/semanage port -a -t bitcoin_port_t -p tcp 18444
%{_sbindir}/fixfiles -R bitcoin-server restore &> /dev/null || :
%{_sbindir}/restorecon -R %{_localstatedir}/lib/bitcoin || :
fi
@@ -355,6 +357,8 @@ if [ $1 -eq 0 ]; then
%{_sbindir}/semanage port -d -p tcp 8333
%{_sbindir}/semanage port -d -p tcp 18332
%{_sbindir}/semanage port -d -p tcp 18333
+ %{_sbindir}/semanage port -d -p tcp 18443
+ %{_sbindir}/semanage port -d -p tcp 18444
for selinuxvariant in %{selinux_variants}; do
%{_sbindir}/semodule -s ${selinuxvariant} -r bitcoin &> /dev/null || :
done
diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py
index b0ac92ae03..28068a7523 100755
--- a/contrib/seeds/generate-seeds.py
+++ b/contrib/seeds/generate-seeds.py
@@ -114,7 +114,7 @@ def process_nodes(g, f, structname, defaultport):
def main():
if len(sys.argv)<2:
print(('Usage: %s <path_to_nodes_txt>' % sys.argv[0]), file=sys.stderr)
- exit(1)
+ sys.exit(1)
g = sys.stdout
indir = sys.argv[1]
g.write('#ifndef BITCOIN_CHAINPARAMSSEEDS_H\n')
diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py
index ea398a27ea..5cc19761d4 100755
--- a/contrib/zmq/zmq_sub.py
+++ b/contrib/zmq/zmq_sub.py
@@ -32,7 +32,7 @@ import sys
if not (sys.version_info.major >= 3 and sys.version_info.minor >= 5):
print("This example only works with Python 3.5 and greater")
- exit(1)
+ sys.exit(1)
port = 28332
diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py
index 1cb7eec0c0..bfb7ea9eae 100755
--- a/contrib/zmq/zmq_sub3.4.py
+++ b/contrib/zmq/zmq_sub3.4.py
@@ -36,7 +36,7 @@ import sys
if not (sys.version_info.major >= 3 and sys.version_info.minor >= 4):
print("This example only works with Python 3.4 and greater")
- exit(1)
+ sys.exit(1)
port = 28332
diff --git a/doc/README.md b/doc/README.md
index 275ae67e54..988019869e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -37,6 +37,7 @@ Building
---------------------
The following are developer notes on how to build Bitcoin on your native platform. They are not complete guides, but include notes on the necessary libraries, compile flags, etc.
+- [Dependencies](dependencies.md)
- [OS X Build Notes](build-osx.md)
- [Unix Build Notes](build-unix.md)
- [Windows Build Notes](build-windows.md)
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 7a17c175bd..f3dc124ece 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -3,7 +3,8 @@ Unauthenticated REST Interface
The REST API can be enabled with the `-rest` option.
-The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet and port 18332 for testnet.
+The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet, port 18332 for testnet,
+and port 18443 for regtest.
Supported API
-------------
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index f4a9826d80..4ea8e30b53 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,6 +1,6 @@
OpenBSD build guide
======================
-(updated for OpenBSD 6.0)
+(updated for OpenBSD 6.1)
This guide describes how to build bitcoind and command-line utilities on OpenBSD.
@@ -18,12 +18,12 @@ pkg_add automake # (select highest version, e.g. 1.15)
pkg_add python # (select highest version, e.g. 3.5)
```
-The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler.
+See [dependencies.md](dependencies.md) for a complete overview.
GCC
-------
-You can install a newer version of gcc with:
+The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler:
```bash
pkg_add g++ # (select newest 4.x version, e.g. 4.9.3)
@@ -48,13 +48,13 @@ BOOST_PREFIX="${BITCOIN_ROOT}/boost"
mkdir -p $BOOST_PREFIX
# Fetch the source and verify that it is not tampered with
-curl -o boost_1_61_0.tar.bz2 http://heanet.dl.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.bz2
-echo 'a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 boost_1_61_0.tar.bz2' | sha256 -c
-# MUST output: (SHA256) boost_1_61_0.tar.bz2: OK
-tar -xjf boost_1_61_0.tar.bz2
+curl -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2
+echo '7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 boost_1_64_0.tar.bz2' | sha256 -c
+# MUST output: (SHA256) boost_1_64_0.tar.bz2: OK
+tar -xjf boost_1_64_0.tar.bz2
-# Boost 1.61 needs one small patch for OpenBSD
-cd boost_1_61_0
+# Boost 1.64 needs one small patch for OpenBSD
+cd boost_1_64_0
# Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch
patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 32d7dbd69e..836c856a64 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -16,7 +16,9 @@ Then install [Homebrew](https://brew.sh).
Dependencies
----------------------
- brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf qt libevent
+ brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf python3 qt libevent
+
+See [dependencies.md](dependencies.md) for a complete overview.
If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG
diff --git a/doc/build-unix.md b/doc/build-unix.md
index b7eae2a630..8a102abaea 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -49,7 +49,7 @@ Optional dependencies:
univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure)
libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.x)
-For the versions used in the release, see [release-process.md](release-process.md) under *Fetch and build inputs*.
+For the versions used, see [dependencies.md](dependencies.md)
Memory Requirements
--------------------
@@ -65,7 +65,7 @@ Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
- sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils
+ sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils python3
Options when installing required Boost library files:
@@ -131,7 +131,7 @@ Dependency Build Instructions: Fedora
-------------------------------------
Build requirements:
- sudo dnf install gcc-c++ libtool make autoconf automake openssl-devel libevent-devel boost-devel libdb4-devel libdb4-cxx-devel
+ sudo dnf install gcc-c++ libtool make autoconf automake openssl-devel libevent-devel boost-devel libdb4-devel libdb4-cxx-devel python3
Optional:
diff --git a/doc/build-windows.md b/doc/build-windows.md
index 9549a4b9da..ce837a222a 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -6,6 +6,9 @@ Below are some notes on how to build Bitcoin Core for Windows.
Most developers use cross-compilation from Ubuntu to build executables for
Windows. This is also used to build the release binaries.
+Currently only building on Ubuntu Trusty 14.04 is supported.
+Other versions are unsupported or known to be broken (e.g. Ubuntu Xenial 16.04).
+
While there are potentially a number of ways to build on Windows (for example using msys / mingw-w64),
using the Windows Subsystem For Linux is the most straightforward. If you are building with
another method, please contribute the instructions here for others who are running versions
@@ -59,6 +62,8 @@ A host toolchain (`build-essential`) is necessary because some dependency
packages (such as `protobuf`) need to build host utilities that are used in the
build process.
+See also: [dependencies.md](dependencies.md).
+
## Building for 64-bit Windows
To build executables for Windows 64-bit, install the following dependencies:
diff --git a/doc/dependencies.md b/doc/dependencies.md
new file mode 100644
index 0000000000..2574d8bb06
--- /dev/null
+++ b/doc/dependencies.md
@@ -0,0 +1,32 @@
+Dependencies
+============
+
+These are the dependencies currently used by Bitcoin Core. You can find instructions for installing them in the `build-*.md` file for your platform.
+
+| Dependency | Version used | Minimum Required | CVEs? | Shared | [Bundled Qt Library](https://doc.qt.io/qt-5/configure-options.html) |
+| --- | --- | --- | --- | --- | --- | --- |
+| openssl | [1.0.1k]](https://www.openssl.org/source) | | Yes | | |
+| ccache | [3.3.4](https://ccache.samba.org/download.html) | | No | | |
+| libevent | [2.1.8-stable](https://github.com/libevent/libevent/releases) | 2.0.22 | No | | |
+| Qt | [5.7.1](https://download.qt.io/official_releases/qt/) | 4.7+ | No | | |
+| Freetype | [2.7.1](http://download.savannah.gnu.org/releases/freetype) | | No | | |
+| Boost | [1.64.0](http://www.boost.org/users/download/) | [1.47.0](https://github.com/bitcoin/bitcoin/pull/8920) | No | | |
+| Protobuf | [2.6.3](https://github.com/google/protobuf/releases) | | No | | |
+| Zeromq | [4.1.5](https://github.com/zeromq/libzmq/releases) | | No | | |
+| miniupnpc | [2.0.20170509](http://miniupnp.free.fr/files) | | No | | |
+| qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | |
+| berkeley-db | [4.8.30](http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.x | No | | |
+| dbus | [1.10.18](https://cgit.freedesktop.org/dbus/dbus/tree/NEWS?h=dbus-1.10) | | No | yes | |
+| expat | [2.2.1](https://libexpat.github.io/) | | No | yes | |
+| fontconfig | [2.12.1](https://www.freedesktop.org/software/fontconfig/release/) | | No | yes | |
+| freetype | | | | | [no](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L38) (linux uses system) |
+| zlib | [1.2.11](http://zlib.net/) | | | | no |
+| libjpeg | | | | | [yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L75) |
+| libpng | | | | | [yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L74) |
+| PCRE | | | | | [yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L76) |
+| xcb | | | | | [yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L94) (linux only) |
+| xkbcommon | | | | | [yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L93) (linux only) |
+| HarfBuzz-NG | | | | | ? |
+| Python (tests) | | [3.4](https://www.python.org/downloads) | | | |
+| GCC | | [4.7+](https://gcc.gnu.org/) | | | |
+| Clang | | [3.3+](http://llvm.org/releases/download.html) (C++11 support) | | | |
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 461d7e1dc6..8fdae25340 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -37,6 +37,8 @@ code.
- **Miscellaneous**
- `++i` is preferred over `i++`.
+ - `nullptr` is preferred over `NULL` or `(void*)0`.
+ - `static_assert` is preferred over `assert` where possible. Generally; compile-time checking is preferred over run-time checking.
Block style example:
```c++
@@ -275,7 +277,7 @@ Wallet
- *Rationale*: In RPC code that conditionally uses the wallet (such as
`validateaddress`) it is easy to forget that global pointer `pwalletMain`
- can be NULL. See `test/functional/disablewallet.py` for functional tests
+ can be nullptr. See `test/functional/disablewallet.py` for functional tests
exercising the API with `-disablewallet`
- Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set
@@ -330,6 +332,12 @@ C++ data structures
- *Rationale*: Ensure determinism by avoiding accidental use of uninitialized
values. Also, static analyzers balk about this.
+- By default, declare single-argument constructors `explicit`.
+
+ - *Rationale*: This is a precaution to avoid unintended conversions that might
+ arise when single-argument constructors are used as implicit conversion
+ functions.
+
- Use explicitly signed or unsigned `char`s, or even better `uint8_t` and
`int8_t`. Do not use bare `char` unless it is to pass to a third-party API.
This type can be signed or unsigned depending on the architecture, which can
@@ -570,16 +578,14 @@ A few guidelines for introducing and reviewing new RPC interfaces:
is specified as-is in BIP22.
- Missing arguments and 'null' should be treated the same: as default values. If there is no
- default value, both cases should fail in the same way.
+ default value, both cases should fail in the same way. The easiest way to follow this
+ guideline is detect unspecified arguments with `params[x].isNull()` instead of
+ `params.size() <= x`. The former returns true if the argument is either null or missing,
+ while the latter returns true if is missing, and false if it is null.
- *Rationale*: Avoids surprises when switching to name-based arguments. Missing name-based arguments
are passed as 'null'.
- - *Exception*: Many legacy exceptions to this exist, one of the worst ones is
- `getbalance` which follows a completely different code path based on the
- number of arguments. We are still in the process of cleaning these up. Do not introduce
- new ones.
-
- Try not to overload methods on argument type. E.g. don't make `getblock(true)` and `getblock("hash")`
do different things.
@@ -607,9 +613,14 @@ A few guidelines for introducing and reviewing new RPC interfaces:
from there.
- A RPC method must either be a wallet method or a non-wallet method. Do not
- introduce new methods such as `getinfo` and `signrawtransaction` that differ
- in behavior based on presence of a wallet.
+ introduce new methods such as `signrawtransaction` that differ in behavior
+ based on presence of a wallet.
- *Rationale*: as well as complicating the implementation and interfering
with the introduction of multi-wallet, wallet and non-wallet code should be
separated to avoid introducing circular dependencies between code units.
+
+- Try to make the RPC response a JSON object.
+
+ - *Rationale*: If a RPC response is not a JSON object then it is harder to avoid API breakage if
+ new data in the response is needed.
diff --git a/doc/init.md b/doc/init.md
index e3db5b05ef..75f9013f29 100644
--- a/doc/init.md
+++ b/doc/init.md
@@ -10,14 +10,14 @@ can be found in the contrib/init folder.
contrib/init/bitcoind.conf: Upstart service configuration file
contrib/init/bitcoind.init: CentOS compatible SysV style init script
-1. Service User
+Service User
---------------------------------
All three Linux startup configurations assume the existence of a "bitcoin" user
and group. They must be created before attempting to use these scripts.
The OS X configuration assumes bitcoind will be set up for the current user.
-2. Configuration
+Configuration
---------------------------------
At a bare minimum, bitcoind requires that the rpcpassword setting be set
@@ -46,10 +46,10 @@ relative to the data directory. `wallet` *only* supports relative paths.
For an example configuration file that describes the configuration settings,
see `contrib/debian/examples/bitcoin.conf`.
-3. Paths
+Paths
---------------------------------
-3a) Linux
+### Linux
All three configurations assume several paths that might need to be adjusted.
@@ -65,17 +65,17 @@ reasons to make the configuration file and data directory only readable by the
bitcoin user and group. Access to bitcoin-cli and other bitcoind rpc clients
can then be controlled by group membership.
-3b) Mac OS X
+### Mac OS X
Binary: `/usr/local/bin/bitcoind`
Configuration file: `~/Library/Application Support/Bitcoin/bitcoin.conf`
-Data directory: `~/Library/Application Support/Bitcoin`
-Lock file: `~/Library/Application Support/Bitcoin/.lock`
+Data directory: `~/Library/Application Support/Bitcoin`
+Lock file: `~/Library/Application Support/Bitcoin/.lock`
-4. Installing Service Configuration
+Installing Service Configuration
-----------------------------------
-4a) systemd
+### systemd
Installing this .service file consists of just copying it to
/usr/lib/systemd/system directory, followed by the command
@@ -84,14 +84,14 @@ Installing this .service file consists of just copying it to
To test, run `systemctl start bitcoind` and to enable for system startup run
`systemctl enable bitcoind`
-4b) OpenRC
+### OpenRC
Rename bitcoind.openrc to bitcoind and drop it in /etc/init.d. Double
check ownership and permissions and make it executable. Test it with
`/etc/init.d/bitcoind start` and configure it to run on startup with
`rc-update add bitcoind`
-4c) Upstart (for Debian/Ubuntu based distributions)
+### Upstart (for Debian/Ubuntu based distributions)
Drop bitcoind.conf in /etc/init. Test by running `service bitcoind start`
it will automatically start on reboot.
@@ -99,7 +99,7 @@ it will automatically start on reboot.
NOTE: This script is incompatible with CentOS 5 and Amazon Linux 2014 as they
use old versions of Upstart and do not supply the start-stop-daemon utility.
-4d) CentOS
+### CentOS
Copy bitcoind.init to /etc/init.d/bitcoind. Test by running `service bitcoind start`.
@@ -107,7 +107,7 @@ Using this script, you can adjust the path and flags to the bitcoind program by
setting the BITCOIND and FLAGS environment variables in the file
/etc/sysconfig/bitcoind. You can also use the DAEMONOPTS environment variable here.
-4e) Mac OS X
+### Mac OS X
Copy org.bitcoin.bitcoind.plist into ~/Library/LaunchAgents. Load the launch agent by
running `launchctl load ~/Library/LaunchAgents/org.bitcoin.bitcoind.plist`.
@@ -118,7 +118,7 @@ NOTE: This approach is intended for those wanting to run bitcoind as the current
You will need to modify org.bitcoin.bitcoind.plist if you intend to use it as a
Launch Daemon with a dedicated bitcoin user.
-5. Auto-respawn
+Auto-respawn
-----------------------------------
Auto respawning is currently only configured for Upstart and systemd.
diff --git a/doc/zmq.md b/doc/zmq.md
index 1019ff6653..38c58fb7fd 100644
--- a/doc/zmq.md
+++ b/doc/zmq.md
@@ -72,7 +72,7 @@ For instance:
Each PUB notification has a topic and body, where the header
corresponds to the notification type. For instance, for the
notification `-zmqpubhashtx` the topic is `hashtx` (no null
-terminator) and the body is the hexadecimal transaction hash (32
+terminator) and the body is the transaction hash (32
bytes).
These options can also be provided in bitcoin.conf.
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 5492fdb8c5..e3be18205d 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -58,7 +58,7 @@ XGETTEXT=os.getenv('XGETTEXT', 'xgettext')
if not XGETTEXT:
print('Cannot extract strings: xgettext utility is not installed or not configured.',file=sys.stderr)
print('Please install package "gettext" and re-run \'./configure\'.',file=sys.stderr)
- exit(1)
+ sys.exit(1)
child = Popen([XGETTEXT,'--output=-','-n','--keyword=_'] + files, stdout=PIPE)
(out, err) = child.communicate()
diff --git a/src/Makefile.am b/src/Makefile.am
index f7abab482e..ebae53a8c1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,6 @@ else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
-BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
@@ -130,6 +129,7 @@ BITCOIN_CORE_H = \
rpc/client.h \
rpc/mining.h \
rpc/protocol.h \
+ rpc/safemode.h \
rpc/server.h \
rpc/register.h \
scheduler.h \
@@ -162,6 +162,8 @@ BITCOIN_CORE_H = \
wallet/crypter.h \
wallet/db.h \
wallet/feebumper.h \
+ wallet/fees.h \
+ wallet/init.h \
wallet/rpcwallet.h \
wallet/wallet.h \
wallet/walletdb.h \
@@ -208,6 +210,7 @@ libbitcoin_server_a_SOURCES = \
rpc/misc.cpp \
rpc/net.cpp \
rpc/rawtransaction.cpp \
+ rpc/safemode.cpp \
rpc/server.cpp \
script/sigcache.cpp \
script/ismine.cpp \
@@ -239,6 +242,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/crypter.cpp \
wallet/db.cpp \
wallet/feebumper.cpp \
+ wallet/fees.cpp \
+ wallet/init.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
wallet/wallet.cpp \
@@ -246,7 +251,7 @@ libbitcoin_wallet_a_SOURCES = \
$(BITCOIN_CORE_H)
# crypto primitives library
-crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_CONFIG_INCLUDES)
+crypto_libbitcoin_crypto_a_CPPFLAGS = $(AM_CPPFLAGS)
crypto_libbitcoin_crypto_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
crypto_libbitcoin_crypto_a_SOURCES = \
crypto/aes.cpp \
@@ -267,7 +272,7 @@ crypto_libbitcoin_crypto_a_SOURCES = \
crypto/sha512.cpp \
crypto/sha512.h
-if EXPERIMENTAL_ASM
+if USE_ASM
crypto_libbitcoin_crypto_a_SOURCES += crypto/sha256_sse4.cpp
endif
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 02f30bc952..ea2ed17472 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -25,12 +25,10 @@ TEST_QT_H = \
qt/test/wallettests.h
TEST_BITCOIN_CPP = \
- test/test_bitcoin.cpp \
- test/testutil.cpp
+ test/test_bitcoin.cpp
TEST_BITCOIN_H = \
- test/test_bitcoin.h \
- test/testutil.h
+ test/test_bitcoin.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 6415b3d2e3..01ab0134fe 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -74,8 +74,6 @@ BITCOIN_TESTS =\
test/test_bitcoin.cpp \
test/test_bitcoin.h \
test/test_bitcoin_main.cpp \
- test/testutil.cpp \
- test/testutil.h \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
diff --git a/src/addrdb.h b/src/addrdb.h
index 8105ebc9b3..d930de204d 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -37,7 +37,7 @@ public:
SetNull();
}
- CBanEntry(int64_t nCreateTimeIn)
+ explicit CBanEntry(int64_t nCreateTimeIn)
{
SetNull();
nCreateTime = nCreateTimeIn;
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 6223e4afeb..5fd4fe96cf 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -250,7 +250,7 @@ public:
uint64_t GetLow64() const
{
- assert(WIDTH >= 2);
+ static_assert(WIDTH >= 2, "Assertion WIDTH >= 2 failed (WIDTH = BITS / 32). BITS is a template parameter.");
return pn[0] | (uint64_t)pn[1] << 32;
}
};
diff --git a/src/base58.cpp b/src/base58.cpp
index c70e358ebb..3b907c20d6 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -212,13 +212,35 @@ int CBase58Data::CompareTo(const CBase58Data& b58) const
namespace
{
+/** base58-encoded Bitcoin addresses.
+ * Public-key-hash-addresses have version 0 (or 111 testnet).
+ * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
+ * Script-hash-addresses have version 5 (or 196 testnet).
+ * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
+ */
+class CBitcoinAddress : public CBase58Data {
+public:
+ bool Set(const CKeyID &id);
+ bool Set(const CScriptID &id);
+ bool Set(const CTxDestination &dest);
+ bool IsValid() const;
+ bool IsValid(const CChainParams &params) const;
+
+ CBitcoinAddress() {}
+ CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
+ CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
+ CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
+
+ CTxDestination Get() const;
+};
+
class CBitcoinAddressVisitor : public boost::static_visitor<bool>
{
private:
CBitcoinAddress* addr;
public:
- CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
+ explicit CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
bool operator()(const CKeyID& id) const { return addr->Set(id); }
bool operator()(const CScriptID& id) const { return addr->Set(id); }
@@ -271,21 +293,6 @@ CTxDestination CBitcoinAddress::Get() const
return CNoDestination();
}
-bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
-{
- if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return false;
- uint160 id;
- memcpy(&id, vchData.data(), 20);
- keyID = CKeyID(id);
- return true;
-}
-
-bool CBitcoinAddress::IsScript() const
-{
- return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
-}
-
void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
assert(vchSecret.IsValid());
@@ -318,3 +325,25 @@ bool CBitcoinSecret::SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
+
+std::string EncodeDestination(const CTxDestination& dest)
+{
+ CBitcoinAddress addr(dest);
+ if (!addr.IsValid()) return "";
+ return addr.ToString();
+}
+
+CTxDestination DecodeDestination(const std::string& str)
+{
+ return CBitcoinAddress(str).Get();
+}
+
+bool IsValidDestinationString(const std::string& str, const CChainParams& params)
+{
+ return CBitcoinAddress(str).IsValid(params);
+}
+
+bool IsValidDestinationString(const std::string& str)
+{
+ return CBitcoinAddress(str).IsValid();
+}
diff --git a/src/base58.h b/src/base58.h
index db12208f74..4b895ca022 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -95,30 +95,6 @@ public:
bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
};
-/** base58-encoded Bitcoin addresses.
- * Public-key-hash-addresses have version 0 (or 111 testnet).
- * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
- * Script-hash-addresses have version 5 (or 196 testnet).
- * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
- */
-class CBitcoinAddress : public CBase58Data {
-public:
- bool Set(const CKeyID &id);
- bool Set(const CScriptID &id);
- bool Set(const CTxDestination &dest);
- bool IsValid() const;
- bool IsValid(const CChainParams &params) const;
-
- CBitcoinAddress() {}
- CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
- CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
- CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
-
- CTxDestination Get() const;
- bool GetKeyID(CKeyID &keyID) const;
- bool IsScript() const;
-};
-
/**
* A base58-encoded secret key
*/
@@ -167,4 +143,9 @@ public:
typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_SECRET_KEY> CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE, CChainParams::EXT_PUBLIC_KEY> CBitcoinExtPubKey;
+std::string EncodeDestination(const CTxDestination& dest);
+CTxDestination DecodeDestination(const std::string& str);
+bool IsValidDestinationString(const std::string& str);
+bool IsValidDestinationString(const std::string& str, const CChainParams& params);
+
#endif // BITCOIN_BASE58_H
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 88a2a570f9..b7ae5c2d57 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -67,7 +67,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::State& state)
prevector<PREVECTOR_SIZE, uint8_t> p;
PrevectorJob(){
}
- PrevectorJob(FastRandomContext& insecure_rand){
+ explicit PrevectorJob(FastRandomContext& insecure_rand){
p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
}
bool operator()()
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 8bec0289f5..3c94c99b3e 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -45,7 +45,8 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout in seconds during HTTP requests, or 0 for no timeout. (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
- strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases)"));
+ strUsage += HelpMessageOpt("-stdinrpcpass", strprintf(_("Read RPC password from standard input as a single line. When combined with -stdin, the first line from standard input is used for the RPC password.")));
+ strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). When combined with -stdinrpcpass, the first line from standard input is used for the RPC password."));
strUsage += HelpMessageOpt("-rpcwallet=<walletname>", _("Send RPC for non-default wallet on RPC server (argument is wallet filename in bitcoind directory, required if bitcoind/-Qt runs with multiple wallets)"));
return strUsage;
@@ -190,7 +191,7 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
-UniValue CallRPC(const std::string& strMethod, const UniValue& params)
+static UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
std::string host;
// In preference order, we choose the following for the port:
@@ -222,7 +223,7 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params)
// Try fall back to cookie-based authentication if no password is provided
if (!GetAuthCookie(&strRPCUserColonPass)) {
throw std::runtime_error(strprintf(
- _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
+ _("Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)"),
GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
}
@@ -293,15 +294,24 @@ int CommandLineRPC(int argc, char *argv[])
argc--;
argv++;
}
+ std::string rpcPass;
+ if (gArgs.GetBoolArg("-stdinrpcpass", false)) {
+ if (!std::getline(std::cin, rpcPass)) {
+ throw std::runtime_error("-stdinrpcpass specified but failed to read from standard input");
+ }
+ gArgs.ForceSetArg("-rpcpassword", rpcPass);
+ }
std::vector<std::string> args = std::vector<std::string>(&argv[1], &argv[argc]);
if (gArgs.GetBoolArg("-stdin", false)) {
// Read one arg per line from stdin and append
std::string line;
- while (std::getline(std::cin,line))
+ while (std::getline(std::cin, line)) {
args.push_back(line);
+ }
}
- if (args.size() < 1)
+ if (args.size() < 1) {
throw std::runtime_error("too few parameters (need at least command)");
+ }
std::string strMethod = args[0];
args.erase(args.begin()); // Remove trailing method name from arguments vector
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index cff90d13af..d8d7934bf6 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -271,11 +271,11 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strIn
// extract and validate ADDRESS
std::string strAddr = vStrInputParts[1];
- CBitcoinAddress addr(strAddr);
- if (!addr.IsValid())
+ CTxDestination destination = DecodeDestination(strAddr);
+ if (!IsValidDestination(destination)) {
throw std::runtime_error("invalid TX output address");
- // build standard output script via GetScriptForDestination()
- CScript scriptPubKey = GetScriptForDestination(addr.Get());
+ }
+ CScript scriptPubKey = GetScriptForDestination(destination);
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
@@ -314,10 +314,8 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- // Get the address for the redeem script, then call
- // GetScriptForDestination() to construct a P2SH scriptPubKey.
- CBitcoinAddress redeemScriptAddr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());
+ // Get the ID for the script, and then construct a P2SH destination for it.
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -381,10 +379,8 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- // Get the address for the redeem script, then call
- // GetScriptForDestination() to construct a P2SH scriptPubKey.
- CBitcoinAddress addr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(addr.Get());
+ // Get the ID for the script, and then construct a P2SH destination for it.
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -444,11 +440,10 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
}
if (bSegWit) {
- scriptPubKey = GetScriptForWitness(scriptPubKey);
+ scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
- CBitcoinAddress addr(scriptPubKey);
- scriptPubKey = GetScriptForDestination(addr.Get());
+ scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
// construct TxOut, append to transaction output list
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 5a1d80d421..50478f9f32 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -16,7 +16,7 @@ struct TransactionCompressor {
private:
CTransactionRef& tx;
public:
- TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
+ explicit TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {}
ADD_SERIALIZE_METHODS;
@@ -75,7 +75,7 @@ public:
std::vector<CTransactionRef> txn;
BlockTransactions() {}
- BlockTransactions(const BlockTransactionsRequest& req) :
+ explicit BlockTransactions(const BlockTransactionsRequest& req) :
blockhash(req.blockhash), txn(req.indexes.size()) {}
ADD_SERIALIZE_METHODS;
@@ -198,7 +198,7 @@ protected:
CTxMemPool* pool;
public:
CBlockHeader header;
- PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
+ explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
// extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock, const std::vector<std::pair<uint256, CTransactionRef>>& extra_txn);
diff --git a/src/chain.h b/src/chain.h
index 02db9ec771..ef7e6f9554 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -247,7 +247,7 @@ public:
SetNull();
}
- CBlockIndex(const CBlockHeader& block)
+ explicit CBlockIndex(const CBlockHeader& block)
{
SetNull();
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 224c9eb0ea..c966683b72 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -57,7 +57,7 @@ class CBaseRegTestParams : public CBaseChainParams
public:
CBaseRegTestParams()
{
- nRPCPort = 18332;
+ nRPCPort = 18443;
strDataDir = "regtest";
}
};
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 4bc6be45f8..6377fbe942 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -131,7 +131,7 @@ public:
boost::mutex ControlMutex;
//! Create a new check queue
- CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
+ explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {}
//! Worker thread
void Thread()
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index 3c5a5c0837..d93ff7413a 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -35,7 +35,7 @@
#if HAVE_DECL_BSWAP_16 == 0
inline uint16_t bswap_16(uint16_t x)
{
- return (x >> 8) | ((x & 0x00ff) << 8);
+ return (x >> 8) | (x << 8);
}
#endif // HAVE_DECL_BSWAP16
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 79d6b2fdbb..dbf178f53c 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -9,10 +9,10 @@
#include "config/bitcoin-config.h"
#endif
-#include <stdint.h>
-
#include "compat/byteswap.h"
+#include <stdint.h>
+
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
diff --git a/src/compressor.h b/src/compressor.h
index 015911484a..094c1bcfe1 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -53,7 +53,7 @@ protected:
unsigned int GetSpecialSize(unsigned int nSize) const;
bool Decompress(unsigned int nSize, const std::vector<unsigned char> &out);
public:
- CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
+ explicit CScriptCompressor(CScript &scriptIn) : script(scriptIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -99,7 +99,7 @@ public:
static uint64_t CompressAmount(uint64_t nAmount);
static uint64_t DecompressAmount(uint64_t nAmount);
- CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
+ explicit CTxOutCompressor(CTxOut &txoutIn) : txout(txoutIn) { }
ADD_SERIALIZE_METHODS;
diff --git a/src/core_io.h b/src/core_io.h
index 3f25faf0ec..ccc72ebb32 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -31,6 +31,6 @@ UniValue ValueFromAmount(const CAmount& amount);
std::string FormatScript(const CScript& script);
std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 0eae4703ab..e16db13650 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -148,12 +148,13 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("type", GetTxnOutputType(type));
UniValue a(UniValue::VARR);
- for (const CTxDestination& addr : addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
out.pushKV("addresses", a);
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
@@ -207,5 +208,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry)
if (!hashBlock.IsNull())
entry.pushKV("blockhash", hashBlock.GetHex());
- entry.pushKV("hex", EncodeHexTx(tx)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
+ if (include_hex) {
+ entry.pushKV("hex", EncodeHexTx(tx, serialize_flags)); // the hex-encoded transaction. used the name "hex" to be consistent with the verbose output of "getrawtransaction".
+ }
}
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index e9f1b52e71..a7b63b19df 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -22,7 +22,7 @@ private:
AES128_ctx ctx;
public:
- AES128Encrypt(const unsigned char key[16]);
+ explicit AES128Encrypt(const unsigned char key[16]);
~AES128Encrypt();
void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
};
@@ -34,7 +34,7 @@ private:
AES128_ctx ctx;
public:
- AES128Decrypt(const unsigned char key[16]);
+ explicit AES128Decrypt(const unsigned char key[16]);
~AES128Decrypt();
void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
};
@@ -46,7 +46,7 @@ private:
AES256_ctx ctx;
public:
- AES256Encrypt(const unsigned char key[32]);
+ explicit AES256Encrypt(const unsigned char key[32]);
~AES256Encrypt();
void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
};
@@ -58,7 +58,7 @@ private:
AES256_ctx ctx;
public:
- AES256Decrypt(const unsigned char key[32]);
+ explicit AES256Decrypt(const unsigned char key[32]);
~AES256Decrypt();
void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
};
diff --git a/src/crypto/common.h b/src/crypto/common.h
index bcca3d30ea..bd9bc9420b 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -6,7 +6,7 @@
#define BITCOIN_CRYPTO_COMMON_H
#if defined(HAVE_CONFIG_H)
-#include "bitcoin-config.h"
+#include "config/bitcoin-config.h"
#endif
#include <stdint.h>
diff --git a/src/crypto/hmac_sha256.h b/src/crypto/hmac_sha256.h
index 1519c1457e..8c42fcfe14 100644
--- a/src/crypto/hmac_sha256.h
+++ b/src/crypto/hmac_sha256.h
@@ -10,7 +10,7 @@
#include <stdint.h>
#include <stdlib.h>
-/** A hasher class for HMAC-SHA-512. */
+/** A hasher class for HMAC-SHA-256. */
class CHMAC_SHA256
{
private:
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 15d6db90c2..29afe86ec7 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -10,7 +10,7 @@
#include <atomic>
#if defined(__x86_64__) || defined(__amd64__)
-#if defined(EXPERIMENTAL_ASM)
+#if defined(USE_ASM)
#include <cpuid.h>
namespace sha256_sse4
{
@@ -178,7 +178,7 @@ TransformType Transform = sha256::Transform;
std::string SHA256AutoDetect()
{
-#if defined(EXPERIMENTAL_ASM) && (defined(__x86_64__) || defined(__amd64__))
+#if defined(USE_ASM) && (defined(__x86_64__) || defined(__amd64__))
uint32_t eax, ebx, ecx, edx;
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx >> 19) & 1) {
Transform = sha256_sse4::Transform;
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index fd24d05ee7..947e1a7185 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOIN_CUCKOOCACHE_H_
-#define _BITCOIN_CUCKOOCACHE_H_
+#ifndef BITCOIN_CUCKOOCACHE_H
+#define BITCOIN_CUCKOOCACHE_H
#include <array>
#include <algorithm>
@@ -58,7 +58,7 @@ public:
* @post All calls to bit_is_set (without subsequent bit_unset) will return
* true.
*/
- bit_packed_atomic_flags(uint32_t size)
+ explicit bit_packed_atomic_flags(uint32_t size)
{
// pad out the size if needed
size = (size + 7) / 8;
@@ -478,4 +478,4 @@ public:
};
} // namespace CuckooCache
-#endif
+#endif // BITCOIN_CUCKOOCACHE_H
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 72eeeef2c3..dfc90f3ab9 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -19,7 +19,7 @@ class CBitcoinLevelDBLogger : public leveldb::Logger {
public:
// This code is adapted from posix_logger.h, which is why it is using vsprintf.
// Please do not do this in normal code
- virtual void Logv(const char * format, va_list ap) override {
+ void Logv(const char * format, va_list ap) override {
if (!LogAcceptCategory(BCLog::LEVELDB)) {
return;
}
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index 54092f9f59..e19fde51c1 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -22,7 +22,7 @@ static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
class dbwrapper_error : public std::runtime_error
{
public:
- dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
+ explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
};
class CDBWrapper;
@@ -61,7 +61,7 @@ public:
/**
* @param[in] _parent CDBWrapper that this batch is to be submitted to
*/
- CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
+ explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
void Clear()
{
diff --git a/src/hash.h b/src/hash.h
index b9952d39fc..ad59bb1817 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -168,7 +168,7 @@ private:
Source* source;
public:
- CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
+ explicit CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {}
void read(char* pch, size_t nSize)
{
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 8c1a74677a..91f96ef207 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -43,7 +43,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
+ explicit HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name() override
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 815d660288..5923871691 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -40,7 +40,7 @@
static const size_t MAX_HEADERS_SIZE = 8192;
/** HTTP request work item */
-class HTTPWorkItem : public HTTPClosure
+class HTTPWorkItem final : public HTTPClosure
{
public:
HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
@@ -79,7 +79,7 @@ private:
{
public:
WorkQueue &wq;
- ThreadCounter(WorkQueue &w): wq(w)
+ explicit ThreadCounter(WorkQueue &w): wq(w)
{
std::lock_guard<std::mutex> lock(wq.cs);
wq.numThreads += 1;
@@ -93,7 +93,7 @@ private:
};
public:
- WorkQueue(size_t _maxDepth) : running(true),
+ explicit WorkQueue(size_t _maxDepth) : running(true),
maxDepth(_maxDepth),
numThreads(0)
{
diff --git a/src/httpserver.h b/src/httpserver.h
index 3e434bf0a0..91ce5b4e00 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -61,7 +61,7 @@ private:
bool replySent;
public:
- HTTPRequest(struct evhttp_request* req);
+ explicit HTTPRequest(struct evhttp_request* req);
~HTTPRequest();
enum RequestMethod {
diff --git a/src/init.cpp b/src/init.cpp
index f9a63348fd..c70c0274be 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -30,6 +30,7 @@
#include "policy/policy.h"
#include "rpc/server.h"
#include "rpc/register.h"
+#include "rpc/safemode.h"
#include "rpc/blockchain.h"
#include "script/standard.h"
#include "script/sigcache.h"
@@ -43,6 +44,7 @@
#include "utilmoneystr.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
+#include "wallet/init.h"
#include "wallet/wallet.h"
#endif
#include "warnings.h"
@@ -69,7 +71,6 @@
bool fFeeEstimatesInitialized = false;
static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false;
-static const bool DEFAULT_DISABLE_SAFEMODE = true;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
std::unique_ptr<CConnman> g_connman;
@@ -133,10 +134,10 @@ bool ShutdownRequested()
* chainstate, while keeping user interface out of the common library, which is shared
* between bitcoind, and bitcoin-qt and non-server tools.
*/
-class CCoinsViewErrorCatcher : public CCoinsViewBacked
+class CCoinsViewErrorCatcher final : public CCoinsViewBacked
{
public:
- CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
+ explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {}
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override {
try {
return CCoinsViewBacked::GetCoin(outpoint, coin);
@@ -317,15 +318,6 @@ void OnRPCStopped()
LogPrint(BCLog::RPC, "RPC stopped.\n");
}
-void OnRPCPreCommand(const CRPCCommand& cmd)
-{
- // Observe safe mode
- std::string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) &&
- !cmd.okSafeMode)
- throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning);
-}
-
std::string HelpMessage(HelpMessageMode mode)
{
const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN);
@@ -362,6 +354,9 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE));
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex()));
+ }
strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL));
strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN));
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
@@ -420,7 +415,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
- strUsage += CWallet::GetWalletHelpString(showDebug);
+ strUsage += GetWalletHelpString(showDebug);
#endif
#if ENABLE_ZMQ
@@ -479,7 +474,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Node relay options:"));
if (showDebug) {
- strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->RequireStandard()));
+ strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()));
strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)));
strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)));
}
@@ -720,7 +715,6 @@ bool AppInitServers(boost::thread_group& threadGroup)
{
RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
- RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
return false;
if (!StartRPC())
@@ -979,6 +973,20 @@ bool AppInitParameterInteraction()
else
LogPrintf("Validating signatures for all blocks.\n");
+ if (gArgs.IsArgSet("-minimumchainwork")) {
+ const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", "");
+ if (!IsHexNumber(minChainWorkStr)) {
+ return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr));
+ }
+ nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr));
+ } else {
+ nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork);
+ }
+ LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex());
+ if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex());
+ }
+
// mempool limits
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
@@ -1035,7 +1043,7 @@ bool AppInitParameterInteraction()
if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) {
return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", "")));
}
- // High fee check is done afterward in CWallet::ParameterInteraction()
+ // High fee check is done afterward in WalletParameterInteraction()
::minRelayTxFee = CFeeRate(n);
} else if (incrementalRelayFee > ::minRelayTxFee) {
// Allow only setting incrementalRelayFee to control both
@@ -1068,7 +1076,7 @@ bool AppInitParameterInteraction()
nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp);
#ifdef ENABLE_WALLET
- if (!CWallet::ParameterInteraction())
+ if (!WalletParameterInteraction())
return false;
#endif
@@ -1245,7 +1253,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
- if (!CWallet::Verify())
+ if (!WalletVerify())
return false;
#endif
// ********************************************************* Step 6: network initialization
@@ -1428,7 +1436,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Check for changed -txindex state
if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex");
+ strLoadError = _("You need to rebuild the database using -reindex to change -txindex");
break;
}
@@ -1566,7 +1574,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
- if (!CWallet::InitLoadWallet())
+ if (!InitLoadWallet())
return false;
#else
LogPrintf("No wallet support compiled in!\n");
@@ -1686,7 +1694,14 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
if (gArgs.IsArgSet("-seednode")) {
connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
}
-
+ // Initiate outbound connections unless connect=0
+ connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect");
+ if (!connOptions.m_use_addrman_outgoing) {
+ const auto connect = gArgs.GetArgs("-connect");
+ if (connect.size() != 1 || connect[0] != "0") {
+ connOptions.m_specified_outgoing = connect;
+ }
+ }
if (!connman.Start(scheduler, connOptions)) {
return false;
}
diff --git a/src/key.h b/src/key.h
index 2c6f151727..151e63531b 100644
--- a/src/key.h
+++ b/src/key.h
@@ -172,6 +172,8 @@ struct CExtKey {
{
unsigned int len = ::ReadCompactSize(s);
unsigned char code[BIP32_EXTKEY_SIZE];
+ if (len != BIP32_EXTKEY_SIZE)
+ throw std::runtime_error("Invalid extended key size\n");
s.read((char *)&code[0], len);
Decode(code);
}
diff --git a/src/keystore.h b/src/keystore.h
index 965ae0c79a..528b6e0834 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -97,14 +97,14 @@ public:
}
return false;
}
- virtual bool AddCScript(const CScript& redeemScript) override;
- virtual bool HaveCScript(const CScriptID &hash) const override;
- virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
+ bool AddCScript(const CScript& redeemScript) override;
+ bool HaveCScript(const CScriptID &hash) const override;
+ bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
- virtual bool AddWatchOnly(const CScript &dest) override;
- virtual bool RemoveWatchOnly(const CScript &dest) override;
- virtual bool HaveWatchOnly(const CScript &dest) const override;
- virtual bool HaveWatchOnly() const override;
+ bool AddWatchOnly(const CScript &dest) override;
+ bool RemoveWatchOnly(const CScript &dest) override;
+ bool HaveWatchOnly(const CScript &dest) const override;
+ bool HaveWatchOnly() const override;
};
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
diff --git a/src/limitedmap.h b/src/limitedmap.h
index e9dcb6defd..7afc8b458d 100644
--- a/src/limitedmap.h
+++ b/src/limitedmap.h
@@ -27,7 +27,7 @@ protected:
size_type nMaxSize;
public:
- limitedmap(size_type nMaxSizeIn)
+ explicit limitedmap(size_type nMaxSizeIn)
{
assert(nMaxSizeIn > 0);
nMaxSize = nMaxSizeIn;
diff --git a/src/miner.cpp b/src/miner.cpp
index f1942ec570..249ea172a6 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -145,6 +145,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
+ assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
diff --git a/src/miner.h b/src/miner.h
index 685b4e0cc8..abd2ff6199 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -11,8 +11,8 @@
#include <stdint.h>
#include <memory>
-#include "boost/multi_index_container.hpp"
-#include "boost/multi_index/ordered_index.hpp"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
class CBlockIndex;
class CChainParams;
@@ -33,7 +33,7 @@ struct CBlockTemplate
// Container for tracking updates to ancestor feerate as we include (parent)
// transactions in a block
struct CTxMemPoolModifiedEntry {
- CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
+ explicit CTxMemPoolModifiedEntry(CTxMemPool::txiter entry)
{
iter = entry;
nSizeWithAncestors = entry->GetSizeWithAncestors();
@@ -116,7 +116,7 @@ typedef indexed_modified_transaction_set::index<ancestor_score>::type::iterator
struct update_for_parent_inclusion
{
- update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
+ explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
void operator() (CTxMemPoolModifiedEntry &e)
{
@@ -164,7 +164,7 @@ public:
CFeeRate blockMinFeeRate;
};
- BlockAssembler(const CChainParams& params);
+ explicit BlockAssembler(const CChainParams& params);
BlockAssembler(const CChainParams& params, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */
diff --git a/src/net.cpp b/src/net.cpp
index 1af317726a..1eb867b48b 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1674,15 +1674,15 @@ void CConnman::ProcessOneShot()
}
}
-void CConnman::ThreadOpenConnections()
+void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
// Connect to specific addresses
- if (gArgs.IsArgSet("-connect"))
+ if (!connect.empty())
{
for (int64_t nLoop = 0;; nLoop++)
{
ProcessOneShot();
- for (const std::string& strAddr : gArgs.GetArgs("-connect"))
+ for (const std::string& strAddr : connect)
{
CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, nullptr, strAddr.c_str());
@@ -2344,9 +2344,16 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
// Initiate outbound connections from -addnode
threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
- // Initiate outbound connections unless connect=0
- if (!gArgs.IsArgSet("-connect") || gArgs.GetArgs("-connect").size() != 1 || gArgs.GetArgs("-connect")[0] != "0")
- threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this)));
+ if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
+ if (clientInterface) {
+ clientInterface->ThreadSafeMessageBox(
+ _("Cannot provide specific connections and have addrman find outgoing connections at the same."),
+ "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
+ if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty())
+ threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this, connOptions.m_specified_outgoing)));
// Process messages
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
diff --git a/src/net.h b/src/net.h
index a32736aa97..244930d8f0 100644
--- a/src/net.h
+++ b/src/net.h
@@ -145,6 +145,8 @@ public:
std::vector<std::string> vSeedNodes;
std::vector<CSubNet> vWhitelistedRange;
std::vector<CService> vBinds, vWhiteBinds;
+ bool m_use_addrman_outgoing = true;
+ std::vector<std::string> m_specified_outgoing;
};
void Init(const Options& connOptions) {
@@ -308,7 +310,7 @@ private:
void ThreadOpenAddedConnections();
void AddOneShot(const std::string& strDest);
void ProcessOneShot();
- void ThreadOpenConnections();
+ void ThreadOpenConnections(std::vector<std::string> connect);
void ThreadMessageHandler();
void AcceptConnection(const ListenSocket& hListenSocket);
void ThreadSocketHandler();
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index e09b56a631..cc44876712 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -281,6 +281,7 @@ void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
fUpdateConnectionTime = false;
LOCK(cs_main);
CNodeState *state = State(nodeid);
+ assert(state != nullptr);
if (state->fSyncStarted)
nSyncStarted--;
@@ -315,6 +316,7 @@ bool MarkBlockAsReceived(const uint256& hash) {
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
+ assert(state != nullptr);
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) {
// Last validated block on the queue was received.
@@ -466,7 +468,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) {
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting.
return;
}
@@ -2783,7 +2785,7 @@ class CompareInvMempoolOrder
{
CTxMemPool *mp;
public:
- CompareInvMempoolOrder(CTxMemPool *_mempool)
+ explicit CompareInvMempoolOrder(CTxMemPool *_mempool)
{
mp = _mempool;
}
diff --git a/src/net_processing.h b/src/net_processing.h
index db6d81e6b6..f4a43980a5 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -32,7 +32,7 @@ private:
CConnman* connman;
public:
- PeerLogicValidation(CConnman* connmanIn);
+ explicit PeerLogicValidation(CConnman* connmanIn);
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
diff --git a/src/netaddress.h b/src/netaddress.h
index 57ce897db5..6ca99b36b5 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -36,7 +36,7 @@ class CNetAddr
public:
CNetAddr();
- CNetAddr(const struct in_addr& ipv4Addr);
+ explicit CNetAddr(const struct in_addr& ipv4Addr);
void Init();
void SetIP(const CNetAddr& ip);
@@ -82,7 +82,7 @@ class CNetAddr
std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = nullptr) const;
- CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
+ explicit CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
@@ -146,7 +146,7 @@ class CService : public CNetAddr
CService();
CService(const CNetAddr& ip, unsigned short port);
CService(const struct in_addr& ipv4Addr, unsigned short port);
- CService(const struct sockaddr_in& addr);
+ explicit CService(const struct sockaddr_in& addr);
void Init();
unsigned short GetPort() const;
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const;
@@ -160,7 +160,7 @@ class CService : public CNetAddr
std::string ToStringIPPort() const;
CService(const struct in6_addr& ipv6Addr, unsigned short port);
- CService(const struct sockaddr_in6& addr);
+ explicit CService(const struct sockaddr_in6& addr);
ADD_SERIALIZE_METHODS;
diff --git a/src/netbase.h b/src/netbase.h
index f02c5e0b05..6572f0a12e 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -29,7 +29,7 @@ class proxyType
{
public:
proxyType(): randomize_credentials(false) {}
- proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
+ explicit proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
bool IsValid() const { return proxy.IsValid(); }
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index 8e8a6e4a02..79b2501c5d 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -12,7 +12,7 @@
class CNetMsgMaker
{
public:
- CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
+ explicit CNetMsgMaker(int nVersionIn) : nVersion(nVersionIn){}
template <typename... Args>
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args&&... args) const
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 565da6c154..7e519e3efa 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -26,7 +26,6 @@ public:
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
/** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
- CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
/**
* Return the fee in satoshis for the given size in bytes.
*/
diff --git a/src/policy/fees.h b/src/policy/fees.h
index f4ef793643..6edaf28714 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -284,7 +284,7 @@ private:
public:
/** Create new FeeFilterRounder */
- FeeFilterRounder(const CFeeRate& minIncrementalFee);
+ explicit FeeFilterRounder(const CFeeRate& minIncrementalFee);
/** Quantize a minimum fee for privacy purpose before broadcast **/
CAmount round(CAmount currentMinFee);
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 605e3e0696..56912d0375 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -54,23 +54,6 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}
- /**
- * Check transaction inputs to mitigate two
- * potential denial-of-service attacks:
- *
- * 1. scriptSigs with extra data stuffed into them,
- * not consumed by scriptPubKey (or P2SH script)
- * 2. P2SH scripts with a crazy number of expensive
- * CHECKSIG/CHECKMULTISIG operations
- *
- * Why bother? To avoid denial-of-service attacks; an attacker
- * can submit a standard HASH... OP_EQUAL transaction,
- * which will get accepted into blocks. The redemption
- * script can be anything; an attacker could use a very
- * expensive-to-check-upon-redemption script like:
- * DUP CHECKSIG DROP ... repeated 100 times... OP_1
- */
-
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled)
{
std::vector<std::vector<unsigned char> > vSolutions;
@@ -160,6 +143,22 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
return true;
}
+/**
+ * Check transaction inputs to mitigate two
+ * potential denial-of-service attacks:
+ *
+ * 1. scriptSigs with extra data stuffed into them,
+ * not consumed by scriptPubKey (or P2SH script)
+ * 2. P2SH scripts with a crazy number of expensive
+ * CHECKSIG/CHECKMULTISIG operations
+ *
+ * Why bother? To avoid denial-of-service attacks; an attacker
+ * can submit a standard HASH... OP_EQUAL transaction,
+ * which will get accepted into blocks. The redemption
+ * script can be anything; an attacker could use a very
+ * expensive-to-check-upon-redemption script like:
+ * DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
diff --git a/src/prevector.h b/src/prevector.h
index f7bde8911a..eb29b3ae7e 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef _BITCOIN_PREVECTOR_H_
-#define _BITCOIN_PREVECTOR_H_
+#ifndef BITCOIN_PREVECTOR_H
+#define BITCOIN_PREVECTOR_H
#include <assert.h>
#include <stdlib.h>
@@ -514,4 +514,4 @@ public:
};
#pragma pack(pop)
-#endif
+#endif // BITCOIN_PREVECTOR_H
diff --git a/src/primitives/block.h b/src/primitives/block.h
index c90a1dfa64..292df40896 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -129,7 +129,7 @@ struct CBlockLocator
CBlockLocator() {}
- CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
+ explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
ADD_SERIALIZE_METHODS;
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 9b6a814e1f..e0a106adb9 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -55,7 +55,7 @@ std::string CTxOut::ToString() const
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
-CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {}
+CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
uint256 CMutableTransaction::GetHash() const
{
@@ -76,9 +76,9 @@ uint256 CTransaction::GetWitnessHash() const
}
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
-CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {}
-CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
-CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash() {}
+CTransaction::CTransaction(const CMutableTransaction &tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
+CTransaction::CTransaction(CMutableTransaction &&tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash(ComputeHash()) {}
CAmount CTransaction::GetValueOut() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 041034bb8b..18d524e23d 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -278,9 +278,9 @@ public:
// actually immutable; deserialization and assignment are implemented,
// and bypass the constness. This is safe, as they update the entire
// structure, including the hash.
- const int32_t nVersion;
const std::vector<CTxIn> vin;
const std::vector<CTxOut> vout;
+ const int32_t nVersion;
const uint32_t nLockTime;
private:
@@ -361,9 +361,9 @@ public:
/** A mutable version of CTransaction. */
struct CMutableTransaction
{
- int32_t nVersion;
std::vector<CTxIn> vin;
std::vector<CTxOut> vout;
+ int32_t nVersion;
uint32_t nLockTime;
CMutableTransaction();
diff --git a/src/protocol.h b/src/protocol.h
index 7890bb627d..67e01d9606 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -39,7 +39,7 @@ public:
};
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
- CMessageHeader(const MessageStartChars& pchMessageStartIn);
+ explicit CMessageHeader(const MessageStartChars& pchMessageStartIn);
CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn);
std::string GetCommand() const;
diff --git a/src/pubkey.h b/src/pubkey.h
index dbf0e23f20..65738d8fe2 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -30,7 +30,7 @@ class CKeyID : public uint160
{
public:
CKeyID() : uint160() {}
- CKeyID(const uint160& in) : uint160(in) {}
+ explicit CKeyID(const uint160& in) : uint160(in) {}
};
typedef uint256 ChainCode;
@@ -88,7 +88,7 @@ public:
}
//! Construct a public key from a byte vector.
- CPubKey(const std::vector<unsigned char>& _vch)
+ explicit CPubKey(const std::vector<unsigned char>& _vch)
{
Set(_vch.begin(), _vch.end());
}
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 2fa032abdc..0eb7ec4306 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -82,14 +82,14 @@ public:
LOCK(wallet->cs_wallet);
for (const std::pair<CTxDestination, CAddressBookData>& item : wallet->mapAddressBook)
{
- const CBitcoinAddress& address = item.first;
- bool fMine = IsMine(*wallet, address.Get());
+ const CTxDestination& address = item.first;
+ bool fMine = IsMine(*wallet, address);
AddressTableEntry::Type addressType = translateTransactionType(
QString::fromStdString(item.second.purpose), fMine);
const std::string& strName = item.second.name;
cachedAddressTable.append(AddressTableEntry(addressType,
QString::fromStdString(strName),
- QString::fromStdString(address.ToString())));
+ QString::fromStdString(EncodeDestination(address))));
}
}
// qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
@@ -246,7 +246,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
if(role == Qt::EditRole)
{
LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */
- CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get();
+ CTxDestination curAddress = DecodeDestination(rec->address.toStdString());
if(index.column() == Label)
{
// Do nothing, if old label == new label
@@ -257,7 +257,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
}
wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose);
} else if(index.column() == Address) {
- CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get();
+ CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
if(boost::get<CNoDestination>(&newAddress))
{
@@ -358,7 +358,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Check for duplicate addresses
{
LOCK(wallet->cs_wallet);
- if(wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get()))
+ if(wallet->mapAddressBook.count(DecodeDestination(strAddress)))
{
editStatus = DUPLICATE_ADDRESS;
return QString();
@@ -384,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
- strAddress = CBitcoinAddress(newKey.GetID()).ToString();
+ strAddress = EncodeDestination(newKey.GetID());
}
else
{
@@ -394,7 +394,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
// Add entry
{
LOCK(wallet->cs_wallet);
- wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel,
+ wallet->SetAddressBook(DecodeDestination(strAddress), strLabel,
(type == Send ? "send" : "receive"));
}
return QString::fromStdString(strAddress);
@@ -412,7 +412,7 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex &parent
}
{
LOCK(wallet->cs_wallet);
- wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get());
+ wallet->DelAddressBook(DecodeDestination(rec->address.toStdString()));
}
return true;
}
@@ -423,8 +423,8 @@ QString AddressTableModel::labelForAddress(const QString &address) const
{
{
LOCK(wallet->cs_wallet);
- CBitcoinAddress address_parsed(address.toStdString());
- std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
+ CTxDestination destination = DecodeDestination(address.toStdString());
+ std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(destination);
if (mi != wallet->mapAddressBook.end())
{
return QString::fromStdString(mi->second.name);
diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp
index d712705c43..4dd1092806 100644
--- a/src/qt/bitcoinaddressvalidator.cpp
+++ b/src/qt/bitcoinaddressvalidator.cpp
@@ -89,9 +89,9 @@ QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &po
{
Q_UNUSED(pos);
// Validate the passed Bitcoin address
- CBitcoinAddress addr(input.toStdString());
- if (addr.IsValid())
+ if (IsValidDestinationString(input.toStdString())) {
return QValidator::Acceptable;
+ }
return QValidator::Invalid;
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index e3970298e6..be2d21daee 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -454,6 +454,7 @@ void BitcoinGUI::createToolBars()
if(walletFrame)
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
+ toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
toolbar->setMovable(false);
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
diff --git a/src/qt/callback.h b/src/qt/callback.h
index a8b593a652..da6b0c4c2e 100644
--- a/src/qt/callback.h
+++ b/src/qt/callback.h
@@ -16,7 +16,7 @@ class FunctionCallback : public Callback
F f;
public:
- FunctionCallback(F f_) : f(std::move(f_)) {}
+ explicit FunctionCallback(F f_) : f(std::move(f_)) {}
~FunctionCallback() override {}
void call() override { f(this); }
};
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index f3ee0fbe39..3ca43eae22 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -18,6 +18,7 @@
#include "policy/fees.h"
#include "policy/policy.h"
#include "validation.h" // For mempool
+#include "wallet/fees.h"
#include "wallet/wallet.h"
#include <QApplication>
@@ -510,7 +511,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
nBytes -= 34;
// Fee
- nPayFee = CWallet::GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
+ nPayFee = GetMinimumFee(nBytes, *coinControl, ::mempool, ::feeEstimator, nullptr /* FeeCalculation */);
if (nPayAmount > 0)
{
@@ -659,7 +660,7 @@ void CoinControlDialog::updateView()
QString sAddress = "";
if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, outputAddress))
{
- sAddress = QString::fromStdString(CBitcoinAddress(outputAddress).ToString());
+ sAddress = QString::fromStdString(EncodeDestination(outputAddress));
// if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs
if (!treeMode || (!(sAddress == sWalletAddress)))
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 99a9f893ff..4949c91771 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -30,9 +30,9 @@ namespace Ui {
class CCoinControlWidgetItem : public QTreeWidgetItem
{
public:
- CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
- CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
- CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ explicit CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
+ explicit CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {}
+ explicit CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {}
bool operator<(const QTreeWidgetItem &other) const;
};
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 14078b9ee8..e31bfee05e 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -199,10 +199,10 @@
<item>
<widget class="QCheckBox" name="allowIncoming">
<property name="toolTip">
- <string>Accept connections from outside</string>
+ <string>Accept connections from outside.</string>
</property>
<property name="text">
- <string>Allow incoming connections</string>
+ <string>Allow incomin&amp;g connections</string>
</property>
</widget>
</item>
@@ -399,7 +399,7 @@
<string>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</string>
</property>
<property name="text">
- <string>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</string>
+ <string>Use separate SOCKS&amp;5 proxy to reach peers via Tor hidden services:</string>
</property>
</widget>
</item>
@@ -507,10 +507,10 @@
<item>
<widget class="QCheckBox" name="hideTrayIcon">
<property name="toolTip">
- <string>&amp;Hide the icon from the system tray.</string>
+ <string>Hide the icon from the system tray.</string>
</property>
<property name="text">
- <string>Hide tray icon</string>
+ <string>&amp;Hide tray icon</string>
</property>
</widget>
</item>
@@ -610,7 +610,7 @@
<string>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</string>
</property>
<property name="text">
- <string>Third party transaction URLs</string>
+ <string>&amp;Third party transaction URLs</string>
</property>
<property name="buddy">
<cstring>thirdPartyTxUrls</cstring>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index f3c5daebec..ea5343c19d 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -112,8 +112,9 @@ static std::string DummyAddress(const CChainParams &params)
sourcedata.insert(sourcedata.end(), dummydata, dummydata + sizeof(dummydata));
for(int i=0; i<256; ++i) { // Try every trailing byte
std::string s = EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
- if (!CBitcoinAddress(s).IsValid())
+ if (!IsValidDestinationString(s)) {
return s;
+ }
sourcedata[sourcedata.size()-1] += 1;
}
return "";
@@ -248,7 +249,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info)
bool isDust(const QString& address, const CAmount& amount)
{
- CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
+ CTxDestination dest = DecodeDestination(address.toStdString());
CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script);
return IsDust(txOut, ::dustRelayFee);
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 72809942f1..0ff95d8502 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -43,7 +43,7 @@ class FreespaceChecker : public QObject
Q_OBJECT
public:
- FreespaceChecker(Intro *intro);
+ explicit FreespaceChecker(Intro *intro);
enum Status {
ST_OK,
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index a41d39d51e..9e7de0f98f 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -18,7 +18,7 @@
extern void qt_mac_set_dock_menu(QMenu *);
#endif
-static MacDockIconHandler *s_instance = NULL;
+static MacDockIconHandler *s_instance = nullptr;
bool dockClickHandler(id self,SEL _cmd,...) {
Q_UNUSED(self)
@@ -34,7 +34,7 @@ void setupDockClickHandler() {
Class cls = objc_getClass("NSApplication");
id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication"));
- if (appInst != NULL) {
+ if (appInst != nullptr) {
id delegate = objc_msgSend(appInst, sel_registerName("delegate"));
Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class"));
SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
@@ -53,7 +53,7 @@ MacDockIconHandler::MacDockIconHandler() : QObject()
setupDockClickHandler();
this->m_dummyWidget = new QWidget();
this->m_dockMenu = new QMenu(this->m_dummyWidget);
- this->setMainWindow(NULL);
+ this->setMainWindow(nullptr);
#if QT_VERSION < 0x050000
qt_mac_set_dock_menu(this->m_dockMenu);
#elif QT_VERSION >= 0x050200
@@ -69,7 +69,7 @@ void MacDockIconHandler::setMainWindow(QMainWindow *window) {
MacDockIconHandler::~MacDockIconHandler()
{
delete this->m_dummyWidget;
- this->setMainWindow(NULL);
+ this->setMainWindow(nullptr);
}
QMenu *MacDockIconHandler::dockMenu()
diff --git a/src/qt/macnotificationhandler.mm b/src/qt/macnotificationhandler.mm
index dd3f622818..4c96d08c8a 100644
--- a/src/qt/macnotificationhandler.mm
+++ b/src/qt/macnotificationhandler.mm
@@ -75,7 +75,7 @@ bool MacNotificationHandler::hasUserNotificationCenterSupport(void)
MacNotificationHandler *MacNotificationHandler::instance()
{
- static MacNotificationHandler *s_instance = NULL;
+ static MacNotificationHandler *s_instance = nullptr;
if (!s_instance) {
s_instance = new MacNotificationHandler();
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 8718929c6a..a7a7a4ce11 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -93,7 +93,7 @@ class FreedesktopImage
{
public:
FreedesktopImage() {}
- FreedesktopImage(const QImage &img);
+ explicit FreedesktopImage(const QImage &img);
static int metaType();
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index b80b6541dd..53e2e5053c 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -17,10 +17,6 @@
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h" // for CWallet::GetRequiredFee()
-#endif
-
#include <QDataWidgetMapper>
#include <QDir>
#include <QIntValidator>
@@ -80,6 +76,8 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(tr(PACKAGE_NAME)));
ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(tr(PACKAGE_NAME)));
+ ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(tr(PACKAGE_NAME)));
+
ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME)));
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
for (const QString &langStr : translations.entryList())
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index ba344f4dbf..ba1839e7b4 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -25,7 +25,7 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
+ explicit TxViewDelegate(const PlatformStyle *_platformStyle, QObject *parent=nullptr):
QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(_platformStyle)
{
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 0a5cb98668..d3799f59ab 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -22,7 +22,7 @@
class SSLVerifyError : public std::runtime_error
{
public:
- SSLVerifyError(std::string err) : std::runtime_error(err) { }
+ explicit SSLVerifyError(std::string err) : std::runtime_error(err) { }
};
bool PaymentRequestPlus::parse(const QByteArray& data)
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index d4137d280f..169684cf6d 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -218,17 +218,15 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
SendCoinsRecipient r;
if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty())
{
- CBitcoinAddress address(r.address.toStdString());
auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
- if (address.IsValid(*tempChainParams))
- {
+ if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::MAIN);
- }
- else {
+ } else {
tempChainParams = CreateChainParams(CBaseChainParams::TESTNET);
- if (address.IsValid(*tempChainParams))
+ if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) {
SelectParams(CBaseChainParams::TESTNET);
+ }
}
}
}
@@ -441,8 +439,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (GUIUtil::parseBitcoinURI(s, &recipient))
{
- CBitcoinAddress address(recipient.address.toStdString());
- if (!address.IsValid()) {
+ if (!IsValidDestinationString(recipient.address.toStdString())) {
Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
@@ -560,7 +557,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
// Append destination address
- addresses.append(QString::fromStdString(CBitcoinAddress(dest).ToString()));
+ addresses.append(QString::fromStdString(EncodeDestination(dest)));
}
else if (!recipient.authenticatedMerchant.isEmpty()) {
// Unauthenticated payment requests to custom bitcoin addresses are not supported
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index f845c4c7c8..98b2364b92 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -72,7 +72,7 @@ public:
static bool ipcSendCommandLine();
// parent should be QApplication object
- PaymentServer(QObject* parent, bool startLocalServer = true);
+ explicit PaymentServer(QObject* parent, bool startLocalServer = true);
~PaymentServer();
// Load root certificate authorities. Pass nullptr (default)
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index a01886c3ea..05c5ccbfe2 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -22,7 +22,7 @@
#include "ui_interface.h"
#include "txmempool.h"
#include "policy/fees.h"
-#include "wallet/wallet.h"
+#include "wallet/fees.h"
#include <QFontMetrics>
#include <QMessageBox>
@@ -185,7 +185,7 @@ void SendCoinsDialog::setModel(WalletModel *_model)
connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel()));
connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels()));
- ui->customFee->setSingleStep(CWallet::GetRequiredFee(1000));
+ ui->customFee->setSingleStep(GetRequiredFee(1000));
updateFeeSectionControls();
updateMinFeeLabel();
updateSmartFeeLabel();
@@ -610,7 +610,7 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
void SendCoinsDialog::setMinimumFee()
{
ui->radioCustomPerKilobyte->setChecked(true);
- ui->customFee->setValue(CWallet::GetRequiredFee(1000));
+ ui->customFee->setValue(GetRequiredFee(1000));
}
void SendCoinsDialog::updateFeeSectionControls()
@@ -643,7 +643,7 @@ void SendCoinsDialog::updateMinFeeLabel()
{
if (model && model->getOptionsModel())
ui->checkBoxMinimumFee->setText(tr("Pay only the required fee of %1").arg(
- BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), CWallet::GetRequiredFee(1000)) + "/kB")
+ BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), GetRequiredFee(1000)) + "/kB")
);
}
@@ -668,7 +668,7 @@ void SendCoinsDialog::updateSmartFeeLabel()
updateCoinControlState(coin_control);
coin_control.m_feerate.reset(); // Explicitly use only fee estimation rate for smart fee labels
FeeCalculation feeCalc;
- CFeeRate feeRate = CFeeRate(CWallet::GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
+ CFeeRate feeRate = CFeeRate(GetMinimumFee(1000, coin_control, ::mempool, ::feeEstimator, &feeCalc));
ui->labelSmartFee->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK()) + "/kB");
@@ -777,22 +777,19 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
CoinControlDialog::coinControl->destChange = CNoDestination();
ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:red;}");
- CBitcoinAddress addr = CBitcoinAddress(text.toStdString());
+ const CTxDestination dest = DecodeDestination(text.toStdString());
if (text.isEmpty()) // Nothing entered
{
ui->labelCoinControlChangeLabel->setText("");
}
- else if (!addr.IsValid()) // Invalid address
+ else if (!IsValidDestination(dest)) // Invalid address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Invalid Bitcoin address"));
}
else // Valid address
{
- CKeyID keyid;
- addr.GetKeyID(keyid);
- if (!model->havePrivKey(keyid)) // Unknown change address
- {
+ if (!model->IsSpendable(dest)) {
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
// confirmation dialog
@@ -800,7 +797,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
if(btnRetVal == QMessageBox::Yes)
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
else
{
ui->lineEditCoinControlChange->setText("");
@@ -819,7 +816,7 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
else
ui->labelCoinControlChangeLabel->setText(tr("(no label)"));
- CoinControlDialog::coinControl->destChange = addr.Get();
+ CoinControlDialog::coinControl->destChange = dest;
}
}
}
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 0950ed0234..4e37b81654 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -117,16 +117,14 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
/* Clear old signature to ensure users don't get confused on error with an old signature displayed */
ui->signatureOut_SM->clear();
- CBitcoinAddress addr(ui->addressIn_SM->text().toStdString());
- if (!addr.IsValid())
- {
+ CTxDestination destination = DecodeDestination(ui->addressIn_SM->text().toStdString());
+ if (!IsValidDestination(destination)) {
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
- {
+ const CKeyID* keyID = boost::get<CKeyID>(&destination);
+ if (!keyID) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -142,7 +140,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
- if (!model->getPrivKey(keyID, key))
+ if (!model->getPrivKey(*keyID, key))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
@@ -197,16 +195,13 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
{
- CBitcoinAddress addr(ui->addressIn_VM->text().toStdString());
- if (!addr.IsValid())
- {
+ CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString());
+ if (!IsValidDestination(destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
- {
+ if (!boost::get<CKeyID>(&destination)) {
ui->addressIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -237,8 +232,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- if (!(CBitcoinAddress(pubkey.GetID()) == addr))
- {
+ if (!(CTxDestination(pubkey.GetID()) == destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
return;
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index cd9ab23457..70fdd4bf58 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -11,7 +11,6 @@
#include "rpc/register.h"
#include "rpc/server.h"
#include "rpcconsole.h"
-#include "test/testutil.h"
#include "test/test_bitcoin.h"
#include "univalue.h"
#include "util.h"
@@ -29,7 +28,7 @@ static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
static const CRPCCommand vRPCCommands[] =
{
- { "test", "rpcNestedTest", &rpcNestedTest_rpc, true, {} },
+ { "test", "rpcNestedTest", &rpcNestedTest_rpc, {} },
};
void RPCNestedTests::rpcNestedTests()
@@ -37,11 +36,6 @@ void RPCNestedTests::rpcNestedTests()
// do some test setup
// could be moved to a more generic place when we add more tests on QT level
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
- ClearDatadirCache();
- std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
- QDir dir(QString::fromStdString(path));
- dir.mkpath(".");
- gArgs.ForceSetArg("-datadir", path);
//mempool.setSanityCheck(1.0);
TestingSetup test;
@@ -136,6 +130,4 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif
-
- fs::remove_all(fs::path(path));
}
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 80a00a634a..4c04e67ccc 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -53,6 +53,10 @@ int main(int argc, char *argv[])
SetupNetworking();
SelectParams(CBaseChainParams::MAIN);
noui_connect();
+ ClearDatadirCache();
+ fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
+ fs::create_directories(pathTemp);
+ gArgs.ForceSetArg("-datadir", pathTemp.string());
bool fInvalid = false;
@@ -97,5 +101,7 @@ int main(int argc, char *argv[])
}
#endif
+ fs::remove_all(pathTemp);
+
return fInvalid;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index ff1eb59f16..5031d7651d 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -57,11 +57,11 @@ void ConfirmSend(QString* text = nullptr, bool cancel = false)
}
//! Send coins to address and return txid.
-uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf)
+uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
{
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<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
sendCoinsDialog.findChild<QFrame*>("frameFee")
->findChild<QFrame*>("frameFeeSelection")
@@ -172,8 +172,8 @@ void TestSendCoins()
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105);
- uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */);
- uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */);
+ uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
+ uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
QCOMPARE(transactionTableModel->rowCount({}), 107);
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index bcacc47ef3..74f5c774a0 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -91,9 +91,8 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (nNet > 0)
{
// Credit
- if (CBitcoinAddress(rec->address).IsValid())
- {
- CTxDestination address = CBitcoinAddress(rec->address).Get();
+ CTxDestination address = DecodeDestination(rec->address);
+ if (IsValidDestination(address)) {
if (wallet->mapAddressBook.count(address))
{
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
@@ -118,7 +117,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
// Online transaction
std::string strAddress = wtx.mapValue["to"];
strHTML += "<b>" + tr("To") + ":</b> ";
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ CTxDestination dest = DecodeDestination(strAddress);
if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest].name) + " ";
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
@@ -189,7 +188,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("To") + ":</b> ";
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
- strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
+ strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE)
strHTML += " (own address)";
else if(toSelf & ISMINE_WATCH_ONLY)
@@ -304,7 +303,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
{
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].name.empty())
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address].name) + " ";
- strHTML += QString::fromStdString(CBitcoinAddress(address).ToString());
+ strHTML += QString::fromStdString(EncodeDestination(address));
}
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>";
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 36d98ce49d..d40ffd22cd 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -55,7 +55,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
- sub.address = CBitcoinAddress(address).ToString();
+ sub.address = EncodeDestination(address);
}
else
{
@@ -127,7 +127,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
- sub.address = CBitcoinAddress(address).ToString();
+ sub.address = EncodeDestination(address);
}
else
{
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index acaa864148..738eeed136 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -41,7 +41,7 @@ class ShutdownWindow : public QWidget
Q_OBJECT
public:
- ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
+ explicit ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0);
static QWidget *showShutdownWindow(BitcoinGUI *window);
protected:
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 3ca726d0f9..53b1c2967c 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -188,8 +188,7 @@ void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
bool WalletModel::validateAddress(const QString &address)
{
- CBitcoinAddress addressParsed(address.toStdString());
- return addressParsed.IsValid();
+ return IsValidDestinationString(address.toStdString());
}
WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl)
@@ -247,7 +246,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
setAddress.insert(rcp.address);
++nAddresses;
- CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get());
+ CScript scriptPubKey = GetScriptForDestination(DecodeDestination(rcp.address.toStdString()));
CRecipient recipient = {scriptPubKey, rcp.amount, rcp.fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@@ -348,7 +347,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
if (!rcp.paymentRequest.IsInitialized())
{
std::string strAddress = rcp.address.toStdString();
- CTxDestination dest = CBitcoinAddress(strAddress).Get();
+ CTxDestination dest = DecodeDestination(strAddress);
std::string strLabel = rcp.label.toStdString();
{
LOCK(wallet->cs_wallet);
@@ -464,7 +463,7 @@ static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet,
const CTxDestination &address, const std::string &label, bool isMine,
const std::string &purpose, ChangeType status)
{
- QString strAddress = QString::fromStdString(CBitcoinAddress(address).ToString());
+ QString strAddress = QString::fromStdString(EncodeDestination(address));
QString strLabel = QString::fromStdString(label);
QString strPurpose = QString::fromStdString(purpose);
@@ -561,9 +560,9 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
return wallet->GetPubKey(address, vchPubKeyOut);
}
-bool WalletModel::havePrivKey(const CKeyID &address) const
+bool WalletModel::IsSpendable(const CTxDestination& dest) const
{
- return wallet->HaveKey(address);
+ return IsMine(*wallet, dest) & ISMINE_SPENDABLE;
}
bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
@@ -577,10 +576,11 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
LOCK2(cs_main, wallet->cs_wallet);
for (const COutPoint& outpoint : vOutpoints)
{
- if (!wallet->mapWallet.count(outpoint.hash)) continue;
- int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
+ auto it = wallet->mapWallet.find(outpoint.hash);
+ if (it == wallet->mapWallet.end()) continue;
+ int nDepth = it->second.GetDepthInMainChain();
if (nDepth < 0) continue;
- COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
+ COutput out(&it->second, outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */);
vOutputs.push_back(out);
}
}
@@ -595,7 +595,7 @@ bool WalletModel::isSpent(const COutPoint& outpoint) const
void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const
{
for (auto& group : wallet->ListCoins()) {
- auto& resultGroup = mapCoins[QString::fromStdString(CBitcoinAddress(group.first).ToString())];
+ auto& resultGroup = mapCoins[QString::fromStdString(EncodeDestination(group.first))];
for (auto& coin : group.second) {
resultGroup.emplace_back(std::move(coin));
}
@@ -633,7 +633,7 @@ void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests
bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
{
- CTxDestination dest = CBitcoinAddress(sAddress).Get();
+ CTxDestination dest = DecodeDestination(sAddress);
std::stringstream ss;
ss << nId;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 6be36a57e2..05733f8272 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -190,7 +190,7 @@ public:
UnlockContext requestUnlock();
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
- bool havePrivKey(const CKeyID &address) const;
+ bool IsSpendable(const CTxDestination& dest) const;
bool getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const;
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
bool isSpent(const COutPoint& outpoint) const;
diff --git a/src/random.cpp b/src/random.cpp
index b004bfa91e..7e0e94439e 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -46,10 +46,10 @@
#include <openssl/err.h>
#include <openssl/rand.h>
-static void RandFailure()
+[[noreturn]] static void RandFailure()
{
LogPrintf("Failed to read randomness, aborting\n");
- abort();
+ std::abort();
}
static inline int64_t GetPerformanceCounter()
@@ -242,7 +242,7 @@ void GetOSRand(unsigned char *ent32)
}
#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
// We need a fallback for OSX < 10.12
- if (&getentropy != NULL) {
+ if (&getentropy != nullptr) {
if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
RandFailure();
}
diff --git a/src/rest.cpp b/src/rest.cpp
index 6a4b005f90..0b2c843d5f 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -48,7 +48,7 @@ struct CCoin {
ADD_SERIALIZE_METHODS;
CCoin() : nHeight(0) {}
- CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
+ explicit CCoin(Coin&& in) : nHeight(in.nHeight), out(std::move(in.out)) {}
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
@@ -190,9 +190,6 @@ static bool rest_headers(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_block(HTTPRequest* req,
@@ -253,9 +250,6 @@ static bool rest_block(HTTPRequest* req,
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart)
@@ -292,9 +286,6 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
@@ -317,9 +308,6 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart)
@@ -342,9 +330,6 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
@@ -394,9 +379,6 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
@@ -581,9 +563,6 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
-
- // not reached
- return true; // continue to process further HTTP reqs on this cxn
}
static const struct {
diff --git a/src/reverse_iterator.h b/src/reverse_iterator.h
index 46789e5417..ab467f07c9 100644
--- a/src/reverse_iterator.h
+++ b/src/reverse_iterator.h
@@ -17,7 +17,7 @@ class reverse_range
T &m_x;
public:
- reverse_range(T &x) : m_x(x) {}
+ explicit reverse_range(T &x) : m_x(x) {}
auto begin() const -> decltype(this->m_x.rbegin())
{
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 24e0405a84..46f4f16321 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -125,7 +125,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
if(txDetails)
{
UniValue objTx(UniValue::VOBJ);
- TxToUniv(*tx, uint256(), objTx);
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
txs.push_back(objTx);
}
else
@@ -343,6 +343,7 @@ std::string EntryDescriptionString()
" \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n"
" \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n"
" \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n"
+ " \"wtxid\" : hash, (string) hash of serialized transaction, including witness data\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n";
@@ -363,6 +364,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("ancestorcount", e.GetCountWithAncestors()));
info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors()));
info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors()));
+ info.push_back(Pair("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString()));
const CTransaction& tx = e.GetTx();
std::set<std::string> setDepends;
for (const CTxIn& txin : tx.vin)
@@ -812,6 +814,7 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash,
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ assert(pcursor);
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -944,9 +947,10 @@ UniValue gettxout(const JSONRPCRequest& request)
"gettxout \"txid\" n ( include_mempool )\n"
"\nReturns details about an unspent transaction output.\n"
"\nArguments:\n"
- "1. \"txid\" (string, required) The transaction id\n"
- "2. n (numeric, required) vout number\n"
- "3. include_mempool (boolean, optional) Whether to include the mempool\n"
+ "1. \"txid\" (string, required) The transaction id\n"
+ "2. \"n\" (numeric, required) vout number\n"
+ "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true."
+ " Note that an unspent output that is spent in the mempool won't appear.\n"
"\nResult:\n"
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
@@ -1343,7 +1347,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request)
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
- " \"mempoolminfee\": xxxxx (numeric) Minimum feerate (" + CURRENCY_UNIT + " per KB) for tx to be accepted\n"
+ " \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmempoolinfo", "")
@@ -1489,11 +1493,11 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
const CBlockIndex* pindex;
int blockcount = 30 * 24 * 60 * 60 / Params().GetConsensus().nPowTargetSpacing; // By default: 1 month
- if (request.params.size() > 0 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
blockcount = request.params[0].get_int();
}
- bool havehash = request.params.size() > 1 && !request.params[1].isNull();
+ bool havehash = !request.params[1].isNull();
uint256 hash;
if (havehash) {
hash = uint256S(request.params[1].get_str());
@@ -1514,6 +1518,8 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
pindex = chainActive.Tip();
}
}
+
+ assert(pindex != nullptr);
if (blockcount < 1 || blockcount >= pindex->nHeight) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 1 and the block's height");
@@ -1531,36 +1537,56 @@ UniValue getchaintxstats(const JSONRPCRequest& request)
return ret;
}
+UniValue savemempool(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 0) {
+ throw std::runtime_error(
+ "savemempool\n"
+ "\nDumps the mempool to disk.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("savemempool", "")
+ + HelpExampleRpc("savemempool", "")
+ );
+ }
+
+ if (!DumpMempool()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
+ }
+
+ return NullUniValue;
+}
+
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} },
- { "blockchain", "getchaintxstats", &getchaintxstats, true, {"nblocks", "blockhash"} },
- { "blockchain", "getbestblockhash", &getbestblockhash, true, {} },
- { "blockchain", "getblockcount", &getblockcount, true, {} },
- { "blockchain", "getblock", &getblock, true, {"blockhash","verbosity|verbose"} },
- { "blockchain", "getblockhash", &getblockhash, true, {"height"} },
- { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} },
- { "blockchain", "getchaintips", &getchaintips, true, {} },
- { "blockchain", "getdifficulty", &getdifficulty, true, {} },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} },
- { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} },
- { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} },
- { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} },
- { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} },
- { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} },
-
- { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, {} },
+ { "blockchain", "getchaintxstats", &getchaintxstats, {"nblocks", "blockhash"} },
+ { "blockchain", "getbestblockhash", &getbestblockhash, {} },
+ { "blockchain", "getblockcount", &getblockcount, {} },
+ { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
+ { "blockchain", "getblockhash", &getblockhash, {"height"} },
+ { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} },
+ { "blockchain", "getchaintips", &getchaintips, {} },
+ { "blockchain", "getdifficulty", &getdifficulty, {} },
+ { "blockchain", "getmempoolancestors", &getmempoolancestors, {"txid","verbose"} },
+ { "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} },
+ { "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, {} },
+ { "blockchain", "getrawmempool", &getrawmempool, {"verbose"} },
+ { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {} },
+ { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} },
+ { "blockchain", "savemempool", &savemempool, {} },
+ { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} },
+
+ { "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} },
- { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} },
- { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} },
- { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} },
- { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} },
+ { "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
+ { "hidden", "reconsiderblock", &reconsiderblock, {"blockhash"} },
+ { "hidden", "waitfornewblock", &waitfornewblock, {"timeout"} },
+ { "hidden", "waitforblock", &waitforblock, {"blockhash","timeout"} },
+ { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} },
};
void RegisterBlockchainRPCCommands(CRPCTable &t)
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f498b5c8ea..9809883700 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -176,12 +176,13 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
nMaxTries = request.params[2].get_int();
}
- CBitcoinAddress address(request.params[1].get_str());
- if (!address.IsValid())
+ CTxDestination destination = DecodeDestination(request.params[1].get_str());
+ if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
+ }
std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
- coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
+ coinbaseScript->reserveScript = GetScriptForDestination(destination);
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
@@ -336,7 +337,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
- " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+ " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
" \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
" \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
" \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
@@ -346,7 +347,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
" \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
" \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n"
" },\n"
- " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+ " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)\n"
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
" \"target\" : \"xxxx\", (string) The hash target\n"
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
@@ -686,7 +687,7 @@ public:
bool found;
CValidationState state;
- submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
+ explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
protected:
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
@@ -825,7 +826,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
" \"CONSERVATIVE\"\n"
"\nResult:\n"
"{\n"
- " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
@@ -842,7 +843,7 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int conf_target = ParseConfirmTarget(request.params[0]);
bool conservative = true;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
FeeEstimateMode fee_mode;
if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
@@ -884,7 +885,7 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
"\nResult:\n"
"{\n"
" \"short\" : { (json object, optional) estimate for short time horizon\n"
- " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
+ " \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
" \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
" \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n"
@@ -967,20 +968,21 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
- { "mining", "getmininginfo", &getmininginfo, true, {} },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","dummy","fee_delta"} },
- { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
- { "mining", "submitblock", &submitblock, true, {"hexdata","dummy"} },
+ { "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} },
+ { "mining", "getmininginfo", &getmininginfo, {} },
+ { "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
+ { "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
+ { "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
+
- { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
+ { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
- { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
- { "util", "estimatesmartfee", &estimatesmartfee, true, {"conf_target", "estimate_mode"} },
+ { "util", "estimatefee", &estimatefee, {"nblocks"} },
+ { "util", "estimatesmartfee", &estimatesmartfee, {"nblocks", "estimate_mode"} },
- { "hidden", "estimaterawfee", &estimaterawfee, true, {"conf_target", "threshold"} },
+ { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} },
};
void RegisterMiningRPCCommands(CRPCTable &t)
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index efff4a99ae..2037ebe3c4 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -31,101 +31,13 @@
#include <univalue.h>
-/**
- * @note Do not add or change anything in the information returned by this
- * method. `getinfo` exists for backwards-compatibility only. It combines
- * information from wildly different sources in the program, which is a mess,
- * and is thus planned to be deprecated eventually.
- *
- * Based on the source of the information, new information should be added to:
- * - `getblockchaininfo`,
- * - `getnetworkinfo` or
- * - `getwalletinfo`
- *
- * Or alternatively, create a specific query method for the information.
- **/
-UniValue getinfo(const JSONRPCRequest& request)
-{
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
- "getinfo\n"
- "\nDEPRECATED. Returns an object containing various state info.\n"
- "\nResult:\n"
- "{\n"
- " \"deprecation-warning\": \"...\" (string) warning that the getinfo command is deprecated and will be removed in 0.16\n"
- " \"version\": xxxxx, (numeric) the server version\n"
- " \"protocolversion\": xxxxx, (numeric) the protocol version\n"
- " \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"timeoffset\": xxxxx, (numeric) the time offset\n"
- " \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
- " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n"
- " \"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 transactions in " + CURRENCY_UNIT + "/kB\n"
- " \"errors\": \"...\" (string) any error messages\n"
- "}\n"
- "\nExamples:\n"
- + HelpExampleCli("getinfo", "")
- + HelpExampleRpc("getinfo", "")
- );
-
-#ifdef ENABLE_WALLET
- CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
-
- LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
-#else
- LOCK(cs_main);
-#endif
-
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
- UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("deprecation-warning", "WARNING: getinfo is deprecated and will be fully removed in 0.16."
- " Projects should transition to using getblockchaininfo, getnetworkinfo, and getwalletinfo before upgrading to 0.16"));
- obj.push_back(Pair("version", CLIENT_VERSION));
- obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
-#ifdef ENABLE_WALLET
- if (pwallet) {
- obj.push_back(Pair("walletversion", pwallet->GetVersion()));
- obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
- }
-#endif
- obj.push_back(Pair("blocks", (int)chainActive.Height()));
- 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() : std::string())));
- obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
-#ifdef ENABLE_WALLET
- if (pwallet) {
- obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize()));
- }
- if (pwallet && pwallet->IsCrypted()) {
- obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
- }
- obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
-#endif
- obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
- obj.push_back(Pair("errors", GetWarnings("statusbar")));
- return obj;
-}
-
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
CWallet * const pwallet;
- DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
+ explicit DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
@@ -152,8 +64,9 @@ public:
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
UniValue a(UniValue::VARR);
- for (const CTxDestination& addr : addresses)
- a.push_back(CBitcoinAddress(addr).ToString());
+ for (const CTxDestination& addr : addresses) {
+ a.push_back(EncodeDestination(addr));
+ }
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
@@ -207,15 +120,14 @@ UniValue validateaddress(const JSONRPCRequest& request)
LOCK(cs_main);
#endif
- CBitcoinAddress address(request.params[0].get_str());
- bool isValid = address.IsValid();
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ bool isValid = IsValidDestination(dest);
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
- CTxDestination dest = address.Get();
- std::string currentAddress = address.ToString();
+ std::string currentAddress = EncodeDestination(dest);
ret.push_back(Pair("address", currentAddress));
CScript scriptPubKey = GetScriptForDestination(dest);
@@ -230,10 +142,10 @@ UniValue validateaddress(const JSONRPCRequest& request)
if (pwallet && pwallet->mapAddressBook.count(dest)) {
ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
}
- CKeyID keyID;
if (pwallet) {
const auto& meta = pwallet->mapKeyMetadata;
- auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end();
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ auto it = keyID ? meta.find(*keyID) : meta.end();
if (it == meta.end()) {
it = meta.find(CScriptID(scriptPubKey));
}
@@ -277,16 +189,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa
const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key:
- CBitcoinAddress address(ks);
- if (pwallet && address.IsValid()) {
- CKeyID keyID;
- if (!address.GetKeyID(keyID))
- throw std::runtime_error(
- strprintf("%s does not refer to a key",ks));
+ CTxDestination dest = DecodeDestination(ks);
+ if (pwallet && IsValidDestination(dest)) {
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
+ throw std::runtime_error(strprintf("%s does not refer to a key", ks));
+ }
CPubKey vchPubKey;
- if (!pwallet->GetPubKey(keyID, vchPubKey)) {
- throw std::runtime_error(
- strprintf("no full public key for address %s",ks));
+ if (!pwallet->GetPubKey(*keyID, vchPubKey)) {
+ throw std::runtime_error(strprintf("no full public key for address %s", ks));
}
if (!vchPubKey.IsFullyValid())
throw std::runtime_error(" Invalid public key: "+ks);
@@ -357,10 +268,9 @@ UniValue createmultisig(const JSONRPCRequest& request)
// Construct using pay-to-script-hash:
CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner);
- CBitcoinAddress address(innerID);
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("address", address.ToString()));
+ result.push_back(Pair("address", EncodeDestination(innerID)));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
@@ -395,13 +305,15 @@ UniValue verifymessage(const JSONRPCRequest& request)
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
- CBitcoinAddress addr(strAddress);
- if (!addr.IsValid())
+ CTxDestination destination = DecodeDestination(strAddress);
+ if (!IsValidDestination(destination)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
+ }
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
+ const CKeyID *keyID = boost::get<CKeyID>(&destination);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
bool fInvalid = false;
std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
@@ -417,7 +329,7 @@ UniValue verifymessage(const JSONRPCRequest& request)
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
- return (pubkey.GetID() == keyID);
+ return (pubkey.GetID() == *keyID);
}
UniValue signmessagewithprivkey(const JSONRPCRequest& request)
@@ -552,7 +464,7 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getmemoryinfo", "")
);
- std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str();
+ std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str();
if (mode == "stats") {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("locked", RPCLockedMemoryInfo()));
@@ -603,11 +515,11 @@ UniValue logging(const JSONRPCRequest& request)
}
uint32_t originalLogCategories = logCategories;
- if (request.params.size() > 0 && request.params[0].isArray()) {
+ if (request.params[0].isArray()) {
logCategories |= getCategoryMask(request.params[0]);
}
- if (request.params.size() > 1 && request.params[1].isArray()) {
+ if (request.params[1].isArray()) {
logCategories &= ~getCategoryMask(request.params[1]);
}
@@ -649,20 +561,19 @@ UniValue echo(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */
- { "control", "getmemoryinfo", &getmemoryinfo, true, {"mode"} },
- { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */
- { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} },
- { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} },
+ { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
+ { "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */
+ { "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
+ { "util", "verifymessage", &verifymessage, {"address","signature","message"} },
+ { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
- { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "logging", &logging, true, {"include", "exclude"}},
+ { "hidden", "setmocktime", &setmocktime, {"timestamp"}},
+ { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", "logging", &logging, {"include", "exclude"}},
};
void RegisterMiscRPCCommands(CRPCTable &t)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index e463a4eda4..7faf216047 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -193,7 +193,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
UniValue addnode(const JSONRPCRequest& request)
{
std::string strCommand;
- if (request.params.size() == 2)
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
@@ -258,7 +258,7 @@ UniValue disconnectnode(const JSONRPCRequest& request)
bool success;
const UniValue &address_arg = request.params[0];
- const UniValue &id_arg = request.params.size() < 2 ? NullUniValue : request.params[1];
+ const UniValue &id_arg = request.params[1];
if (!address_arg.isNull() && id_arg.isNull()) {
/* handle disconnect-by-address */
@@ -311,7 +311,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (request.params.size() == 1 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
if (info.strAddedNode == request.params[0].get_str()) {
@@ -490,7 +490,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
UniValue setban(const JSONRPCRequest& request)
{
std::string strCommand;
- if (request.params.size() >= 2)
+ if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
@@ -534,11 +534,11 @@ UniValue setban(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
- if (request.params.size() >= 3 && !request.params[2].isNull())
+ if (!request.params[2].isNull())
banTime = request.params[2].get_int64();
bool absolute = false;
- if (request.params.size() == 4 && request.params[3].isTrue())
+ if (request.params[3].isTrue())
absolute = true;
isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
@@ -623,20 +623,20 @@ UniValue setnetworkactive(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, true, {} },
- { "network", "ping", &ping, true, {} },
- { "network", "getpeerinfo", &getpeerinfo, true, {} },
- { "network", "addnode", &addnode, true, {"node","command"} },
- { "network", "disconnectnode", &disconnectnode, true, {"address", "nodeid"} },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} },
- { "network", "getnettotals", &getnettotals, true, {} },
- { "network", "getnetworkinfo", &getnetworkinfo, true, {} },
- { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} },
- { "network", "listbanned", &listbanned, true, {} },
- { "network", "clearbanned", &clearbanned, true, {} },
- { "network", "setnetworkactive", &setnetworkactive, true, {"state"} },
+ { "network", "getconnectioncount", &getconnectioncount, {} },
+ { "network", "ping", &ping, {} },
+ { "network", "getpeerinfo", &getpeerinfo, {} },
+ { "network", "addnode", &addnode, {"node","command"} },
+ { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} },
+ { "network", "getnettotals", &getnettotals, {} },
+ { "network", "getnetworkinfo", &getnetworkinfo, {} },
+ { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} },
+ { "network", "listbanned", &listbanned, {} },
+ { "network", "clearbanned", &clearbanned, {} },
+ { "network", "setnetworkactive", &setnetworkactive, {"state"} },
};
void RegisterNetRPCCommands(CRPCTable &t)
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index db0626b5e1..dc6bcec382 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -66,9 +66,14 @@ static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
-fs::path GetAuthCookieFile()
+/** Get name of RPC authentication cookie file */
+static fs::path GetAuthCookieFile(bool temp=false)
{
- fs::path path(gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
+ if (temp) {
+ arg += ".tmp";
+ }
+ fs::path path(arg);
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
@@ -84,14 +89,20 @@ bool GenerateAuthCookie(std::string *cookie_out)
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
- fs::path filepath = GetAuthCookieFile();
- file.open(filepath.string().c_str());
+ fs::path filepath_tmp = GetAuthCookieFile(true);
+ file.open(filepath_tmp.string().c_str());
if (!file.is_open()) {
- LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath_tmp.string());
return false;
}
file << cookie;
file.close();
+
+ fs::path filepath = GetAuthCookieFile(false);
+ if (!RenameOver(filepath_tmp, filepath)) {
+ LogPrintf("Unable to rename cookie authentication file %s to %s\n", filepath_tmp.string(), filepath.string());
+ return false;
+ }
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 4bd4702d62..5c9c64f67d 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -91,8 +91,6 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
-/** Get name of RPC authentication cookie file */
-fs::path GetAuthCookieFile();
/** Generate a new RPC authentication cookie and write it to disk */
bool GenerateAuthCookie(std::string *cookie_out);
/** Read the RPC authentication cookie from disk */
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 8100511854..a0322f67b4 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -16,6 +16,7 @@
#include "policy/policy.h"
#include "policy/rbf.h"
#include "primitives/transaction.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "script/script.h"
#include "script/script_error.h"
@@ -41,7 +42,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
// Blockchain contextual information (confirmations and blocktime) is not
// available to code in bitcoin-common, so we query them here and push the
// data into the returned UniValue.
- TxToUniv(tx, uint256(), entry);
+ TxToUniv(tx, uint256(), entry, true, RPCSerializationFlags());
if (!hashBlock.IsNull()) {
entry.push_back(Pair("blockhash", hashBlock.GetHex()));
@@ -160,13 +161,10 @@ UniValue getrawtransaction(const JSONRPCRequest& request)
: "No such mempool transaction. Use -txindex to enable blockchain transaction queries") +
". Use gettransaction for wallet transactions.");
- std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags());
-
if (!fVerbose)
- return strHex;
+ return EncodeHexTx(*tx, RPCSerializationFlags());
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", strHex));
TxToJSON(*tx, hashBlock, result);
return result;
}
@@ -339,14 +337,14 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CMutableTransaction rawTx;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
}
- bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false;
+ bool rbfOptIn = request.params[3].isTrue();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
@@ -386,7 +384,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
rawTx.vin.push_back(in);
}
- std::set<CBitcoinAddress> setAddress;
+ std::set<CTxDestination> destinations;
std::vector<std::string> addrList = sendTo.getKeys();
for (const std::string& name_ : addrList) {
@@ -396,15 +394,16 @@ UniValue createrawtransaction(const JSONRPCRequest& request)
CTxOut out(0, CScript() << OP_RETURN << data);
rawTx.vout.push_back(out);
} else {
- CBitcoinAddress address(name_);
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
+ CTxDestination destination = DecodeDestination(name_);
+ if (!IsValidDestination(destination)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
- setAddress.insert(address);
+ if (!destinations.insert(destination).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CScript scriptPubKey = GetScriptForDestination(destination);
CAmount nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey);
@@ -483,7 +482,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
- TxToUniv(CTransaction(std::move(mtx)), uint256(), result);
+ TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false);
return result;
}
@@ -531,7 +530,7 @@ UniValue decodescript(const JSONRPCRequest& request)
if (type.isStr() && type.get_str() != "scripthash") {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
- r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script))));
}
return r;
@@ -572,7 +571,7 @@ UniValue combinerawtransaction(const JSONRPCRequest& request)
" ]\n"
"\nResult:\n"
- "\"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
+ "\"hex\" (string) The hex-encoded raw transaction with signature(s)\n"
"\nExamples:\n"
+ HelpExampleCli("combinerawtransaction", "[\"myhex1\", \"myhex2\", \"myhex3\"]")
@@ -706,6 +705,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
+ ObserveSafeMode();
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : nullptr);
#else
@@ -735,7 +735,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ if (!request.params[2].isNull()) {
fGivenKeys = true;
UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
@@ -757,7 +757,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
// Add previous txouts given in the RPC call:
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
@@ -828,7 +828,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
#endif
int nHashType = SIGHASH_ALL;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
+ if (!request.params[3].isNull()) {
static std::map<std::string, int> mapSigHashValues = {
{std::string("ALL"), int(SIGHASH_ALL)},
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
@@ -911,6 +911,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
+ ObserveSafeMode();
LOCK(cs_main);
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
@@ -922,7 +923,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
const uint256& hashTx = tx->GetHash();
CAmount nMaxRawTxFee = maxTxFee;
- if (request.params.size() > 1 && request.params[1].get_bool())
+ if (!request.params[1].isNull() && request.params[1].get_bool())
nMaxRawTxFee = 0;
CCoinsViewCache &view = *pcoinsTip;
@@ -962,18 +963,18 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
}
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
+{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable"} },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} },
- { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} },
- { "rawtransactions", "combinerawtransaction", &combinerawtransaction, true, {"txs"} },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
-
- { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose"} },
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} },
+ { "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */
+
+ { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} },
+ { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} },
};
void RegisterRawTransactionRPCCommands(CRPCTable &t)
diff --git a/src/rpc/safemode.cpp b/src/rpc/safemode.cpp
new file mode 100644
index 0000000000..24770ad47f
--- /dev/null
+++ b/src/rpc/safemode.cpp
@@ -0,0 +1,14 @@
+#include "safemode.h"
+
+#include "rpc/protocol.h"
+#include "util.h"
+#include "warnings.h"
+
+void ObserveSafeMode()
+{
+ std::string warning = GetWarnings("rpc");
+ if (warning != "" && !gArgs.GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE)) {
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + warning);
+ }
+}
+
diff --git a/src/rpc/safemode.h b/src/rpc/safemode.h
new file mode 100644
index 0000000000..8466d6b2f9
--- /dev/null
+++ b/src/rpc/safemode.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2017 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_RPC_SAFEMODE_H
+#define BITCOIN_RPC_SAFEMODE_H
+
+static const bool DEFAULT_DISABLE_SAFEMODE = true;
+
+void ObserveSafeMode();
+
+#endif // BITCOIN_RPC_SAFEMODE_H
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 9ad8d228fa..428ab3b9b0 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -51,11 +51,6 @@ void RPCServer::OnStopped(std::function<void ()> slot)
g_rpcSignals.Stopped.connect(slot);
}
-void RPCServer::OnPreCommand(std::function<void (const CRPCCommand&)> slot)
-{
- g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
-}
-
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected,
bool fAllowNull)
@@ -267,12 +262,12 @@ UniValue uptime(const JSONRPCRequest& jsonRequest)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafe argNames
- // --------------------- ------------------------ ----------------------- ------ ----------
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
- { "control", "help", &help, true, {"command"} },
- { "control", "stop", &stop, true, {} },
- { "control", "uptime", &uptime, true, {} },
+ { "control", "help", &help, {"command"} },
+ { "control", "stop", &stop, {} },
+ { "control", "uptime", &uptime, {} },
};
CRPCTable::CRPCTable()
diff --git a/src/rpc/server.h b/src/rpc/server.h
index dd6f763245..777acbcb94 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -25,13 +25,12 @@ namespace RPCServer
{
void OnStarted(std::function<void ()> slot);
void OnStopped(std::function<void ()> slot);
- void OnPreCommand(std::function<void (const CRPCCommand&)> slot);
}
/** Wrapper for UniValue::VType, which includes typeAny:
* Used to denote don't care type. Only used by RPCTypeCheckObj */
struct UniValueType {
- UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
+ explicit UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
UniValueType() : typeAny(true) {}
bool typeAny;
UniValue::VType type;
@@ -134,7 +133,6 @@ public:
std::string category;
std::string name;
rpcfn_type actor;
- bool okSafeMode;
std::vector<std::string> argNames;
};
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 1d3fb1f6ea..4edb2c6d9b 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -174,7 +174,7 @@ void SingleThreadedSchedulerClient::ProcessQueue() {
// to ensure both happen safely even if callback() throws.
struct RAIICallbacksRunning {
SingleThreadedSchedulerClient* instance;
- RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
+ explicit RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
~RAIICallbacksRunning() {
{
LOCK(instance->m_cs_callbacks_pending);
diff --git a/src/scheduler.h b/src/scheduler.h
index cc2f01f2ff..db93bcb21e 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -102,7 +102,7 @@ private:
void ProcessQueue();
public:
- SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
+ explicit SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
void AddToProcessQueue(std::function<void (void)> func);
// Processes all remaining queue members on the calling thread, blocking until queue is empty
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 437826b5dd..f845e1943b 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -114,7 +114,7 @@ struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs;
- PrecomputedTransactionData(const CTransaction& tx);
+ explicit PrecomputedTransactionData(const CTransaction& tx);
};
enum SigVersion
diff --git a/src/script/sign.h b/src/script/sign.h
index bd45862892..a0d8ee4ff9 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -21,7 +21,7 @@ protected:
const CKeyStore* keystore;
public:
- BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
+ explicit BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {}
const CKeyStore& KeyStore() const { return *keystore; };
virtual ~BaseSignatureCreator() {}
virtual const BaseSignatureChecker& Checker() const =0;
@@ -54,7 +54,7 @@ public:
/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
- DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
+ explicit DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
const BaseSignatureChecker& Checker() const override;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
};
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 9570b8c8d9..b6e2232ab4 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -34,9 +34,6 @@ const char* GetTxnOutputType(txnouttype t)
return nullptr;
}
-/**
- * Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
- */
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
{
// Templates
@@ -253,7 +250,7 @@ class CScriptVisitor : public boost::static_visitor<bool>
private:
CScript *script;
public:
- CScriptVisitor(CScript *scriptin) { script = scriptin; }
+ explicit CScriptVisitor(CScript *scriptin) { script = scriptin; }
bool operator()(const CNoDestination &dest) const {
script->clear();
@@ -320,3 +317,7 @@ CScript GetScriptForWitness(const CScript& redeemscript)
ret << OP_0 << ToByteVector(hash);
return ret;
}
+
+bool IsValidDestination(const CTxDestination& dest) {
+ return dest.which() != 0;
+}
diff --git a/src/script/standard.h b/src/script/standard.h
index 097e0c3748..8df143a3a3 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -27,8 +27,19 @@ public:
CScriptID(const uint160& in) : uint160(in) {}
};
-static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
+/**
+ * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
+ * +2 for the pushdata opcodes.
+ */
+static const unsigned int MAX_OP_RETURN_RELAY = 83;
+
+/**
+ * A data carrying output is an unspendable output containing data. The script
+ * type is designated as TX_NULL_DATA.
+ */
extern bool fAcceptDatacarrier;
+
+/** Maximum size of TX_NULL_DATA scripts that this node considers standard. */
extern unsigned nMaxDatacarrierBytes;
/**
@@ -36,7 +47,7 @@ extern unsigned nMaxDatacarrierBytes;
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
* but in the future other flags may be added, such as a soft-fork to enforce
* strict DER encoding.
- *
+ *
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
* details.
*/
@@ -50,7 +61,7 @@ enum txnouttype
TX_PUBKEYHASH,
TX_SCRIPTHASH,
TX_MULTISIG,
- TX_NULL_DATA,
+ TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
TX_WITNESS_V0_SCRIPTHASH,
TX_WITNESS_V0_KEYHASH,
};
@@ -61,24 +72,70 @@ public:
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};
-/**
+/**
* A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
* * CKeyID: TX_PUBKEYHASH destination
* * CScriptID: TX_SCRIPTHASH destination
- * A CTxDestination is the internal data type encoded in a CBitcoinAddress
+ * A CTxDestination is the internal data type encoded in a bitcoin address
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
+/** Check whether a CTxDestination is a CNoDestination. */
+bool IsValidDestination(const CTxDestination& dest);
+
+/** Get the name of a txnouttype as a C string, or nullptr if unknown. */
const char* GetTxnOutputType(txnouttype t);
+/**
+ * Parse a scriptPubKey and identify script type for standard scripts. If
+ * successful, returns script type and parsed pubkeys or hashes, depending on
+ * the type. For example, for a P2SH script, vSolutionsRet will contain the
+ * script hash, for P2PKH it will contain the key hash, etc.
+ *
+ * @param[in] scriptPubKey Script to parse
+ * @param[out] typeRet The script type
+ * @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
+ * @return True if script matches standard template
+ */
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
+
+/**
+ * Parse a standard scriptPubKey for the destination address. Assigns result to
+ * the addressRet parameter and returns true if successful. For multisig
+ * scripts, instead use ExtractDestinations. Currently only works for P2PK,
+ * P2PKH, and P2SH scripts.
+ */
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
+
+/**
+ * Parse a standard scriptPubKey with one or more destination addresses. For
+ * multisig scripts, this populates the addressRet vector with the pubkey IDs
+ * and nRequiredRet with the n required to spend. For other destinations,
+ * addressRet is populated with a single value and nRequiredRet is set to 1.
+ * Returns true if successful. Currently does not extract address from
+ * pay-to-witness scripts.
+ */
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
+/**
+ * Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
+ * script for a CKeyID destination, a P2SH script for a CScriptID, and an empty
+ * script for CNoDestination.
+ */
CScript GetScriptForDestination(const CTxDestination& dest);
+
+/** Generate a P2PK script for the given pubkey. */
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
+
+/** Generate a multisig script. */
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
+
+/**
+ * Generate a pay-to-witness script for the given redeem script. If the redeem
+ * script is P2PK or P2PKH, this returns a P2WPKH script, otherwise it returns a
+ * P2WSH script.
+ */
CScript GetScriptForWitness(const CScript& redeemscript);
#endif // BITCOIN_SCRIPT_STANDARD_H
diff --git a/src/serialize.h b/src/serialize.h
index 8b86a07a76..eeb05fa76c 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -402,7 +402,7 @@ class CVarInt
protected:
I &n;
public:
- CVarInt(I& nIn) : n(nIn) { }
+ explicit CVarInt(I& nIn) : n(nIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -420,7 +420,7 @@ class CCompactSize
protected:
uint64_t &n;
public:
- CCompactSize(uint64_t& nIn) : n(nIn) { }
+ explicit CCompactSize(uint64_t& nIn) : n(nIn) { }
template<typename Stream>
void Serialize(Stream &s) const {
@@ -439,7 +439,7 @@ class LimitedString
protected:
std::string& string;
public:
- LimitedString(std::string& _string) : string(_string) {}
+ explicit LimitedString(std::string& _string) : string(_string) {}
template<typename Stream>
void Unserialize(Stream& s)
diff --git a/src/streams.h b/src/streams.h
index a3fc919714..159847279d 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -82,7 +82,7 @@ class CVectorWriter
* @param[in] nVersionIn Serialization Version (including any flags)
* @param[in] vchDataIn Referenced byte vector to overwrite/append
* @param[in] nPosIn Starting position. Vector index where writes should start. The vector will initially
- * grow as necessary to max(index, vec.size()). So to append, use vec.size().
+ * grow as necessary to max(nPosIn, vec.size()). So to append, use vec.size().
*/
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn) : nType(nTypeIn), nVersion(nVersionIn), vchData(vchDataIn), nPos(nPosIn)
{
@@ -91,7 +91,7 @@ class CVectorWriter
}
/*
* (other params same as above)
- * @param[in] args A list of items to serialize starting at nPos.
+ * @param[in] args A list of items to serialize starting at nPosIn.
*/
template <typename... Args>
CVectorWriter(int nTypeIn, int nVersionIn, std::vector<unsigned char>& vchDataIn, size_t nPosIn, Args&&... args) : CVectorWriter(nTypeIn, nVersionIn, vchDataIn, nPosIn)
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index 7641d81471..cecbdec1aa 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -150,7 +150,7 @@ public:
* If this callback is provided and returns false, the allocation fails (hard fail), if
* it returns true the allocation proceeds, but it could warn.
*/
- LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = nullptr);
+ explicit LockedPool(std::unique_ptr<LockedPageAllocator> allocator, LockingFailed_Callback lf_cb_in = nullptr);
~LockedPool();
/** Allocate size bytes from this arena.
@@ -217,7 +217,7 @@ public:
}
private:
- LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
+ explicit LockedPoolManager(std::unique_ptr<LockedPageAllocator> allocator);
/** Create a new LockedPoolManager specialized to the OS */
static void CreateInstance();
diff --git a/src/sync.h b/src/sync.h
index ddaf62b3b3..0871c5fb4d 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -196,7 +196,7 @@ private:
int value;
public:
- CSemaphore(int init) : value(init) {}
+ explicit CSemaphore(int init) : value(init) {}
void wait()
{
@@ -267,7 +267,7 @@ public:
CSemaphoreGrant() : sem(nullptr), fHaveGrant(false) {}
- CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
+ explicit CSemaphoreGrant(CSemaphore& sema, bool fTry = false) : sem(&sema), fHaveGrant(false)
{
if (fTry)
TryAcquire();
diff --git a/src/test/README.md b/src/test/README.md
index eeb04c6ffa..dbaa9c27f3 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -5,7 +5,10 @@ and tests weren't explicitly disabled.
After configuring, they can be run with `make check`.
-To run the bitcoind tests manually, launch `src/test/test_bitcoin`.
+To run the bitcoind tests manually, launch `src/test/test_bitcoin`. To recompile
+after a test file was modified, run `make` and then run the test again. If you
+modify a non-test file, use `make -C src/test` to recompile only what's needed
+to run the bitcoind tests.
To add more bitcoind tests, add `BOOST_AUTO_TEST_CASE` functions to the existing
.cpp files in the `test/` directory or add new .cpp files that
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 2ad22d34ad..7be29c6d6b 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -15,7 +15,7 @@ class CAddrManTest : public CAddrMan
uint64_t state;
public:
- CAddrManTest(bool makeDeterministic = true)
+ explicit CAddrManTest(bool makeDeterministic = true)
{
state = 1;
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index b33cdb9fe6..4829590c54 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -78,7 +78,7 @@ class TestAddrTypeVisitor : public boost::static_visitor<bool>
private:
std::string exp_addrType;
public:
- TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }
+ explicit TestAddrTypeVisitor(const std::string &_exp_addrType) : exp_addrType(_exp_addrType) { }
bool operator()(const CKeyID &id) const
{
return (exp_addrType == "pubkey");
@@ -99,7 +99,7 @@ class TestPayloadVisitor : public boost::static_visitor<bool>
private:
std::vector<unsigned char> exp_payload;
public:
- TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }
+ explicit TestPayloadVisitor(std::vector<unsigned char> &_exp_payload) : exp_payload(_exp_payload) { }
bool operator()(const CKeyID &id) const
{
uint160 exp_key(exp_payload);
@@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
CBitcoinSecret secret;
- CBitcoinAddress addr;
+ CTxDestination destination;
SelectParams(CBaseChainParams::MAIN);
for (unsigned int idx = 0; idx < tests.size(); idx++) {
@@ -145,7 +145,6 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
bool isCompressed = find_value(metadata, "isCompressed").get_bool();
// Must be valid private key
- // Note: CBitcoinSecret::SetString tests isValid, whereas CBitcoinAddress does not!
BOOST_CHECK_MESSAGE(secret.SetString(exp_base58string), "!SetString:"+ strTest);
BOOST_CHECK_MESSAGE(secret.IsValid(), "!IsValid:" + strTest);
CKey privkey = secret.GetKey();
@@ -153,18 +152,17 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
BOOST_CHECK_MESSAGE(privkey.size() == exp_payload.size() && std::equal(privkey.begin(), privkey.end(), exp_payload.begin()), "key mismatch:" + strTest);
// Private key must be invalid public key
- addr.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid privkey as pubkey:" + strTest);
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
}
else
{
std::string exp_addrType = find_value(metadata, "addrType").get_str(); // "script" or "pubkey"
// Must be valid public key
- BOOST_CHECK_MESSAGE(addr.SetString(exp_base58string), "SetString:" + strTest);
- BOOST_CHECK_MESSAGE(addr.IsValid(), "!IsValid:" + strTest);
- BOOST_CHECK_MESSAGE(addr.IsScript() == (exp_addrType == "script"), "isScript mismatch" + strTest);
- CTxDestination dest = addr.Get();
- BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), dest), "addrType mismatch" + strTest);
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
+ BOOST_CHECK_MESSAGE((boost::get<CScriptID>(&destination) != nullptr) == (exp_addrType == "script"), "isScript mismatch" + strTest);
+ BOOST_CHECK_MESSAGE(boost::apply_visitor(TestAddrTypeVisitor(exp_addrType), destination), "addrType mismatch" + strTest);
// Public key must be invalid private key
secret.SetString(exp_base58string);
@@ -226,17 +224,11 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
BOOST_ERROR("Bad addrtype: " << strTest);
continue;
}
- CBitcoinAddress addrOut;
- BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
- BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
+ std::string address = EncodeDestination(dest);
+ BOOST_CHECK_MESSAGE(address == exp_base58string, "mismatch: " + strTest);
}
}
- // Visiting a CNoDestination must fail
- CBitcoinAddress dummyAddr;
- CTxDestination nodest = CNoDestination();
- BOOST_CHECK(!dummyAddr.Set(nodest));
-
SelectParams(CBaseChainParams::MAIN);
}
@@ -245,7 +237,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
CBitcoinSecret secret;
- CBitcoinAddress addr;
+ CTxDestination destination;
for (unsigned int idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx];
@@ -258,8 +250,8 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
std::string exp_base58string = test[0].get_str();
// must be invalid as public and as private key
- addr.SetString(exp_base58string);
- BOOST_CHECK_MESSAGE(!addr.IsValid(), "IsValid pubkey:" + strTest);
+ destination = DecodeDestination(exp_base58string);
+ BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey:" + strTest);
secret.SetString(exp_base58string);
BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid privkey:" + strTest);
}
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 6bcd550d7b..c851ab2849 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -24,7 +24,7 @@ struct TestVector {
std::string strHexMaster;
std::vector<TestDerivation> vDerive;
- TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
+ explicit TestVector(std::string strHexMasterIn) : strHexMaster(strHexMasterIn) {}
TestVector& operator()(std::string pub, std::string prv, unsigned int nChild) {
vDerive.push_back(TestDerivation());
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 812e8534cd..f2d5b385d0 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -118,12 +118,12 @@ public:
std::vector<uint64_t> shorttxids;
std::vector<PrefilledTransaction> prefilledtxn;
- TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
+ explicit TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs& orig) {
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << orig;
stream >> *this;
}
- TestHeaderAndShortIDs(const CBlock& block) :
+ explicit TestHeaderAndShortIDs(const CBlock& block) :
TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block, true)) {}
uint64_t GetShortID(const uint256& txhash) const {
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 37ddf83f5e..dc358bff95 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -74,7 +74,7 @@ public:
class CCoinsViewCacheTest : public CCoinsViewCache
{
public:
- CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {}
+ explicit CCoinsViewCacheTest(CCoinsView* _base) : CCoinsViewCache(_base) {}
void SelfTest() const
{
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index e6b382af13..ad74b7cf1b 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -45,7 +45,7 @@
"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"],
["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"],
-["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"],
+["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation. In a signature, it contains an ASN1 integer which isn't strict-DER conformant due to being negative, which doesn't make sense in a signature. Before BIP66 activated, it was a valid signature. After it activated, it's not valid any more."],
[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"],
["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]],
"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"],
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 6ed6e7744e..251d5a7142 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -231,7 +231,7 @@ struct StringContentsSerializer {
// This is a terrible idea
std::string str;
StringContentsSerializer() {}
- StringContentsSerializer(const std::string& inp) : str(inp) {}
+ explicit StringContentsSerializer(const std::string& inp) : str(inp) {}
StringContentsSerializer& operator+=(const std::string& s) {
str += s;
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 559b3caf1c..91c0175412 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -16,17 +16,16 @@
#include <boost/test/unit_test.hpp>
-static const std::string strSecret1 ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
-static const std::string strSecret2 ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
-static const std::string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
-static const std::string strSecret2C ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
-static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
-static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
-static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
-static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");
+static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj";
+static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3";
+static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw";
+static const std::string strSecret2C = "L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g";
+static const std::string addr1 = "1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ";
+static const std::string addr2 = "1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ";
+static const std::string addr1C = "1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs";
+static const std::string addr2C = "1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs";
-
-static const std::string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");
+static const std::string strAddressBad = "1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF";
BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
@@ -74,10 +73,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
- BOOST_CHECK(addr1.Get() == CTxDestination(pubkey1.GetID()));
- BOOST_CHECK(addr2.Get() == CTxDestination(pubkey2.GetID()));
- BOOST_CHECK(addr1C.Get() == CTxDestination(pubkey1C.GetID()));
- BOOST_CHECK(addr2C.Get() == CTxDestination(pubkey2C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
+ BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
for (int n=0; n<16; n++)
{
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index 1d5893bdc3..280eb59ce8 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -29,10 +29,7 @@ static void CheckCreateVch(const int64_t& num)
CScriptNum scriptnum(num);
BOOST_CHECK(verify(bignum, scriptnum));
- std::vector<unsigned char> vch = bignum.getvch();
-
CScriptNum10 bignum2(bignum.getvch(), false);
- vch = scriptnum.getvch();
CScriptNum scriptnum2(scriptnum.getvch(), false);
BOOST_CHECK(verify(bignum2, scriptnum2));
@@ -90,11 +87,10 @@ static void CheckSubtract(const int64_t& num1, const int64_t& num2)
const CScriptNum10 bignum2(num2);
const CScriptNum scriptnum1(num1);
const CScriptNum scriptnum2(num2);
- bool invalid = false;
// int64_t overflow is undefined.
- invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||
- (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));
+ bool invalid = ((num2 > 0 && num1 < std::numeric_limits<int64_t>::min() + num2) ||
+ (num2 < 0 && num1 > std::numeric_limits<int64_t>::max() + num2));
if (!invalid)
{
BOOST_CHECK(verify(bignum1 - bignum2, scriptnum1 - scriptnum2));
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 1ca83a7cf8..ecbdf57788 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -124,11 +124,9 @@ BOOST_AUTO_TEST_CASE(sighash_test)
#if defined(PRINT_SIGHASH_JSON)
std::cout << "[\n";
std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n";
- #endif
+ int nRandomTests = 500;
+ #else
int nRandomTests = 50000;
-
- #if defined(PRINT_SIGHASH_JSON)
- nRandomTests = 500;
#endif
for (int i=0; i<nRandomTests; i++) {
int nHashType = InsecureRand32();
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 94ec7c03f5..194f62ca11 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -22,8 +22,6 @@
#include "rpc/register.h"
#include "script/sigcache.h"
-#include "test/testutil.h"
-
#include <memory>
uint256 insecure_rand_seed = GetRandHash();
@@ -61,7 +59,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
RegisterAllCoreRPCCommands(tableRPC);
ClearDatadirCache();
- pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
+ pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000)));
fs::create_directories(pathTemp);
gArgs.ForceSetArg("-datadir", pathTemp.string());
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index dd3b13c8c8..2ddac2f076 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -41,7 +41,7 @@ static inline bool InsecureRandBool() { return insecure_rand_ctx.randbool(); }
struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle;
- BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
@@ -56,7 +56,7 @@ struct TestingSetup: public BasicTestingSetup {
CConnman* connman;
CScheduler scheduler;
- TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
};
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
index 34beef5539..b556c953b9 100644
--- a/src/test/test_bitcoin_main.cpp
+++ b/src/test/test_bitcoin_main.cpp
@@ -10,14 +10,14 @@
std::unique_ptr<CConnman> g_connman;
-void Shutdown(void* parg)
+[[noreturn]] void Shutdown(void* parg)
{
- exit(EXIT_SUCCESS);
+ std::exit(EXIT_SUCCESS);
}
-void StartShutdown()
+[[noreturn]] void StartShutdown()
{
- exit(EXIT_SUCCESS);
+ std::exit(EXIT_SUCCESS);
}
bool ShutdownRequested()
diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp
deleted file mode 100644
index 591d0bf302..0000000000
--- a/src/test/testutil.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2009-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.
-
-#include "testutil.h"
-
-#ifdef WIN32
-#include <shlobj.h>
-#endif
-
-#include "fs.h"
-
-fs::path GetTempPath() {
- return fs::temp_directory_path();
-}
diff --git a/src/test/testutil.h b/src/test/testutil.h
deleted file mode 100644
index cbe784d640..0000000000
--- a/src/test/testutil.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2009-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.
-
-/**
- * Utility functions shared by unit tests
- */
-#ifndef BITCOIN_TEST_TESTUTIL_H
-#define BITCOIN_TEST_TESTUTIL_H
-
-#include "fs.h"
-
-fs::path GetTempPath();
-
-#endif // BITCOIN_TEST_TESTUTIL_H
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 5679086969..6ec544290d 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -253,6 +253,31 @@ BOOST_AUTO_TEST_CASE(util_IsHex)
BOOST_CHECK(!IsHex("0x0000"));
}
+BOOST_AUTO_TEST_CASE(util_IsHexNumber)
+{
+ BOOST_CHECK(IsHexNumber("0x0"));
+ BOOST_CHECK(IsHexNumber("0"));
+ BOOST_CHECK(IsHexNumber("0x10"));
+ BOOST_CHECK(IsHexNumber("10"));
+ BOOST_CHECK(IsHexNumber("0xff"));
+ BOOST_CHECK(IsHexNumber("ff"));
+ BOOST_CHECK(IsHexNumber("0xFfa"));
+ BOOST_CHECK(IsHexNumber("Ffa"));
+ BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF"));
+ BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF"));
+
+ BOOST_CHECK(!IsHexNumber("")); // empty string not allowed
+ BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed
+ BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end,
+ BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning,
+ BOOST_CHECK(!IsHexNumber("0x 0")); // or middle,
+ BOOST_CHECK(!IsHexNumber(" ")); // etc.
+ BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character
+ BOOST_CHECK(!IsHexNumber("x0")); // broken prefix
+ BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed
+
+}
+
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
{
SeedInsecureRand(true);
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index f433aad889..882afb2e20 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -314,20 +314,20 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Mine one period worth of blocks, and check that the bit will be on for the
// next period.
- lastBlock = secondChain.Mine(2016, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Mine another period worth of blocks, signaling the new bit.
- lastBlock = secondChain.Mine(4032, nStartTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
+ lastBlock = secondChain.Mine(4032, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
// After one period of setting the bit on each block, it should have locked in.
// We keep setting the bit for one more period though, until activation.
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Now check that we keep mining the block until the end of this period, and
// then stop at the beginning of the next period.
- lastBlock = secondChain.Mine(6047, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(6047, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
- lastBlock = secondChain.Mine(6048, nStartTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
// Finally, verify that after a soft fork has activated, CBV no longer uses
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 5022d46809..2e453e56bb 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -167,7 +167,7 @@ namespace tinyformat {
class format_error: public std::runtime_error
{
public:
- format_error(const std::string &what): std::runtime_error(what) {
+ explicit format_error(const std::string &what): std::runtime_error(what) {
}
};
@@ -498,7 +498,7 @@ class FormatArg
FormatArg() {}
template<typename T>
- FormatArg(const T& value)
+ explicit FormatArg(const T& value)
: m_value(static_cast<const void*>(&value)),
m_formatImpl(&formatImpl<T>),
m_toIntImpl(&toIntImpl<T>)
@@ -867,7 +867,7 @@ class FormatListN : public FormatList
public:
#ifdef TINYFORMAT_USE_VARIADIC_TEMPLATES
template<typename... Args>
- FormatListN(const Args&... args)
+ explicit FormatListN(const Args&... args)
: FormatList(&m_formatterStore[0], N),
m_formatterStore { FormatArg(args)... }
{ static_assert(sizeof...(args) == N, "Number of args must be N"); }
@@ -876,7 +876,7 @@ class FormatListN : public FormatList
# define TINYFORMAT_MAKE_FORMATLIST_CONSTRUCTOR(n) \
\
template<TINYFORMAT_ARGTYPES(n)> \
- FormatListN(TINYFORMAT_VARARGS(n)) \
+ explicit FormatListN(TINYFORMAT_VARARGS(n)) \
: FormatList(&m_formatterStore[0], n) \
{ assert(n == N); init(0, TINYFORMAT_PASSARGS(n)); } \
\
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 6b96c24af2..1cea197666 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -76,7 +76,7 @@ public:
/** Create a new TorControlConnection.
*/
- TorControlConnection(struct event_base *base);
+ explicit TorControlConnection(struct event_base *base);
~TorControlConnection();
/**
diff --git a/src/txdb.cpp b/src/txdb.cpp
index bbad3899ea..134bb8721b 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -35,7 +35,7 @@ namespace {
struct CoinEntry {
COutPoint* outpoint;
char key;
- CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
+ explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
template<typename Stream>
void Serialize(Stream &s) const {
diff --git a/src/txdb.h b/src/txdb.h
index adcbc73380..d1cd5a4250 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -64,12 +64,12 @@ struct CDiskTxPos : public CDiskBlockPos
};
/** CCoinsView backed by the coin database (chainstate/) */
-class CCoinsViewDB : public CCoinsView
+class CCoinsViewDB final : public CCoinsView
{
protected:
CDBWrapper db;
public:
- CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+ explicit CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
bool HaveCoin(const COutPoint &outpoint) const override;
@@ -109,7 +109,7 @@ private:
class CBlockTreeDB : public CDBWrapper
{
public:
- CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
+ explicit CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
private:
CBlockTreeDB(const CBlockTreeDB&);
void operator=(const CBlockTreeDB&);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 4a81055231..f68d677646 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -39,11 +39,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFe
nSigOpCostWithAncestors = sigOpCost;
}
-CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
-{
- *this = other;
-}
-
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
nModFeesWithDescendants += newFeeDelta - feeDelta;
diff --git a/src/txmempool.h b/src/txmempool.h
index 0b183cbd90..b07886579c 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -21,11 +21,10 @@
#include "sync.h"
#include "random.h"
-#include "boost/multi_index_container.hpp"
-#include "boost/multi_index/ordered_index.hpp"
-#include "boost/multi_index/hashed_index.hpp"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
-
#include <boost/signals2/signal.hpp>
class CBlockIndex;
@@ -95,8 +94,6 @@ public:
bool spendsCoinbase,
int64_t nSigOpsCost, LockPoints lp);
- CTxMemPoolEntry(const CTxMemPoolEntry& other);
-
const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; }
const CAmount& GetFee() const { return nFee; }
@@ -167,7 +164,7 @@ struct update_ancestor_state
struct update_fee_delta
{
- update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
+ explicit update_fee_delta(int64_t _feeDelta) : feeDelta(_feeDelta) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateFeeDelta(feeDelta); }
@@ -177,7 +174,7 @@ private:
struct update_lock_points
{
- update_lock_points(const LockPoints& _lp) : lp(_lp) { }
+ explicit update_lock_points(const LockPoints& _lp) : lp(_lp) { }
void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
@@ -501,7 +498,7 @@ public:
/** Create a new CTxMemPool.
*/
- CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
+ explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr);
/**
* If sanity-checking is turned on, check makes sure the pool is
diff --git a/src/uint256.h b/src/uint256.h
index a92ce07f11..3ed694d723 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -111,7 +111,7 @@ public:
class uint160 : public base_blob<160> {
public:
uint160() {}
- uint160(const base_blob<160>& b) : base_blob<160>(b) {}
+ explicit uint160(const base_blob<160>& b) : base_blob<160>(b) {}
explicit uint160(const std::vector<unsigned char>& vch) : base_blob<160>(vch) {}
};
@@ -123,7 +123,7 @@ public:
class uint256 : public base_blob<256> {
public:
uint256() {}
- uint256(const base_blob<256>& b) : base_blob<256>(b) {}
+ explicit uint256(const base_blob<256>& b) : base_blob<256>(b) {}
explicit uint256(const std::vector<unsigned char>& vch) : base_blob<256>(vch) {}
/** A cheap hash function that just returns 64 bits from the result, it can be
diff --git a/src/undo.h b/src/undo.h
index 0f9d041bbd..a720de4ac5 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -33,7 +33,7 @@ public:
::Serialize(s, CTxOutCompressor(REF(txout->out)));
}
- TxInUndoSerializer(const Coin* coin) : txout(coin) {}
+ explicit TxInUndoSerializer(const Coin* coin) : txout(coin) {}
};
class TxInUndoDeserializer
@@ -57,7 +57,7 @@ public:
::Unserialize(s, REF(CTxOutCompressor(REF(txout->out))));
}
- TxInUndoDeserializer(Coin* coin) : txout(coin) {}
+ explicit TxInUndoDeserializer(Coin* coin) : txout(coin) {}
};
static const size_t MIN_TRANSACTION_INPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxIn(), SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/univalue/lib/univalue_utffilter.h b/src/univalue/lib/univalue_utffilter.h
index 0e330dce9c..2fb6a492d1 100644
--- a/src/univalue/lib/univalue_utffilter.h
+++ b/src/univalue/lib/univalue_utffilter.h
@@ -13,7 +13,7 @@
class JSONUTF8StringFilter
{
public:
- JSONUTF8StringFilter(std::string &s):
+ explicit JSONUTF8StringFilter(std::string &s):
str(s), is_valid(true), codepoint(0), state(0), surpair(0)
{
}
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index fd233f6757..741680e93f 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -65,6 +65,19 @@ bool IsHex(const std::string& str)
return (str.size() > 0) && (str.size()%2 == 0);
}
+bool IsHexNumber(const std::string& str)
+{
+ size_t starting_location = 0;
+ if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') {
+ starting_location = 2;
+ }
+ for (auto c : str.substr(starting_location)) {
+ if (HexDigit(c) < 0) return false;
+ }
+ // Return false for empty string or "0x".
+ return (str.size() > starting_location);
+}
+
std::vector<unsigned char> ParseHex(const char* psz)
{
// convert hex dump to vector
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 53da60e8f1..192f33fb29 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -38,7 +38,13 @@ std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);
signed char HexDigit(char c);
+/* Returns true if each character in str is a hex character, and has an even
+ * number of hex digits.*/
bool IsHex(const std::string& str);
+/**
+* Return true if the string is a hex number, optionally prefixed with "0x"
+*/
+bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = nullptr);
std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len);
diff --git a/src/validation.cpp b/src/validation.cpp
index e0df397089..0bd1ec672b 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -53,6 +53,9 @@
# error "Bitcoin cannot be compiled without assertions."
#endif
+#define MICRO 0.000001
+#define MILLI 0.001
+
/**
* Global state
*/
@@ -80,6 +83,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
uint256 hashAssumeValid;
+arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@@ -251,6 +255,8 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
AssertLockHeld(mempool.cs);
CBlockIndex* tip = chainActive.Tip();
+ assert(tip != nullptr);
+
CBlockIndex index;
index.pprev = tip;
// CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
@@ -1032,8 +1038,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
bool IsInitialBlockDownload()
{
- const CChainParams& chainParams = Params();
-
// Once this function has returned false, it must remain false.
static std::atomic<bool> latchToFalse{false};
// Optimization: pre-test latch before taking the lock.
@@ -1047,7 +1051,7 @@ bool IsInitialBlockDownload()
return true;
if (chainActive.Tip() == nullptr)
return true;
- if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
+ if (chainActive.Tip()->nChainWork < nMinimumChainWork)
return true;
if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
@@ -1563,7 +1567,7 @@ private:
int bit;
public:
- WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
+ explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); }
@@ -1623,6 +1627,7 @@ static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0;
+static int64_t nBlocksTotal = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
@@ -1653,6 +1658,8 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
return true;
}
+ nBlocksTotal++;
+
bool fScriptChecks = true;
if (!hashAssumeValid.IsNull()) {
// We've been configured with the hash of a block which has been externally verified to have a valid history.
@@ -1664,7 +1671,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (it != mapBlockIndex.end()) {
if (it->second->GetAncestor(pindex->nHeight) == pindex &&
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
- pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) {
+ pindexBestHeader->nChainWork >= nMinimumChainWork) {
// This block is a member of the assumed verified chain and an ancestor of the best header.
// The equivalent time check discourages hash power from extorting the network via DOS attack
// into accepting an invalid block through telling users they must manually set assumevalid.
@@ -1680,7 +1687,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
}
int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart;
- LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001);
+ LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal);
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -1729,7 +1736,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
unsigned int flags = GetBlockScriptFlags(pindex, chainparams.GetConsensus());
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
- LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001);
+ LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal);
CBlockUndo blockundo;
@@ -1803,7 +1810,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
- LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward)
@@ -1815,7 +1822,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
if (!control.Wait())
return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
- LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001);
+ LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
if (fJustCheck)
return true;
@@ -1847,10 +1854,10 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
view.SetBestBlock(pindex->GetBlockHash());
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001);
+ LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal);
int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5;
- LogPrint(BCLog::BENCH, " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
+ LogPrint(BCLog::BENCH, " - Callbacks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeCallbacks * MICRO, nTimeCallbacks * MILLI / nBlocksTotal);
return true;
}
@@ -2075,7 +2082,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
bool flushed = view.Flush();
assert(flushed);
}
- LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001);
+ LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
return false;
@@ -2135,7 +2142,7 @@ private:
CTxMemPool &pool;
public:
- ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
+ explicit ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
}
@@ -2196,7 +2203,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
// Apply the block atomically to the chain state.
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
int64_t nTime3;
- LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
+ LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
{
CCoinsViewCache view(pcoinsTip);
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
@@ -2207,17 +2214,17 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
- LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal);
bool flushed = view.Flush();
assert(flushed);
}
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
- LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001);
+ LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(chainparams, state, FLUSH_STATE_IF_NEEDED))
return false;
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
- LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
+ LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
// Remove conflicting transactions from the mempool.;
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
disconnectpool.removeForBlock(blockConnecting.vtx);
@@ -2225,8 +2232,8 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
UpdateTip(pindexNew, chainparams);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
- LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
- LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
+ LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal);
+ LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal);
connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
return true;
@@ -4326,7 +4333,7 @@ bool LoadMempool(void)
return true;
}
-void DumpMempool(void)
+bool DumpMempool(void)
{
int64_t start = GetTimeMicros();
@@ -4346,7 +4353,7 @@ void DumpMempool(void)
try {
FILE* filestr = fsbridge::fopen(GetDataDir() / "mempool.dat.new", "wb");
if (!filestr) {
- return;
+ return false;
}
CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
@@ -4367,10 +4374,12 @@ void DumpMempool(void)
file.fclose();
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat");
int64_t last = GetTimeMicros();
- LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*0.000001, (last-mid)*0.000001);
+ LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO);
} catch (const std::exception& e) {
LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
+ return false;
}
+ return true;
}
//! Guess how far we are in the verification process at the given block index
diff --git a/src/validation.h b/src/validation.h
index d0f6cdc135..23d4b35585 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -186,6 +186,9 @@ extern bool fEnableReplacement;
/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
extern uint256 hashAssumeValid;
+/** Minimum work we will assume exists on some valid chain. */
+extern arith_uint256 nMinimumChainWork;
+
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -475,7 +478,7 @@ static const unsigned int REJECT_HIGHFEE = 0x100;
CBlockFileInfo* GetBlockFileInfo(size_t n);
/** Dump the mempool to disk. */
-void DumpMempool();
+bool DumpMempool();
/** Load the mempool from disk. */
bool LoadMempool();
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index bf20d606f8..be5029dec3 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -30,7 +30,7 @@ struct MainSignalsInstance {
// our own queue here :(
SingleThreadedSchedulerClient m_schedulerClient;
- MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
+ explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
};
static CMainSignals g_signals;
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index 59588023ad..64ae939672 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -185,7 +185,7 @@ protected:
}
public:
- VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
+ explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
};
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 1dc44e424f..f1e8a25650 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -113,7 +113,6 @@ public:
class CCryptoKeyStore : public CBasicKeyStore
{
private:
- CryptedKeyMap mapCryptedKeys;
CKeyingMaterial vMasterKey;
@@ -131,6 +130,7 @@ protected:
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
+ CryptedKeyMap mapCryptedKeys;
public:
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index d2fe4866fa..d66ba48421 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -558,7 +558,6 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
}
MilliSleep(100);
}
- return false;
}
@@ -684,7 +683,6 @@ bool CWalletDBWrapper::Backup(const std::string& strDest)
}
MilliSleep(100);
}
- return false;
}
void CWalletDBWrapper::Flush(bool shutdown)
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index c1ea2b6290..6abd060714 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -5,6 +5,7 @@
#include "consensus/validation.h"
#include "wallet/coincontrol.h"
#include "wallet/feebumper.h"
+#include "wallet/fees.h"
#include "wallet/wallet.h"
#include "policy/fees.h"
#include "policy/policy.h"
@@ -76,12 +77,12 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
vErrors.clear();
bumpedTxid.SetNull();
AssertLockHeld(pWallet->cs_wallet);
- if (!pWallet->mapWallet.count(txid)) {
+ auto it = pWallet->mapWallet.find(txid);
+ if (it == pWallet->mapWallet.end()) {
vErrors.push_back("Invalid or non-wallet transaction id");
currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
return;
}
- auto it = pWallet->mapWallet.find(txid);
const CWalletTx& wtx = it->second;
if (!preconditionChecks(pWallet, wtx)) {
@@ -156,7 +157,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
currentResult = BumpFeeResult::INVALID_PARAMETER;
return;
}
- CAmount requiredFee = CWallet::GetRequiredFee(maxNewTxSize);
+ CAmount requiredFee = GetRequiredFee(maxNewTxSize);
if (totalFee < requiredFee) {
vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
FormatMoney(requiredFee)));
@@ -166,7 +167,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
nNewFee = totalFee;
nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
} else {
- nNewFee = CWallet::GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
+ nNewFee = GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
// New fee rate must be at least old rate + minimum incremental relay rate
@@ -241,12 +242,13 @@ bool CFeeBumper::commit(CWallet *pWallet)
if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {
return false;
}
- if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
+ auto it = txid.IsNull() ? pWallet->mapWallet.end() : pWallet->mapWallet.find(txid);
+ if (it == pWallet->mapWallet.end()) {
vErrors.push_back("Invalid or non-wallet transaction id");
currentResult = BumpFeeResult::MISC_ERROR;
return false;
}
- CWalletTx& oldWtx = pWallet->mapWallet[txid];
+ CWalletTx& oldWtx = it->second;
// make sure the transaction still has no descendants and hasn't been mined in the meantime
if (!preconditionChecks(pWallet, oldWtx)) {
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
new file mode 100644
index 0000000000..76eeeeda05
--- /dev/null
+++ b/src/wallet/fees.cpp
@@ -0,0 +1,89 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 "wallet/fees.h"
+
+#include "policy/policy.h"
+#include "txmempool.h"
+#include "util.h"
+#include "validation.h"
+#include "wallet/coincontrol.h"
+#include "wallet/wallet.h"
+
+
+CAmount GetRequiredFee(unsigned int nTxBytes)
+{
+ return std::max(CWallet::minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
+}
+
+
+CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc)
+{
+ /* User control of how to calculate fee uses the following parameter precedence:
+ 1. coin_control.m_feerate
+ 2. coin_control.m_confirm_target
+ 3. payTxFee (user-set global variable)
+ 4. nTxConfirmTarget (user-set global variable)
+ The first parameter that is set is used.
+ */
+ CAmount fee_needed;
+ if (coin_control.m_feerate) { // 1.
+ fee_needed = coin_control.m_feerate->GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ // Allow to override automatic min/max check over coin control instance
+ if (coin_control.fOverrideFeeRate) return fee_needed;
+ }
+ else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee
+ fee_needed = ::payTxFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
+ }
+ else { // 2. or 4.
+ // We will use smart fee estimation
+ unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget;
+ // By default estimates are economical iff we are signaling opt-in-RBF
+ bool conservative_estimate = !coin_control.signalRbf;
+ // Allow to override the default fee estimate mode over the CoinControl instance
+ if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
+ else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
+
+ fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
+ if (fee_needed == 0) {
+ // if we don't have enough data for estimateSmartFee, then use fallbackFee
+ fee_needed = CWallet::fallbackFee.GetFee(nTxBytes);
+ if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
+ }
+ // Obey mempool min fee when using smart fee estimation
+ CAmount min_mempool_fee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
+ if (fee_needed < min_mempool_fee) {
+ fee_needed = min_mempool_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
+ }
+ }
+
+ // prevent user from paying a fee below minRelayTxFee or minTxFee
+ CAmount required_fee = GetRequiredFee(nTxBytes);
+ if (required_fee > fee_needed) {
+ fee_needed = required_fee;
+ if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
+ }
+ // But always obey the maximum
+ if (fee_needed > maxTxFee) {
+ fee_needed = maxTxFee;
+ if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
+ }
+ return fee_needed;
+}
+
+
+CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator)
+{
+ unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
+ CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */);
+ // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
+ discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate);
+ // Discard rate must be at least dustRelayFee
+ discard_rate = std::max(discard_rate, ::dustRelayFee);
+ return discard_rate;
+}
diff --git a/src/wallet/fees.h b/src/wallet/fees.h
new file mode 100644
index 0000000000..7b8a7dc868
--- /dev/null
+++ b/src/wallet/fees.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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.
+
+#ifndef BITCOIN_WALLET_FEES_H
+#define BITCOIN_WALLET_FEES_H
+
+#include "amount.h"
+
+class CBlockPolicyEstimator;
+class CCoinControl;
+class CFeeRate;
+class CTxMemPool;
+struct FeeCalculation;
+
+/**
+ * Return the minimum required fee taking into account the
+ * floating relay fee and user set minimum transaction fee
+ */
+CAmount GetRequiredFee(unsigned int nTxBytes);
+
+/**
+ * Estimate the minimum fee considering user set parameters
+ * and the required fee
+ */
+CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc);
+
+/**
+ * Return the maximum feerate for discarding change.
+ */
+CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator);
+
+#endif // BITCOIN_WALLET_FEES_H
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
new file mode 100644
index 0000000000..18365b1b72
--- /dev/null
+++ b/src/wallet/init.cpp
@@ -0,0 +1,247 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 "wallet/init.h"
+
+#include "net.h"
+#include "util.h"
+#include "utilmoneystr.h"
+#include "validation.h"
+#include "wallet/wallet.h"
+
+std::string GetWalletHelpString(bool showDebug)
+{
+ std::string strUsage = HelpMessageGroup(_("Wallet options:"));
+ strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
+ strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
+ strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
+ strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
+ "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
+ strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
+ 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"));
+ 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));
+ strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
+ strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
+ strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
+ strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
+ strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
+ strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
+ " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
+
+ if (showDebug)
+ {
+ strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
+
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
+ strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
+ }
+
+ return strUsage;
+}
+
+bool WalletParameterInteraction()
+{
+ gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
+ const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
+
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
+
+ if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
+ LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
+ }
+
+ if (gArgs.GetBoolArg("-salvagewallet", false)) {
+ if (is_multiwallet) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
+ }
+ // Rewrite just private keys: rescan to find transactions
+ if (gArgs.SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
+ }
+ }
+
+ int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
+ // -zapwallettxes implies dropping the mempool on startup
+ if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
+ }
+
+ // -zapwallettxes implies a rescan
+ if (zapwallettxes != 0) {
+ if (is_multiwallet) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
+ }
+ if (gArgs.SoftSetBoolArg("-rescan", true)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
+ }
+ }
+
+ if (is_multiwallet) {
+ if (gArgs.GetBoolArg("-upgradewallet", false)) {
+ return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
+ }
+ }
+
+ if (gArgs.GetBoolArg("-sysperms", false))
+ return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
+ if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
+
+ if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
+ _("The wallet will avoid paying less than the minimum relay fee."));
+
+ if (gArgs.IsArgSet("-mintxfee"))
+ {
+ CAmount n = 0;
+ if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n)
+ return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
+ if (n > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-mintxfee") + " " +
+ _("This is the minimum transaction fee you pay on every transaction."));
+ CWallet::minTxFee = CFeeRate(n);
+ }
+ if (gArgs.IsArgSet("-fallbackfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-fallbackfee") + " " +
+ _("This is the transaction fee you may pay when fee estimates are not available."));
+ CWallet::fallbackFee = CFeeRate(nFeePerK);
+ }
+ if (gArgs.IsArgSet("-discardfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK))
+ return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-discardfee") + " " +
+ _("This is the transaction fee you may discard if change is smaller than dust at this level"));
+ CWallet::m_discard_rate = CFeeRate(nFeePerK);
+ }
+ if (gArgs.IsArgSet("-paytxfee"))
+ {
+ CAmount nFeePerK = 0;
+ if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
+ return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
+ if (nFeePerK > HIGH_TX_FEE_PER_KB)
+ InitWarning(AmountHighWarn("-paytxfee") + " " +
+ _("This is the transaction fee you will pay if you send a transaction."));
+
+ payTxFee = CFeeRate(nFeePerK, 1000);
+ if (payTxFee < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
+ gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+ if (gArgs.IsArgSet("-maxtxfee"))
+ {
+ CAmount nMaxFee = 0;
+ if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
+ return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
+ if (nMaxFee > HIGH_MAX_TX_FEE)
+ InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
+ maxTxFee = nMaxFee;
+ if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
+ {
+ return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+ gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
+ }
+ }
+ nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
+ bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
+ fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
+
+ return true;
+}
+
+bool WalletVerify()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
+
+ uiInterface.InitMessage(_("Verifying wallet(s)..."));
+
+ // Keep track of each wallet absolute path to detect duplicates.
+ std::set<fs::path> wallet_paths;
+
+ for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
+ if (boost::filesystem::path(walletFile).filename() != walletFile) {
+ return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile));
+ }
+
+ if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
+ return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile));
+ }
+
+ fs::path wallet_path = fs::absolute(walletFile, GetDataDir());
+
+ if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
+ return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile));
+ }
+
+ if (!wallet_paths.insert(wallet_path).second) {
+ return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile));
+ }
+
+ std::string strError;
+ if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) {
+ return InitError(strError);
+ }
+
+ if (gArgs.GetBoolArg("-salvagewallet", false)) {
+ // Recover readable keypairs:
+ CWallet dummyWallet;
+ std::string backup_filename;
+ if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
+ return false;
+ }
+ }
+
+ std::string strWarning;
+ bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
+ if (!strWarning.empty()) {
+ InitWarning(strWarning);
+ }
+ if (!dbV) {
+ InitError(strError);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool InitLoadWallet()
+{
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ LogPrintf("Wallet disabled!\n");
+ return true;
+ }
+
+ for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
+ CWallet * const pwallet = CWallet::CreateWalletFromFile(walletFile);
+ if (!pwallet) {
+ return false;
+ }
+ vpwallets.push_back(pwallet);
+ }
+
+ return true;
+}
diff --git a/src/wallet/init.h b/src/wallet/init.h
new file mode 100644
index 0000000000..fa2251506d
--- /dev/null
+++ b/src/wallet/init.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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.
+
+#ifndef BITCOIN_WALLET_INIT_H
+#define BITCOIN_WALLET_INIT_H
+
+#include <string>
+
+//! Return the wallets help message.
+std::string GetWalletHelpString(bool showDebug);
+
+//! Wallets parameter interaction
+bool WalletParameterInteraction();
+
+//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
+// This function will perform salvage on the wallet if requested, as long as only one wallet is
+// being loaded (CWallet::ParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
+bool WalletVerify();
+
+//! Load wallet databases.
+bool InitLoadWallet();
+
+#endif // BITCOIN_WALLET_INIT_H
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 67c6d9ec64..9539cc9f42 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -4,6 +4,7 @@
#include "base58.h"
#include "chain.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "init.h"
#include "validation.h"
@@ -174,12 +175,13 @@ UniValue abortrescan(const JSONRPCRequest& request)
+ HelpExampleRpc("abortrescan", "")
);
+ ObserveSafeMode();
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
return true;
}
-void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel);
+void ImportAddress(CWallet*, const CTxDestination& dest, 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) {
@@ -196,7 +198,7 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri
if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel);
+ ImportAddress(pwallet, CScriptID(script), strLabel);
} else {
CTxDestination destination;
if (ExtractDestination(script, destination)) {
@@ -205,13 +207,13 @@ void ImportScript(CWallet* const pwallet, const CScript& script, const std::stri
}
}
-void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel)
+void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel)
{
- CScript script = GetScriptForDestination(address.Get());
+ CScript script = GetScriptForDestination(dest);
ImportScript(pwallet, script, strLabel, false);
// add to address book or update label
- if (address.IsValid())
- pwallet->SetAddressBook(address.Get(), strLabel, "receive");
+ if (IsValidDestination(dest))
+ pwallet->SetAddressBook(dest, strLabel, "receive");
}
UniValue importaddress(const JSONRPCRequest& request)
@@ -263,11 +265,12 @@ UniValue importaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (address.IsValid()) {
- if (fP2SH)
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (IsValidDestination(dest)) {
+ if (fP2SH) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
- ImportAddress(pwallet, address, strLabel);
+ }
+ ImportAddress(pwallet, dest, strLabel);
} else if (IsHex(request.params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);
@@ -430,7 +433,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel);
+ ImportAddress(pwallet, pubKey.GetID(), strLabel);
ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
if (fRescan)
@@ -504,7 +507,7 @@ UniValue importwallet(const JSONRPCRequest& request)
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
- LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
+ LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
continue;
}
int64_t nTime = DecodeDumpTime(vstr[1]);
@@ -522,7 +525,7 @@ UniValue importwallet(const JSONRPCRequest& request)
fLabel = true;
}
}
- LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
+ LogPrintf("Importing %s...\n", EncodeDestination(keyid));
if (!pwallet->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
@@ -571,14 +574,16 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
std::string strAddress = request.params[0].get_str();
- CBitcoinAddress address;
- if (!address.SetString(strAddress))
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CKeyID keyID;
- if (!address.GetKeyID(keyID))
+ }
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
+ }
CKey vchSecret;
- if (!pwallet->GetKey(keyID, vchSecret)) {
+ if (!pwallet->GetKey(*keyID, vchSecret)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
}
return CBitcoinSecret(vchSecret).ToString();
@@ -657,7 +662,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
const CKeyID &keyid = it->second;
std::string strTime = EncodeDumpTime(it->first);
- std::string strAddr = CBitcoinAddress(keyid).ToString();
+ std::string strAddr = EncodeDestination(keyid);
CKey key;
if (pwallet->GetKey(keyid, key)) {
file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
@@ -713,14 +718,14 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
// Parse the output.
CScript script;
- CBitcoinAddress address;
+ CTxDestination dest;
if (!isScript) {
- address = CBitcoinAddress(output);
- if (!address.IsValid()) {
+ dest = DecodeDestination(output);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}
- script = GetScriptForDestination(address.Get());
+ script = GetScriptForDestination(dest);
} else {
if (!IsHex(output)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
@@ -778,8 +783,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript));
- CScript redeemDestination = GetScriptForDestination(redeemAddress.Get());
+ CTxDestination redeem_dest = CScriptID(redeemScript);
+ CScript redeemDestination = GetScriptForDestination(redeem_dest);
if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -792,8 +797,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// add to address book or update label
- if (address.IsValid()) {
- pwallet->SetAddressBook(address.Get(), label, "receive");
+ if (IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
// Import private keys.
@@ -852,27 +857,25 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
}
- CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+ CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
- if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
- CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- scriptAddress = CBitcoinAddress(destination);
- if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
+ if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
}
- CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get());
+ CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
@@ -885,8 +888,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
}
// add to address book or update label
- if (pubKeyAddress.IsValid()) {
- pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive");
+ if (IsValidDestination(pubkey_dest)) {
+ pwallet->SetAddressBook(pubkey_dest, label, "receive");
}
// TODO Is this necessary?
@@ -925,21 +928,19 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
CPubKey pubKey = key.GetPubKey();
assert(key.VerifyPubKey(pubKey));
- CBitcoinAddress pubKeyAddress = CBitcoinAddress(pubKey.GetID());
+ CTxDestination pubkey_dest = pubKey.GetID();
// Consistency check.
- if (!isScript && !(pubKeyAddress.Get() == address.Get())) {
+ if (!isScript && !(pubkey_dest == dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
// Consistency check.
if (isScript) {
- CBitcoinAddress scriptAddress;
CTxDestination destination;
if (ExtractDestination(script, destination)) {
- scriptAddress = CBitcoinAddress(destination);
- if (!(scriptAddress.Get() == pubKeyAddress.Get())) {
+ if (!(destination == pubkey_dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
}
}
@@ -978,8 +979,8 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
if (scriptPubKey.getType() == UniValue::VOBJ) {
// add to address book or update label
- if (address.IsValid()) {
- pwallet->SetAddressBook(address.Get(), label, "receive");
+ if (IsValidDestination(dest)) {
+ pwallet->SetAddressBook(dest, label, "receive");
}
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 094357639b..637ca04e82 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -8,7 +8,6 @@
#include "chain.h"
#include "consensus/validation.h"
#include "core_io.h"
-#include "init.h"
#include "httpserver.h"
#include "validation.h"
#include "net.h"
@@ -17,6 +16,7 @@
#include "policy/policy.h"
#include "policy/rbf.h"
#include "rpc/mining.h"
+#include "rpc/safemode.h"
#include "rpc/server.h"
#include "script/sign.h"
#include "timedata.h"
@@ -27,6 +27,8 @@
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
+#include <init.h> // For StartShutdown
+
#include <stdint.h>
#include <univalue.h>
@@ -168,18 +170,18 @@ UniValue getnewaddress(const JSONRPCRequest& request)
pwallet->SetAddressBook(keyID, strAccount, "receive");
- return CBitcoinAddress(keyID).ToString();
+ return EncodeDestination(keyID);
}
-CBitcoinAddress GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
+CTxDestination GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
{
CPubKey pubKey;
if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
- return CBitcoinAddress(pubKey.GetID());
+ return pubKey.GetID();
}
UniValue getaccountaddress(const JSONRPCRequest& request)
@@ -211,7 +213,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
UniValue ret(UniValue::VSTR);
- ret = GetAccountAddress(pwallet, strAccount).ToString();
+ ret = EncodeDestination(GetAccountAddress(pwallet, strAccount));
return ret;
}
@@ -250,7 +252,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
CKeyID keyID = vchPubKey.GetID();
- return CBitcoinAddress(keyID).ToString();
+ return EncodeDestination(keyID);
}
@@ -275,24 +277,25 @@ UniValue setaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
std::string strAccount;
- if (request.params.size() > 1)
+ if (!request.params[1].isNull())
strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
- if (IsMine(*pwallet, address.Get())) {
+ if (IsMine(*pwallet, dest)) {
// Detect when changing the account of an address that is the 'unused current key' of another account:
- if (pwallet->mapAddressBook.count(address.Get())) {
- std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name;
- if (address == GetAccountAddress(pwallet, strOldAccount)) {
+ if (pwallet->mapAddressBook.count(dest)) {
+ std::string strOldAccount = pwallet->mapAddressBook[dest].name;
+ if (dest == GetAccountAddress(pwallet, strOldAccount)) {
GetAccountAddress(pwallet, strOldAccount, true);
}
}
- pwallet->SetAddressBook(address.Get(), strAccount, "receive");
+ pwallet->SetAddressBook(dest, strAccount, "receive");
}
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
@@ -323,12 +326,13 @@ UniValue getaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
std::string strAccount;
- std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get());
+ std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(dest);
if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) {
strAccount = (*mi).second.name;
}
@@ -365,11 +369,12 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
// 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;
+ for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ const CTxDestination& dest = item.first;
const std::string& strName = item.second.name;
- if (strName == strAccount)
- ret.push_back(address.ToString());
+ if (strName == strAccount) {
+ ret.push_back(EncodeDestination(dest));
+ }
}
return ret;
}
@@ -449,11 +454,13 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
// Amount
CAmount nAmount = AmountFromValue(request.params[1]);
@@ -462,26 +469,26 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
// Wallet comments
CWalletTx wtx;
- if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())
+ if (!request.params[2].isNull() && !request.params[2].get_str().empty())
wtx.mapValue["comment"] = request.params[2].get_str();
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (request.params.size() > 4 && !request.params[4].isNull()) {
+ if (!request.params[4].isNull()) {
fSubtractFeeFromAmount = request.params[4].get_bool();
}
CCoinControl coin_control;
- if (request.params.size() > 5 && !request.params[5].isNull()) {
+ if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
- if (request.params.size() > 6 && !request.params[6].isNull()) {
+ if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
- if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
@@ -490,7 +497,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control);
+ SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control);
return wtx.GetHash().GetHex();
}
@@ -525,20 +532,21 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
+ HelpExampleRpc("listaddressgroupings", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances();
- for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) {
+ for (const std::set<CTxDestination>& grouping : pwallet->GetAddressGroupings()) {
UniValue jsonGrouping(UniValue::VARR);
- for (CTxDestination address : grouping)
+ for (const CTxDestination& address : grouping)
{
UniValue addressInfo(UniValue::VARR);
- addressInfo.push_back(CBitcoinAddress(address).ToString());
+ addressInfo.push_back(EncodeDestination(address));
addressInfo.push_back(ValueFromAmount(balances[address]));
{
- if (pwallet->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwallet->mapAddressBook.end()) {
- addressInfo.push_back(pwallet->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
+ if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
+ addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
}
}
jsonGrouping.push_back(addressInfo);
@@ -583,16 +591,18 @@ UniValue signmessage(const JSONRPCRequest& request)
std::string strAddress = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
- CBitcoinAddress addr(strAddress);
- if (!addr.IsValid())
+ CTxDestination dest = DecodeDestination(strAddress);
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
+ }
- CKeyID keyID;
- if (!addr.GetKeyID(keyID))
+ const CKeyID *keyID = boost::get<CKeyID>(&dest);
+ if (!keyID) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
+ }
CKey key;
- if (!pwallet->GetKey(keyID, key)) {
+ if (!pwallet->GetKey(*keyID, key)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
}
@@ -634,13 +644,15 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
- CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ }
+ CScript scriptPubKey = GetScriptForDestination(dest);
if (!IsMine(*pwallet, scriptPubKey)) {
return ValueFromAmount(0);
}
@@ -694,6 +706,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
// Minimum confirmations
@@ -766,20 +779,34 @@ UniValue getbalance(const JSONRPCRequest& request)
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 0)
- return ValueFromAmount(pwallet->GetBalance());
+ const UniValue& account_value = request.params[0];
+ const UniValue& minconf = request.params[1];
+ const UniValue& include_watchonly = request.params[2];
- const std::string& account_param = request.params[0].get_str();
+ if (account_value.isNull()) {
+ if (!minconf.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance minconf option is only currently supported if an account is specified");
+ }
+ if (!include_watchonly.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER,
+ "getbalance include_watchonly option is only currently supported if an account is specified");
+ }
+ return ValueFromAmount(pwallet->GetBalance());
+ }
+
+ const std::string& account_param = account_value.get_str();
const std::string* account = account_param != "*" ? &account_param : nullptr;
int nMinDepth = 1;
- if (!request.params[1].isNull())
- nMinDepth = request.params[1].get_int();
+ if (!minconf.isNull())
+ nMinDepth = minconf.get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(!request.params[2].isNull())
- if(request.params[2].get_bool())
+ if(!include_watchonly.isNull())
+ if(include_watchonly.get_bool())
filter = filter | ISMINE_WATCH_ONLY;
return ValueFromAmount(pwallet->GetLegacyBalance(filter, nMinDepth, account));
@@ -797,6 +824,7 @@ UniValue getunconfirmedbalance(const JSONRPCRequest &request)
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetUnconfirmedBalance());
@@ -831,6 +859,7 @@ UniValue movecmd(const JSONRPCRequest& request)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strFrom = AccountFromValue(request.params[0]);
@@ -838,11 +867,11 @@ UniValue movecmd(const JSONRPCRequest& request)
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)request.params[3].get_int();
std::string strComment;
- if (request.params.size() > 4)
+ if (!request.params[4].isNull())
strComment = request.params[4].get_str();
if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) {
@@ -889,24 +918,26 @@ UniValue sendfrom(const JSONRPCRequest& request)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = AccountFromValue(request.params[0]);
- CBitcoinAddress address(request.params[1].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[1].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
- if (request.params.size() > 3)
+ if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())
+ if (!request.params[4].isNull() && !request.params[4].get_str().empty())
wtx.mapValue["comment"] = request.params[4].get_str();
- if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())
+ if (!request.params[5].isNull() && !request.params[5].get_str().empty())
wtx.mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked(pwallet);
@@ -917,7 +948,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
CCoinControl no_coin_control; // This is a deprecated API
- SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control);
+ SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control);
return wtx.GetHash().GetHex();
}
@@ -972,6 +1003,7 @@ UniValue sendmany(const JSONRPCRequest& request)
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
if (pwallet->GetBroadcastTransactions() && !g_connman) {
@@ -986,44 +1018,45 @@ UniValue sendmany(const JSONRPCRequest& request)
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ if (!request.params[3].isNull() && !request.params[3].get_str().empty())
wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (request.params.size() > 4 && !request.params[4].isNull())
+ if (!request.params[4].isNull())
subtractFeeFromAmount = request.params[4].get_array();
CCoinControl coin_control;
- if (request.params.size() > 5 && !request.params[5].isNull()) {
+ if (!request.params[5].isNull()) {
coin_control.signalRbf = request.params[5].get_bool();
}
- if (request.params.size() > 6 && !request.params[6].isNull()) {
+ if (!request.params[6].isNull()) {
coin_control.m_confirm_target = ParseConfirmTarget(request.params[6]);
}
- if (request.params.size() > 7 && !request.params[7].isNull()) {
+ if (!request.params[7].isNull()) {
if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
}
- std::set<CBitcoinAddress> setAddress;
+ std::set<CTxDestination> destinations;
std::vector<CRecipient> vecSend;
CAmount totalAmount = 0;
std::vector<std::string> keys = sendTo.getKeys();
- for (const std::string& name_ : keys)
- {
- CBitcoinAddress address(name_);
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_);
+ for (const std::string& name_ : keys) {
+ CTxDestination dest = DecodeDestination(name_);
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_);
- setAddress.insert(address);
+ if (destinations.count(dest)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
+ destinations.insert(dest);
- CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CScript scriptPubKey = GetScriptForDestination(dest);
CAmount nAmount = AmountFromValue(sendTo[name_]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
@@ -1105,7 +1138,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount;
- if (request.params.size() > 2)
+ if (!request.params[2].isNull())
strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
@@ -1114,7 +1147,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
pwallet->AddCScript(inner);
pwallet->SetAddressBook(innerID, strAccount, "send");
- return CBitcoinAddress(innerID).ToString();
+ return EncodeDestination(innerID);
}
class Witnessifier : public boost::static_visitor<bool>
@@ -1123,7 +1156,7 @@ public:
CWallet * const pwallet;
CScriptID result;
- Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
+ explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
bool operator()(const CNoDestination &dest) const { return false; }
@@ -1202,12 +1235,12 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
}
}
- CBitcoinAddress address(request.params[0].get_str());
- if (!address.IsValid())
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
+ }
Witnessifier w(pwallet);
- CTxDestination dest = address.Get();
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
@@ -1215,7 +1248,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
pwallet->SetAddressBook(w.result, "", "receive");
- return CBitcoinAddress(w.result).ToString();
+ return EncodeDestination(w.result);
}
struct tallyitem
@@ -1250,7 +1283,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
filter = filter | ISMINE_WATCH_ONLY;
// Tally
- std::map<CBitcoinAddress, tallyitem> mapTally;
+ std::map<CTxDestination, tallyitem> mapTally;
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
const CWalletTx& wtx = pairWtx.second;
@@ -1283,10 +1316,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
// Reply
UniValue ret(UniValue::VARR);
std::map<std::string, tallyitem> mapAccountTally;
- for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) {
- const CBitcoinAddress& address = item.first;
+ for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
+ const CTxDestination& dest = item.first;
const std::string& strAccount = item.second.name;
- std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
+ std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@@ -1312,7 +1345,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("address", address.ToString()));
+ obj.push_back(Pair("address", EncodeDestination(dest)));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
@@ -1389,6 +1422,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, false);
@@ -1428,6 +1462,7 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, true);
@@ -1435,9 +1470,9 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
- CBitcoinAddress addr;
- if (addr.Set(dest))
- entry.push_back(Pair("address", addr.ToString()));
+ if (IsValidDestination(dest)) {
+ entry.push_back(Pair("address", EncodeDestination(dest)));
+ }
}
/**
@@ -1615,6 +1650,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = "*";
@@ -1708,13 +1744,14 @@ UniValue listaccounts(const JSONRPCRequest& request)
+ HelpExampleRpc("listaccounts", "6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
- if (request.params.size() > 0)
+ if (!request.params[0].isNull())
nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(request.params.size() > 1)
+ if(!request.params[1].isNull())
if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
@@ -1816,6 +1853,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
@@ -1874,10 +1912,11 @@ UniValue listsinceblock(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
}
for (const CTransactionRef& tx : block.vtx) {
- if (pwallet->mapWallet.count(tx->GetHash()) > 0) {
+ auto it = pwallet->mapWallet.find(tx->GetHash());
+ if (it != pwallet->mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative.
- ListTransactions(pwallet, pwallet->mapWallet[tx->GetHash()], "*", -100000000, true, removed, filter);
+ ListTransactions(pwallet, it->second, "*", -100000000, true, removed, filter);
}
}
paltindex = paltindex->pprev;
@@ -1946,6 +1985,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -1957,10 +1997,11 @@ UniValue gettransaction(const JSONRPCRequest& request)
filter = filter | ISMINE_WATCH_ONLY;
UniValue entry(UniValue::VOBJ);
- if (!pwallet->mapWallet.count(hash)) {
+ auto it = pwallet->mapWallet.find(hash);
+ if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
}
- const CWalletTx& wtx = pwallet->mapWallet[hash];
+ const CWalletTx& wtx = it->second;
CAmount nCredit = wtx.GetCredit(filter);
CAmount nDebit = wtx.GetDebit(filter);
@@ -2006,6 +2047,7 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -2361,19 +2403,18 @@ UniValue lockunspent(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.params.size() == 1)
- RPCTypeCheck(request.params, {UniValue::VBOOL});
- else
- RPCTypeCheck(request.params, {UniValue::VBOOL, UniValue::VARR});
+ RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
bool fUnlock = request.params[0].get_bool();
- if (request.params.size() == 1) {
+ if (request.params[1].isNull()) {
if (fUnlock)
pwallet->UnlockAllCoins();
return true;
}
+ RPCTypeCheckArgument(request.params[1], UniValue::VARR);
+
UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
@@ -2439,6 +2480,7 @@ UniValue listlockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listlockunspent", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
std::vector<COutPoint> vOutpts;
@@ -2517,6 +2559,7 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
+ HelpExampleRpc("getwalletinfo", "")
);
+ ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
UniValue obj(UniValue::VOBJ);
@@ -2669,35 +2712,38 @@ UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
);
+ ObserveSafeMode();
+
int nMinDepth = 1;
- if (request.params.size() > 0 && !request.params[0].isNull()) {
+ if (!request.params[0].isNull()) {
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int();
}
int nMaxDepth = 9999999;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int();
}
- std::set<CBitcoinAddress> setAddress;
- if (request.params.size() > 2 && !request.params[2].isNull()) {
+ std::set<CTxDestination> destinations;
+ if (!request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
- CBitcoinAddress address(input.get_str());
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str());
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str());
- setAddress.insert(address);
+ CTxDestination dest = DecodeDestination(input.get_str());
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
+ }
+ if (!destinations.insert(dest).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
+ }
}
}
bool include_unsafe = true;
- if (request.params.size() > 3 && !request.params[3].isNull()) {
+ if (!request.params[3].isNull()) {
RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
include_unsafe = request.params[3].get_bool();
}
@@ -2734,7 +2780,7 @@ UniValue listunspent(const JSONRPCRequest& request)
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
- if (setAddress.size() && (!fValidAddress || !setAddress.count(address)))
+ if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
UniValue entry(UniValue::VOBJ);
@@ -2742,7 +2788,7 @@ UniValue listunspent(const JSONRPCRequest& request)
entry.push_back(Pair("vout", out.i));
if (fValidAddress) {
- entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
+ entry.push_back(Pair("address", EncodeDestination(address)));
if (pwallet->mapAddressBook.count(address)) {
entry.push_back(Pair("account", pwallet->mapAddressBook[address].name));
@@ -2797,7 +2843,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
- " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n"
+ " \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
" The outputs are specified by their zero-based index, before any change output is added.\n"
@@ -2830,6 +2876,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);
+ ObserveSafeMode();
RPCTypeCheck(request.params, {UniValue::VSTR});
CCoinControl coinControl;
@@ -2864,12 +2911,13 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
true, true);
if (options.exists("changeAddress")) {
- CBitcoinAddress address(options["changeAddress"].get_str());
+ CTxDestination dest = DecodeDestination(options["changeAddress"].get_str());
- if (!address.IsValid())
+ if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address");
+ }
- coinControl.destChange = address.Get();
+ coinControl.destChange = dest;
}
if (options.exists("changePosition"))
@@ -3112,7 +3160,7 @@ UniValue generate(const JSONRPCRequest& request)
int num_generate = request.params[0].get_int();
uint64_t max_tries = 1000000;
- if (request.params.size() > 1 && !request.params[1].isNull()) {
+ if (!request.params[1].isNull()) {
max_tries = request.params[1].get_int();
}
@@ -3144,60 +3192,60 @@ extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
-{ // category name actor (function) okSafeMode
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false, {"hexstring","options"} },
- { "hidden", "resendwallettransactions", &resendwallettransactions, true, {} },
- { "wallet", "abandontransaction", &abandontransaction, false, {"txid"} },
- { "wallet", "abortrescan", &abortrescan, false, {} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
- { "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
- { "wallet", "backupwallet", &backupwallet, true, {"destination"} },
- { "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
- { "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
- { "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
- { "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
- { "wallet", "getaccountaddress", &getaccountaddress, true, {"account"} },
- { "wallet", "getaccount", &getaccount, true, {"address"} },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, {"account"} },
- { "wallet", "getbalance", &getbalance, false, {"account","minconf","include_watchonly"} },
- { "wallet", "getnewaddress", &getnewaddress, true, {"account"} },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, {} },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, {"account","minconf"} },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, {"address","minconf"} },
- { "wallet", "gettransaction", &gettransaction, false, {"txid","include_watchonly"} },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, {} },
- { "wallet", "getwalletinfo", &getwalletinfo, false, {} },
- { "wallet", "importmulti", &importmulti, true, {"requests","options"} },
- { "wallet", "importprivkey", &importprivkey, true, {"privkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, true, {"filename"} },
- { "wallet", "importaddress", &importaddress, true, {"address","label","rescan","p2sh"} },
- { "wallet", "importprunedfunds", &importprunedfunds, true, {"rawtransaction","txoutproof"} },
- { "wallet", "importpubkey", &importpubkey, true, {"pubkey","label","rescan"} },
- { "wallet", "keypoolrefill", &keypoolrefill, true, {"newsize"} },
- { "wallet", "listaccounts", &listaccounts, false, {"minconf","include_watchonly"} },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false, {} },
- { "wallet", "listlockunspent", &listlockunspent, false, {} },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
- { "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
- { "wallet", "listwallets", &listwallets, true, {} },
- { "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
- { "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
- { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
- { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
- { "wallet", "setaccount", &setaccount, true, {"address","account"} },
- { "wallet", "settxfee", &settxfee, true, {"amount"} },
- { "wallet", "signmessage", &signmessage, true, {"address","message"} },
- { "wallet", "walletlock", &walletlock, true, {} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, {"oldpassphrase","newpassphrase"} },
- { "wallet", "walletpassphrase", &walletpassphrase, true, {"passphrase","timeout"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, true, {"txid"} },
-
- { "generating", "generate", &generate, true, {"nblocks","maxtries"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options"} },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
+ { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
+ { "wallet", "abortrescan", &abortrescan, {} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} },
+ { "wallet", "addwitnessaddress", &addwitnessaddress, {"address"} },
+ { "wallet", "backupwallet", &backupwallet, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
+ { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
+ { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
+ { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
+ { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
+ { "wallet", "getaccount", &getaccount, {"address"} },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
+ { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} },
+ { "wallet", "getnewaddress", &getnewaddress, {"account"} },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, {} },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
+ { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
+ { "wallet", "getwalletinfo", &getwalletinfo, {} },
+ { "wallet", "importmulti", &importmulti, {"requests","options"} },
+ { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
+ { "wallet", "importwallet", &importwallet, {"filename"} },
+ { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
+ { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
+ { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
+ { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
+ { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
+ { "wallet", "listlockunspent", &listlockunspent, {} },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
+ { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} },
+ { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
+ { "wallet", "listwallets", &listwallets, {} },
+ { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
+ { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
+ { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
+ { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "setaccount", &setaccount, {"address","account"} },
+ { "wallet", "settxfee", &settxfee, {"amount"} },
+ { "wallet", "signmessage", &signmessage, {"address","message"} },
+ { "wallet", "walletlock", &walletlock, {} },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
+ { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+
+ { "generating", "generate", &generate, {"nblocks","maxtries"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index 98d957b322..cbd74b6f96 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -9,86 +9,9 @@
#include <vector>
#include <boost/test/unit_test.hpp>
-#include <openssl/aes.h>
-#include <openssl/evp.h>
BOOST_FIXTURE_TEST_SUITE(wallet_crypto, BasicTestingSetup)
-bool OldSetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod, unsigned char* chKey, unsigned char* chIV)
-{
- if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
- return false;
-
- int i = 0;
- if (nDerivationMethod == 0)
- i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
- (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV);
-
- if (i != (int)WALLET_CRYPTO_KEY_SIZE)
- {
- memory_cleanse(chKey, WALLET_CRYPTO_KEY_SIZE);
- memory_cleanse(chIV, WALLET_CRYPTO_IV_SIZE);
- return false;
- }
- return true;
-}
-
-bool OldEncrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext, const unsigned char chKey[32], const unsigned char chIV[16])
-{
- // max ciphertext len for a n bytes of plaintext is
- // n + AES_BLOCK_SIZE - 1 bytes
- int nLen = vchPlaintext.size();
- int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
- vchCiphertext = std::vector<unsigned char> (nCLen);
-
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
-
- if (!ctx) return false;
-
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(ctx);
- if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, chKey, chIV) != 0;
- if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen) != 0;
- if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0]) + nCLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(ctx);
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!fOk) return false;
-
- vchCiphertext.resize(nCLen + nFLen);
- return true;
-}
-
-bool OldDecrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext, const unsigned char chKey[32], const unsigned char chIV[16])
-{
- // plaintext will always be equal to or lesser than length of ciphertext
- int nLen = vchCiphertext.size();
- int nPLen = nLen, nFLen = 0;
-
- vchPlaintext = CKeyingMaterial(nPLen);
-
- EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
-
- if (!ctx) return false;
-
- bool fOk = true;
-
- EVP_CIPHER_CTX_init(ctx);
- if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, chKey, chIV) != 0;
- if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen) != 0;
- if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0]) + nPLen, &nFLen) != 0;
- EVP_CIPHER_CTX_cleanup(ctx);
-
- EVP_CIPHER_CTX_free(ctx);
-
- if (!fOk) return false;
-
- vchPlaintext.resize(nPLen + nFLen);
- return true;
-}
-
class TestCrypter
{
public:
@@ -96,25 +19,15 @@ static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, cons
const std::vector<unsigned char>& correctKey = std::vector<unsigned char>(),
const std::vector<unsigned char>& correctIV=std::vector<unsigned char>())
{
- unsigned char chKey[WALLET_CRYPTO_KEY_SIZE];
- unsigned char chIV[WALLET_CRYPTO_IV_SIZE];
-
CCrypter crypt;
crypt.SetKeyFromPassphrase(passphrase, vchSalt, rounds, 0);
- OldSetKeyFromPassphrase(passphrase, vchSalt, rounds, 0, chKey, chIV);
-
- BOOST_CHECK_MESSAGE(memcmp(chKey, crypt.vchKey.data(), crypt.vchKey.size()) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(crypt.vchKey));
- BOOST_CHECK_MESSAGE(memcmp(chIV, crypt.vchIV.data(), crypt.vchIV.size()) == 0, \
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(crypt.vchIV));
-
if(!correctKey.empty())
- BOOST_CHECK_MESSAGE(memcmp(chKey, &correctKey[0], sizeof(chKey)) == 0, \
- HexStr(chKey, chKey+sizeof(chKey)) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
+ BOOST_CHECK_MESSAGE(memcmp(crypt.vchKey.data(), correctKey.data(), crypt.vchKey.size()) == 0, \
+ HexStr(crypt.vchKey.begin(), crypt.vchKey.end()) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
if(!correctIV.empty())
- BOOST_CHECK_MESSAGE(memcmp(chIV, &correctIV[0], sizeof(chIV)) == 0,
- HexStr(chIV, chIV+sizeof(chIV)) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
+ BOOST_CHECK_MESSAGE(memcmp(crypt.vchIV.data(), correctIV.data(), crypt.vchIV.size()) == 0,
+ HexStr(crypt.vchIV.begin(), crypt.vchIV.end()) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
}
static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,
@@ -126,50 +39,26 @@ static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const Secu
TestPassphraseSingle(vchSalt, SecureString(i, passphrase.end()), rounds);
}
-
static void TestDecrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchCiphertext, \
const std::vector<unsigned char>& vchPlaintext = std::vector<unsigned char>())
{
- CKeyingMaterial vchDecrypted1;
- CKeyingMaterial vchDecrypted2;
- int result1, result2;
- result1 = crypt.Decrypt(vchCiphertext, vchDecrypted1);
- result2 = OldDecrypt(vchCiphertext, vchDecrypted2, crypt.vchKey.data(), crypt.vchIV.data());
- BOOST_CHECK(result1 == result2);
-
- // These two should be equal. However, OpenSSL 1.0.1j introduced a change
- // that would zero all padding except for the last byte for failed decrypts.
- // This behavior was reverted for 1.0.1k.
- if (vchDecrypted1 != vchDecrypted2 && vchDecrypted1.size() >= AES_BLOCK_SIZE && SSLeay() == 0x100010afL)
- {
- for(CKeyingMaterial::iterator it = vchDecrypted1.end() - AES_BLOCK_SIZE; it != vchDecrypted1.end() - 1; it++)
- *it = 0;
- }
-
- BOOST_CHECK_MESSAGE(vchDecrypted1 == vchDecrypted2, HexStr(vchDecrypted1.begin(), vchDecrypted1.end()) + " != " + HexStr(vchDecrypted2.begin(), vchDecrypted2.end()));
-
+ CKeyingMaterial vchDecrypted;
+ crypt.Decrypt(vchCiphertext, vchDecrypted);
if (vchPlaintext.size())
- BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted2);
+ BOOST_CHECK(CKeyingMaterial(vchPlaintext.begin(), vchPlaintext.end()) == vchDecrypted);
}
static void TestEncryptSingle(const CCrypter& crypt, const CKeyingMaterial& vchPlaintext,
const std::vector<unsigned char>& vchCiphertextCorrect = std::vector<unsigned char>())
{
- std::vector<unsigned char> vchCiphertext1;
- std::vector<unsigned char> vchCiphertext2;
- int result1 = crypt.Encrypt(vchPlaintext, vchCiphertext1);
-
- int result2 = OldEncrypt(vchPlaintext, vchCiphertext2, crypt.vchKey.data(), crypt.vchIV.data());
- BOOST_CHECK(result1 == result2);
- BOOST_CHECK(vchCiphertext1 == vchCiphertext2);
+ std::vector<unsigned char> vchCiphertext;
+ crypt.Encrypt(vchPlaintext, vchCiphertext);
if (!vchCiphertextCorrect.empty())
- BOOST_CHECK(vchCiphertext2 == vchCiphertextCorrect);
+ BOOST_CHECK(vchCiphertext == vchCiphertextCorrect);
const std::vector<unsigned char> vchPlaintext2(vchPlaintext.begin(), vchPlaintext.end());
-
- if(vchCiphertext1 == vchCiphertext2)
- TestDecrypt(crypt, vchCiphertext1, vchPlaintext2);
+ TestDecrypt(crypt, vchCiphertext, vchPlaintext2);
}
static void TestEncrypt(const CCrypter& crypt, const std::vector<unsigned char>& vchPlaintextIn, \
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index 97a6d98397..9373b7907c 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -10,7 +10,7 @@
/** Testing setup and teardown for wallet.
*/
struct WalletTestingSetup: public TestingSetup {
- WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~WalletTestingSetup();
};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 4a2cc9a139..5ebacd57d3 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -364,6 +364,12 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
empty_wallet();
}
+static void AddKey(CWallet& wallet, const CKey& key)
+{
+ LOCK(wallet.cs_wallet);
+ wallet.AddKeyPubKey(key, key.GetPubKey());
+}
+
BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
LOCK(cs_main);
@@ -379,8 +385,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// and new block files.
{
CWallet wallet;
- LOCK(wallet.cs_wallet);
- wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ AddKey(wallet, coinbaseKey);
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -393,8 +398,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
// file.
{
CWallet wallet;
- LOCK(wallet.cs_wallet);
- wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ AddKey(wallet, coinbaseKey);
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -599,8 +603,7 @@ public:
wallet.reset(new CWallet(std::unique_ptr<CWalletDBWrapper>(new CWalletDBWrapper(&bitdb, "wallet_test.dat"))));
bool firstRun;
wallet->LoadWallet(firstRun);
- LOCK(wallet->cs_wallet);
- wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+ AddKey(*wallet, coinbaseKey);
wallet->ScanForWalletTransactions(chainActive.Genesis());
}
@@ -635,7 +638,7 @@ public:
BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
{
std::string coinbaseAddress = coinbaseKey.GetPubKey().GetID().ToString();
- LOCK(wallet->cs_wallet);
+ LOCK2(cs_main, wallet->cs_wallet);
// Confirm ListCoins initially returns 1 coin grouped under coinbaseKey
// address.
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index f8c6f9e87b..584324feb5 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -30,6 +30,7 @@
#include "util.h"
#include "ui_interface.h"
#include "utilmoneystr.h"
+#include "wallet/fees.h"
#include <assert.h>
@@ -306,7 +307,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
- std::string strAddr = CBitcoinAddress(CScriptID(redeemScript)).ToString();
+ std::string strAddr = EncodeDestination(CScriptID(redeemScript));
LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n",
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
@@ -494,63 +495,6 @@ void CWallet::Flush(bool shutdown)
dbw->Flush(shutdown);
}
-bool CWallet::Verify()
-{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
- return true;
-
- uiInterface.InitMessage(_("Verifying wallet(s)..."));
-
- // Keep track of each wallet absolute path to detect duplicates.
- std::set<fs::path> wallet_paths;
-
- for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- if (boost::filesystem::path(walletFile).filename() != walletFile) {
- return InitError(strprintf(_("Error loading wallet %s. -wallet parameter must only specify a filename (not a path)."), walletFile));
- }
-
- if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
- return InitError(strprintf(_("Error loading wallet %s. Invalid characters in -wallet filename."), walletFile));
- }
-
- fs::path wallet_path = fs::absolute(walletFile, GetDataDir());
-
- if (fs::exists(wallet_path) && (!fs::is_regular_file(wallet_path) || fs::is_symlink(wallet_path))) {
- return InitError(strprintf(_("Error loading wallet %s. -wallet filename must be a regular file."), walletFile));
- }
-
- if (!wallet_paths.insert(wallet_path).second) {
- return InitError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), walletFile));
- }
-
- std::string strError;
- if (!CWalletDB::VerifyEnvironment(walletFile, GetDataDir().string(), strError)) {
- return InitError(strError);
- }
-
- if (gArgs.GetBoolArg("-salvagewallet", false)) {
- // Recover readable keypairs:
- CWallet dummyWallet;
- std::string backup_filename;
- if (!CWalletDB::Recover(walletFile, (void *)&dummyWallet, CWalletDB::RecoverKeysOnlyFilter, backup_filename)) {
- return false;
- }
- }
-
- std::string strWarning;
- bool dbV = CWalletDB::VerifyDatabaseFile(walletFile, GetDataDir().string(), strWarning, strError);
- if (!strWarning.empty()) {
- InitWarning(strWarning);
- }
- if (!dbV) {
- InitError(strError);
- return false;
- }
- }
-
- return true;
-}
-
void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range)
{
// We want all the wallet transactions in range to have the same metadata as
@@ -623,8 +567,9 @@ void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid)
void CWallet::AddToSpends(const uint256& wtxid)
{
- assert(mapWallet.count(wtxid));
- CWalletTx& thisTx = mapWallet[wtxid];
+ auto it = mapWallet.find(wtxid);
+ assert(it != mapWallet.end());
+ CWalletTx& thisTx = it->second;
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
@@ -1007,8 +952,9 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, nullptr)));
AddToSpends(hash);
for (const CTxIn& txin : wtx.tx->vin) {
- if (mapWallet.count(txin.prevout.hash)) {
- CWalletTx& prevtx = mapWallet[txin.prevout.hash];
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ CWalletTx& prevtx = it->second;
if (prevtx.nIndex == -1 && !prevtx.hashUnset()) {
MarkConflicted(prevtx.hashBlock, wtx.GetHash());
}
@@ -1107,8 +1053,9 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
std::set<uint256> done;
// Can't mark abandoned if confirmed or in mempool
- assert(mapWallet.count(hashTx));
- CWalletTx& origtx = mapWallet[hashTx];
+ auto it = mapWallet.find(hashTx);
+ assert(it != mapWallet.end());
+ CWalletTx& origtx = it->second;
if (origtx.GetDepthInMainChain() > 0 || origtx.InMempool()) {
return false;
}
@@ -1119,8 +1066,9 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
- assert(mapWallet.count(now));
- CWalletTx& wtx = mapWallet[now];
+ auto it = mapWallet.find(now);
+ assert(it != mapWallet.end());
+ CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
// If the orig tx was not in block, none of its spends can be
assert(currentconfirm <= 0);
@@ -1145,8 +1093,10 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
// available of the outputs it spends. So force those to be recomputed
for (const CTxIn& txin : wtx.tx->vin)
{
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
}
@@ -1184,8 +1134,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
uint256 now = *todo.begin();
todo.erase(now);
done.insert(now);
- assert(mapWallet.count(now));
- CWalletTx& wtx = mapWallet[now];
+ auto it = mapWallet.find(now);
+ assert(it != mapWallet.end());
+ CWalletTx& wtx = it->second;
int currentconfirm = wtx.GetDepthInMainChain();
if (conflictconfirms < currentconfirm) {
// Block is 'more conflicted' than current confirm; update.
@@ -1204,10 +1155,11 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
- for (const CTxIn& txin : wtx.tx->vin)
- {
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ for (const CTxIn& txin : wtx.tx->vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
}
@@ -1222,10 +1174,11 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be
// recomputed, also:
- for (const CTxIn& txin : tx.vin)
- {
- if (mapWallet.count(txin.prevout.hash))
- mapWallet[txin.prevout.hash].MarkDirty();
+ for (const CTxIn& txin : tx.vin) {
+ auto it = mapWallet.find(txin.prevout.hash);
+ if (it != mapWallet.end()) {
+ it->second.MarkDirty();
+ }
}
}
@@ -2599,17 +2552,6 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
return true;
}
-static CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator)
-{
- unsigned int highest_target = estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
- CFeeRate discard_rate = estimator.estimateSmartFee(highest_target, nullptr /* FeeCalculation */, false /* conservative */);
- // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
- discard_rate = (discard_rate == CFeeRate(0)) ? CWallet::m_discard_rate : std::min(discard_rate, CWallet::m_discard_rate);
- // Discard rate must be at least dustRelayFee
- discard_rate = std::max(discard_rate, ::dustRelayFee);
- return discard_rate;
-}
-
bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign)
{
@@ -2670,6 +2612,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
assert(txNew.nLockTime <= (unsigned int)chainActive.Height());
assert(txNew.nLockTime < LOCKTIME_THRESHOLD);
FeeCalculation feeCalc;
+ CAmount nFeeNeeded;
unsigned int nBytes;
{
std::set<CInputCoin> setCoins;
@@ -2831,7 +2774,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
vin.scriptWitness.SetNull();
}
- CAmount nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
+ nFeeNeeded = GetMinimumFee(nBytes, coin_control, ::mempool, ::feeEstimator, &feeCalc);
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
@@ -2852,13 +2795,15 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// new inputs. We now know we only need the smaller fee
// (because of reduced tx size) and so we should add a
// change output. Only try this once.
- CAmount fee_needed_for_change = GetMinimumFee(change_prototype_size, coin_control, ::mempool, ::feeEstimator, nullptr);
- CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
- CAmount max_excess_fee = fee_needed_for_change + minimum_value_for_change;
- if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
- pick_new_inputs = false;
- nFeeRet = nFeeNeeded + fee_needed_for_change;
- continue;
+ if (nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) {
+ unsigned int tx_size_with_change = nBytes + change_prototype_size + 2; // Add 2 as a buffer in case increasing # of outputs changes compact size
+ CAmount fee_needed_with_change = GetMinimumFee(tx_size_with_change, coin_control, ::mempool, ::feeEstimator, nullptr);
+ CAmount minimum_value_for_change = GetDustThreshold(change_prototype_txout, discard_rate);
+ if (nFeeRet >= fee_needed_with_change + minimum_value_for_change) {
+ pick_new_inputs = false;
+ nFeeRet = fee_needed_with_change;
+ continue;
+ }
}
// If we have change output already, just increase it
@@ -2953,8 +2898,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
}
}
- LogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
- nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
+ LogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
+ nFeeRet, nBytes, nFeeNeeded, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
feeCalc.est.pass.start, feeCalc.est.pass.end,
100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool),
feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
@@ -3031,80 +2976,16 @@ bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwa
return true;
}
-CAmount CWallet::GetRequiredFee(unsigned int nTxBytes)
-{
- return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes));
-}
-
-CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc)
-{
- /* User control of how to calculate fee uses the following parameter precedence:
- 1. coin_control.m_feerate
- 2. coin_control.m_confirm_target
- 3. payTxFee (user-set global variable)
- 4. nTxConfirmTarget (user-set global variable)
- The first parameter that is set is used.
- */
- CAmount fee_needed;
- if (coin_control.m_feerate) { // 1.
- fee_needed = coin_control.m_feerate->GetFee(nTxBytes);
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
- // Allow to override automatic min/max check over coin control instance
- if (coin_control.fOverrideFeeRate) return fee_needed;
- }
- else if (!coin_control.m_confirm_target && ::payTxFee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for global payTxFee
- fee_needed = ::payTxFee.GetFee(nTxBytes);
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
- }
- else { // 2. or 4.
- // We will use smart fee estimation
- unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : ::nTxConfirmTarget;
- // By default estimates are economical iff we are signaling opt-in-RBF
- bool conservative_estimate = !coin_control.signalRbf;
- // Allow to override the default fee estimate mode over the CoinControl instance
- if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
- else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
-
- fee_needed = estimator.estimateSmartFee(target, feeCalc, conservative_estimate).GetFee(nTxBytes);
- if (fee_needed == 0) {
- // if we don't have enough data for estimateSmartFee, then use fallbackFee
- fee_needed = fallbackFee.GetFee(nTxBytes);
- if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
- }
- // Obey mempool min fee when using smart fee estimation
- CAmount min_mempool_fee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nTxBytes);
- if (fee_needed < min_mempool_fee) {
- fee_needed = min_mempool_fee;
- if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
- }
- }
-
- // prevent user from paying a fee below minRelayTxFee or minTxFee
- CAmount required_fee = GetRequiredFee(nTxBytes);
- if (required_fee > fee_needed) {
- fee_needed = required_fee;
- if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
- }
- // But always obey the maximum
- if (fee_needed > maxTxFee) {
- fee_needed = maxTxFee;
- if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
- }
- return fee_needed;
-}
-
-
-
-
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
+ LOCK2(cs_main, cs_wallet);
+
fFirstRunRet = false;
DBErrors nLoadWalletRet = CWalletDB(*dbw,"cr+").LoadWallet(this);
if (nLoadWalletRet == DB_NEED_REWRITE)
{
if (dbw->Rewrite("\x04pool"))
{
- LOCK(cs_wallet);
setInternalKeyPool.clear();
setExternalKeyPool.clear();
m_pool_key_to_index.clear();
@@ -3114,9 +2995,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
}
+ // This wallet is in its first run if all of these are empty
+ fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty();
+
if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet;
- fFirstRunRet = !vchDefaultKey.IsValid();
uiInterface.LoadWallet(this);
@@ -3126,7 +3009,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
AssertLockHeld(cs_wallet); // mapWallet
- vchDefaultKey = CPubKey();
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut)
mapWallet.erase(hash);
@@ -3155,7 +3037,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{
- vchDefaultKey = CPubKey();
DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE)
{
@@ -3191,9 +3072,9 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
}
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
- if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose))
+ if (!strPurpose.empty() && !CWalletDB(*dbw).WritePurpose(EncodeDestination(address), strPurpose))
return false;
- return CWalletDB(*dbw).WriteName(CBitcoinAddress(address).ToString(), strName);
+ return CWalletDB(*dbw).WriteName(EncodeDestination(address), strName);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
@@ -3202,7 +3083,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
LOCK(cs_wallet); // mapAddressBook
// Delete destdata tuples associated with address
- std::string strAddress = CBitcoinAddress(address).ToString();
+ std::string strAddress = EncodeDestination(address);
for (const std::pair<std::string, std::string> &item : mapAddressBook[address].destdata)
{
CWalletDB(*dbw).EraseDestData(strAddress, item.first);
@@ -3212,8 +3093,8 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != ISMINE_NO, "", CT_DELETED);
- CWalletDB(*dbw).ErasePurpose(CBitcoinAddress(address).ToString());
- return CWalletDB(*dbw).EraseName(CBitcoinAddress(address).ToString());
+ CWalletDB(*dbw).ErasePurpose(EncodeDestination(address));
+ return CWalletDB(*dbw).EraseName(EncodeDestination(address));
}
const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
@@ -3231,14 +3112,6 @@ const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
return DEFAULT_ACCOUNT_NAME;
}
-bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
-{
- if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
- return false;
- vchDefaultKey = vchPubKey;
- return true;
-}
-
/**
* Mark old keypool keys as used,
* and generate all new keys
@@ -3659,15 +3532,11 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
}
walletdb.ErasePool(index);
+ LogPrintf("keypool index %d removed\n", index);
it = setKeyPool->erase(it);
}
}
-bool CWallet::HasUnusedKeys(int min_keys) const
-{
- return setExternalKeyPool.size() >= min_keys && (setInternalKeyPool.size() >= min_keys || !CanSupportFeature(FEATURE_HD_SPLIT));
-}
-
void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script)
{
std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this);
@@ -3842,14 +3711,14 @@ bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, co
return false;
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
- return CWalletDB(*dbw).WriteDestData(CBitcoinAddress(dest).ToString(), key, value);
+ return CWalletDB(*dbw).WriteDestData(EncodeDestination(dest), key, value);
}
bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key)
{
if (!mapAddressBook[dest].destdata.erase(key))
return false;
- return CWalletDB(*dbw).EraseDestData(CBitcoinAddress(dest).ToString(), key);
+ return CWalletDB(*dbw).EraseDestData(EncodeDestination(dest), key);
}
bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
@@ -3888,46 +3757,6 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
-std::string CWallet::GetWalletHelpString(bool showDebug)
-{
- std::string strUsage = HelpMessageGroup(_("Wallet options:"));
- strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
- strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), DEFAULT_KEYPOOL_SIZE));
- strUsage += HelpMessageOpt("-fallbackfee=<amt>", strprintf(_("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)));
- strUsage += HelpMessageOpt("-discardfee=<amt>", strprintf(_("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
- "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)));
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)"),
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)));
- strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
- 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"));
- 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));
- strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
- strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
- strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
- strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
- strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
- strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
- " " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
-
- if (showDebug)
- {
- strUsage += HelpMessageGroup(_("Wallet debugging/testing options:"));
-
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE));
- strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", DEFAULT_FLUSHWALLET));
- strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", DEFAULT_WALLET_PRIVDB));
- strUsage += HelpMessageOpt("-walletrejectlongchains", strprintf(_("Wallet will not create transactions that violate mempool chain limits (default: %u)"), DEFAULT_WALLET_REJECT_LONG_CHAINS));
- }
-
- return strUsage;
-}
-
CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
{
// needed to restore wallet transaction meta data after -zapwallettxes
@@ -3937,15 +3766,12 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
- CWallet *tempWallet = new CWallet(std::move(dbw));
+ std::unique_ptr<CWallet> tempWallet(new CWallet(std::move(dbw)));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
return nullptr;
}
-
- delete tempWallet;
- tempWallet = nullptr;
}
uiInterface.InitMessage(_("Loading wallet..."));
@@ -4014,13 +3840,11 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (!walletInstance->SetHDMasterKey(masterPubKey))
throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
}
- CPubKey newDefaultKey;
- if (walletInstance->GetKeyFromPool(newDefaultKey, false)) {
- walletInstance->SetDefaultKey(newDefaultKey);
- if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
- InitError(_("Cannot write default address") += "\n");
- return nullptr;
- }
+
+ // Top up the keypool
+ if (!walletInstance->TopUpKeyPool()) {
+ InitError(_("Unable to generate initial keys") += "\n");
+ return NULL;
}
walletInstance->SetBestChain(chainActive.GetLocator());
@@ -4121,24 +3945,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
return walletInstance;
}
-bool CWallet::InitLoadWallet()
-{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
- LogPrintf("Wallet disabled!\n");
- return true;
- }
-
- for (const std::string& walletFile : gArgs.GetArgs("-wallet")) {
- CWallet * const pwallet = CreateWalletFromFile(walletFile);
- if (!pwallet) {
- return false;
- }
- vpwallets.push_back(pwallet);
- }
-
- return true;
-}
-
std::atomic<bool> CWallet::fFlushScheduled(false);
void CWallet::postInitProcess(CScheduler& scheduler)
@@ -4153,126 +3959,6 @@ void CWallet::postInitProcess(CScheduler& scheduler)
}
}
-bool CWallet::ParameterInteraction()
-{
- gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
- const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
-
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
- return true;
-
- if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
- }
-
- if (gArgs.GetBoolArg("-salvagewallet", false)) {
- if (is_multiwallet) {
- return InitError(strprintf("%s is only allowed with a single wallet file", "-salvagewallet"));
- }
- // Rewrite just private keys: rescan to find transactions
- if (gArgs.SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting -rescan=1\n", __func__);
- }
- }
-
- int zapwallettxes = gArgs.GetArg("-zapwallettxes", 0);
- // -zapwallettxes implies dropping the mempool on startup
- if (zapwallettxes != 0 && gArgs.SoftSetBoolArg("-persistmempool", false)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
- }
-
- // -zapwallettxes implies a rescan
- if (zapwallettxes != 0) {
- if (is_multiwallet) {
- return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
- }
- if (gArgs.SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
- }
- }
-
- if (is_multiwallet) {
- if (gArgs.GetBoolArg("-upgradewallet", false)) {
- return InitError(strprintf("%s is only allowed with a single wallet file", "-upgradewallet"));
- }
- }
-
- if (gArgs.GetBoolArg("-sysperms", false))
- return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
- if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
- return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
-
- if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
- _("The wallet will avoid paying less than the minimum relay fee."));
-
- if (gArgs.IsArgSet("-mintxfee"))
- {
- CAmount n = 0;
- if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n)
- return InitError(AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")));
- if (n > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-mintxfee") + " " +
- _("This is the minimum transaction fee you pay on every transaction."));
- CWallet::minTxFee = CFeeRate(n);
- }
- if (gArgs.IsArgSet("-fallbackfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK))
- return InitError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-fallbackfee") + " " +
- _("This is the transaction fee you may pay when fee estimates are not available."));
- CWallet::fallbackFee = CFeeRate(nFeePerK);
- }
- if (gArgs.IsArgSet("-discardfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK))
- return InitError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-discardfee") + " " +
- _("This is the transaction fee you may discard if change is smaller than dust at this level"));
- CWallet::m_discard_rate = CFeeRate(nFeePerK);
- }
- if (gArgs.IsArgSet("-paytxfee"))
- {
- CAmount nFeePerK = 0;
- if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK))
- return InitError(AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")));
- if (nFeePerK > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-paytxfee") + " " +
- _("This is the transaction fee you will pay if you send a transaction."));
-
- payTxFee = CFeeRate(nFeePerK, 1000);
- if (payTxFee < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
- gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
- if (gArgs.IsArgSet("-maxtxfee"))
- {
- CAmount nMaxFee = 0;
- if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
- if (nMaxFee > HIGH_MAX_TX_FEE)
- InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
- maxTxFee = nMaxFee;
- if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
- gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
- nTxConfirmTarget = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
- bSpendZeroConfChange = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
- fWalletRbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
-
- return true;
-}
-
bool CWallet::BackupWallet(const std::string& strDest)
{
return dbw->Backup(strDest);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index f97a99d82a..51abe2b25f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -87,7 +87,7 @@ enum class FeeEstimateMode;
/** (client) version numbers for particular wallet features */
enum WalletFeature
{
- FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)
+ FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getwalletinfo's clientversion output)
FEATURE_WALLETCRYPT = 40000, // wallet encryption
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
@@ -208,7 +208,7 @@ public:
Init();
}
- CMerkleTx(CTransactionRef arg)
+ explicit CMerkleTx(CTransactionRef arg)
{
SetTx(std::move(arg));
Init();
@@ -548,7 +548,7 @@ public:
//! todo: add something to note what created it (user, getnewaddress, change)
//! maybe should have a map<string, string> property map
- CWalletKey(int64_t nExpires=0);
+ explicit CWalletKey(int64_t nExpires=0);
ADD_SERIALIZE_METHODS;
@@ -651,7 +651,7 @@ private:
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
-class CWallet : public CCryptoKeyStore, public CValidationInterface
+class CWallet final : public CCryptoKeyStore, public CValidationInterface
{
private:
static std::atomic<bool> fFlushScheduled;
@@ -765,7 +765,7 @@ public:
}
// Create wallet with passed-in database handle
- CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
+ explicit CWallet(std::unique_ptr<CWalletDBWrapper> dbw_in) : dbw(std::move(dbw_in))
{
SetNull();
}
@@ -807,8 +807,6 @@ public:
std::map<CTxDestination, CAddressBookData> mapAddressBook;
- CPubKey vchDefaultKey;
-
std::set<COutPoint> setLockedCoins;
const CWalletTx* GetWalletTx(const uint256& hash) const;
@@ -960,16 +958,6 @@ public:
static CFeeRate minTxFee;
static CFeeRate fallbackFee;
static CFeeRate m_discard_rate;
- /**
- * Estimate the minimum fee considering user set parameters
- * and the required fee
- */
- static CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl& coin_control, const CTxMemPool& pool, const CBlockPolicyEstimator& estimator, FeeCalculation *feeCalc);
- /**
- * Return the minimum required fee taking into account the
- * floating relay fee and user set minimum transaction fee
- */
- static CAmount GetRequiredFee(unsigned int nTxBytes);
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
@@ -984,8 +972,6 @@ public:
*/
void MarkReserveKeysAsUsed(int64_t keypool_id);
const std::map<CKeyID, int64_t>& GetAllReserveKeys() const { return m_pool_key_to_index; }
- /** Does the wallet have at least min_keys in the keypool? */
- bool HasUnusedKeys(int min_keys) const;
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
@@ -1040,8 +1026,6 @@ public:
return setInternalKeyPool.size() + setExternalKeyPool.size();
}
- bool SetDefaultKey(const CPubKey &vchPubKey);
-
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = nullptr, bool fExplicit = false);
@@ -1060,11 +1044,6 @@ public:
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
- //! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
- // This function will perform salvage on the wallet if requested, as long as only one wallet is
- // being loaded (CWallet::ParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
- static bool Verify();
-
/**
* Address book entry changed.
* @note called with lock cs_wallet held.
@@ -1101,12 +1080,8 @@ public:
/** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
- /* Returns the wallets help message */
- static std::string GetWalletHelpString(bool showDebug);
-
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static CWallet* CreateWalletFromFile(const std::string walletFile);
- static bool InitLoadWallet();
/**
* Wallet post-init setup
@@ -1114,9 +1089,6 @@ public:
*/
void postInitProcess(CScheduler& scheduler);
- /* Wallets parameter interaction */
- static bool ParameterInteraction();
-
bool BackupWallet(const std::string& strDest);
/* Set the HD chain model (chain child index counters) */
@@ -1137,7 +1109,7 @@ public:
};
/** A key allocated from the key pool. */
-class CReserveKey : public CReserveScript
+class CReserveKey final : public CReserveScript
{
protected:
CWallet* pwallet;
@@ -1145,7 +1117,7 @@ protected:
CPubKey vchPubKey;
bool fInternal;
public:
- CReserveKey(CWallet* pwalletIn)
+ explicit CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index cd26d87fdb..52370a8eb5 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -130,11 +130,6 @@ bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
return WriteIC(std::string("orderposnext"), nOrderPosNext);
}
-bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
-{
- return WriteIC(std::string("defaultkey"), vchPubKey);
-}
-
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
{
return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
@@ -258,13 +253,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{
std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
+ ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
}
else if (strType == "purpose")
{
std::string strAddress;
ssKey >> strAddress;
- ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
+ ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
}
else if (strType == "tx")
{
@@ -452,7 +447,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
else if (strType == "defaultkey")
{
- ssValue >> pwallet->vchDefaultKey;
+ // We don't want or need the default key, but if there is one set,
+ // we want to make sure that it is valid so that we can detect corruption
+ CPubKey vchPubKey;
+ ssValue >> vchPubKey;
+ if (!vchPubKey.IsValid()) {
+ strErr = "Error reading wallet database: Default Key corrupt";
+ return false;
+ }
}
else if (strType == "pool")
{
@@ -491,7 +493,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssKey >> strAddress;
ssKey >> strKey;
ssValue >> strValue;
- if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
+ if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue))
{
strErr = "Error reading wallet database: LoadDestData failed";
return false;
@@ -522,7 +524,6 @@ bool CWalletDB::IsKeyType(const std::string& strType)
DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{
- pwallet->vchDefaultKey = CPubKey();
CWalletScanState wss;
bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK;
@@ -565,7 +566,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{
// losing keys is considered a catastrophic error, anything else
// we assume the user can live with:
- if (IsKeyType(strType))
+ if (IsKeyType(strType) || strType == "defaultkey")
result = DB_CORRUPT;
else
{
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index d78f143ebd..4f8ea185d5 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -105,7 +105,7 @@ public:
{
SetNull();
}
- CKeyMetadata(int64_t nCreateTime_)
+ explicit CKeyMetadata(int64_t nCreateTime_)
{
SetNull();
nCreateTime = nCreateTime_;
@@ -162,7 +162,7 @@ private:
}
public:
- CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
+ explicit CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
batch(dbw, pszMode, _fFlushOnClose),
m_dbw(dbw)
{
@@ -191,8 +191,6 @@ public:
bool WriteOrderPosNext(int64_t nOrderPosNext);
- bool WriteDefaultKey(const CPubKey& vchPubKey);
-
bool ReadPool(int64_t nPool, CKeyPool& keypool);
bool WritePool(int64_t nPool, const CKeyPool& keypool);
bool ErasePool(int64_t nPool);
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index eec6f7bc64..cb92216fa4 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -13,7 +13,7 @@
class CBlockIndex;
class CZMQAbstractNotifier;
-class CZMQNotificationInterface : public CValidationInterface
+class CZMQNotificationInterface final : public CValidationInterface
{
public:
virtual ~CZMQNotificationInterface();
diff --git a/test/functional/README.md b/test/functional/README.md
index 44efda33d3..2558bd017d 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -24,8 +24,8 @@ don't have test cases for.
- Use a module-level docstring to describe what the test is testing, and how it
is testing it.
- When subclassing the BitcoinTestFramwork, place overrides for the
- `__init__()`, and `setup_xxxx()` methods at the top of the subclass, then
- locally-defined helper methods, then the `run_test()` method.
+ `set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of
+ the subclass, then locally-defined helper methods, then the `run_test()` method.
#### General test-writing advice
@@ -36,7 +36,7 @@ don't have test cases for.
- Avoid stop-starting the nodes multiple times during the test if possible. A
stop-start takes several seconds, so doing it several times blows up the
runtime of the test.
-- Set the `self.setup_clean_chain` variable in `__init__()` to control whether
+- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether
or not to use the cached data directories. The cached data directories
contain a 200-block pre-mined blockchain and wallets for four nodes. Each node
has 25 mature blocks (25x50=1250 BTC) in its wallet.
diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py
index c87c02492d..e8dbc86469 100755
--- a/test/functional/abandonconflict.py
+++ b/test/functional/abandonconflict.py
@@ -14,10 +14,8 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class AbandonConflictTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
self.extra_args = [["-minrelaytxfee=0.00001"], []]
def run_test(self):
@@ -74,7 +72,7 @@ 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
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
+ self.start_node(0, extra_args=["-minrelaytxfee=0.0001"])
# Verify txs no longer in either node's mempool
assert_equal(len(self.nodes[0].getrawmempool()), 0)
@@ -101,7 +99,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])
+ self.start_node(0, extra_args=["-minrelaytxfee=0.00001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
assert_equal(self.nodes[0].getbalance(), balance)
@@ -121,7 +119,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Remove using high relay fee again
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
+ self.start_node(0, extra_args=["-minrelaytxfee=0.0001"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
newbalance = self.nodes[0].getbalance()
assert_equal(newbalance, balance - Decimal("24.9996"))
diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py
index 9d17faac51..beaf8c7055 100755
--- a/test/functional/assumevalid.py
+++ b/test/functional/assumevalid.py
@@ -54,16 +54,16 @@ class BaseNode(NodeConnCB):
self.send_message(headers_message)
class AssumeValidTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
def setup_network(self):
+ self.add_nodes(3)
# Start node0. We don't start the other nodes yet since
# 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.start_node(0, self.options.tmpdir)]
+ self.start_node(0)
def send_blocks_until_disconnected(self, node):
"""Keep sending blocks to the node until we're disconnected."""
@@ -162,15 +162,13 @@ class AssumeValidTest(BitcoinTestFramework):
height += 1
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
- self.nodes.append(self.start_node(1, self.options.tmpdir,
- ["-assumevalid=" + hex(block102.sha256)]))
+ self.start_node(1, extra_args=["-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(self.start_node(2, self.options.tmpdir,
- ["-assumevalid=" + hex(block102.sha256)]))
+ self.start_node(2, extra_args=["-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/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py
index 7e5e4cf682..2cd6df6e37 100755
--- a/test/functional/bip65-cltv-p2p.py
+++ b/test/functional/bip65-cltv-p2p.py
@@ -60,9 +60,7 @@ def create_transaction(node, coinbase, to_address, amount):
return tx
class BIP65Test(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
self.setup_clean_chain = True
@@ -109,7 +107,7 @@ class BIP65Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- assert wait_until(lambda: "reject" in node0.last_message.keys())
+ wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock:
assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)')
@@ -138,7 +136,7 @@ class BIP65Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- assert wait_until (lambda: "reject" in node0.last_message.keys())
+ wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock:
assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
assert_equal(node0.last_message["reject"].data, block.sha256)
diff --git a/test/functional/bip68-112-113-p2p.py b/test/functional/bip68-112-113-p2p.py
index 5a322e8c0e..7e6a4f4408 100755
--- a/test/functional/bip68-112-113-p2p.py
+++ b/test/functional/bip68-112-113-p2p.py
@@ -92,9 +92,9 @@ def all_rlt_txs(txarray):
return txs
class BIP68_112_113Test(ComparisonTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
+ self.setup_clean_chain = True
self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4']]
def run_test(self):
diff --git a/test/functional/bip68-sequence.py b/test/functional/bip68-sequence.py
index 87a50692f6..3818287209 100755
--- a/test/functional/bip68-sequence.py
+++ b/test/functional/bip68-sequence.py
@@ -17,10 +17,8 @@ SEQUENCE_LOCKTIME_MASK = 0x0000ffff
NOT_FINAL_ERROR = "64: non-BIP68-final"
class BIP68Test(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
self.extra_args = [[], ["-acceptnonstdtxn=0"]]
def run_test(self):
@@ -387,7 +385,7 @@ class BIP68Test(BitcoinTestFramework):
tx = FromHex(CTransaction(), rawtxfund)
tx.nVersion = 2
tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"]
- tx_id = self.nodes[1].sendrawtransaction(tx_signed)
+ self.nodes[1].sendrawtransaction(tx_signed)
if __name__ == '__main__':
BIP68Test().main()
diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py
index f00232c9ff..904789301a 100755
--- a/test/functional/bip9-softforks.py
+++ b/test/functional/bip9-softforks.py
@@ -28,11 +28,10 @@ from test_framework.comptool import TestInstance, TestManager
from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP
class BIP9SoftForksTest(ComparisonTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-whitelist=127.0.0.1']]
+ self.setup_clean_chain = True
def run_test(self):
self.test = TestManager(self, self.options.tmpdir)
@@ -241,6 +240,7 @@ class BIP9SoftForksTest(ComparisonTestFramework):
# Restart all
self.test.clear_all_connections()
self.stop_nodes()
+ self.nodes = []
shutil.rmtree(self.options.tmpdir + "/node0")
self.setup_chain()
self.setup_network()
diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py
index 38a9009544..c620d3e155 100755
--- a/test/functional/bipdersig-p2p.py
+++ b/test/functional/bipdersig-p2p.py
@@ -48,9 +48,7 @@ def create_transaction(node, coinbase, to_address, amount):
return tx
class BIP66Test(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']]
self.setup_clean_chain = True
@@ -98,7 +96,7 @@ class BIP66Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- assert wait_until(lambda: "reject" in node0.last_message.keys())
+ wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock:
assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)')
@@ -128,7 +126,7 @@ class BIP66Test(BitcoinTestFramework):
node0.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- assert wait_until (lambda: "reject" in node0.last_message.keys())
+ wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
with mininode_lock:
# We can receive different reject messages depending on whether
# bitcoind is running with multiple script check threads. If script
diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py
new file mode 100755
index 0000000000..ffed5b0d33
--- /dev/null
+++ b/test/functional/bitcoin_cli.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test bitcoin-cli"""
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_process_error, get_auth_cookie
+
+class TestBitcoinCli(BitcoinTestFramework):
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def run_test(self):
+ """Main test logic"""
+
+ self.log.info("Compare responses from gewalletinfo RPC and `bitcoin-cli getwalletinfo`")
+ cli_response = self.nodes[0].cli.getwalletinfo()
+ rpc_response = self.nodes[0].getwalletinfo()
+ assert_equal(cli_response, rpc_response)
+
+ self.log.info("Compare responses from getblockchaininfo RPC and `bitcoin-cli getblockchaininfo`")
+ cli_response = self.nodes[0].cli.getblockchaininfo()
+ rpc_response = self.nodes[0].getblockchaininfo()
+ assert_equal(cli_response, rpc_response)
+
+ user, password = get_auth_cookie(self.nodes[0].datadir)
+
+ self.log.info("Test -stdinrpcpass option")
+ assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount())
+ assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input="foo").echo)
+
+ self.log.info("Test -stdin and -stdinrpcpass")
+ assert_equal(["foo", "bar"], self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input=password + "\nfoo\nbar").echo())
+ assert_raises_process_error(1, "incorrect rpcuser or rpcpassword", self.nodes[0].cli('-rpcuser=%s' % user, '-stdin', '-stdinrpcpass', input="foo").echo)
+
+if __name__ == '__main__':
+ TestBitcoinCli().main()
diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py
index 0812e1b0df..50be9262e4 100755
--- a/test/functional/blockchain.py
+++ b/test/functional/blockchain.py
@@ -21,7 +21,7 @@ from decimal import Decimal
import http.client
import subprocess
-from test_framework.test_framework import (BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT)
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises,
@@ -30,12 +30,8 @@ from test_framework.util import (
assert_is_hash_string,
)
-
class BlockchainTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = False
+ def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-stopatheight=207']]
@@ -145,8 +141,8 @@ class BlockchainTest(BitcoinTestFramework):
except (ConnectionError, http.client.BadStatusLine):
pass # The node already shut down before response
self.log.debug('Node should stop at this height...')
- self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
- self.nodes[0] = self.start_node(0, self.options.tmpdir)
+ self.nodes[0].wait_until_stopped()
+ self.start_node(0)
assert_equal(self.nodes[0].getblockcount(), 207)
diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py
index 9633ffdebb..dde87d5bd1 100755
--- a/test/functional/bumpfee.py
+++ b/test/functional/bumpfee.py
@@ -30,25 +30,21 @@ WALLET_PASSPHRASE_TIMEOUT = 3600
class BumpFeeTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
+ self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
+ for i in range(self.num_nodes)]
- def setup_network(self, split=False):
- extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
- for i in range(self.num_nodes)]
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
-
+ def run_test(self):
# Encrypt wallet for test_locked_wallet_fails test
self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE)
- self.nodes[1] = self.start_node(1, self.options.tmpdir, extra_args[1])
+ self.start_node(1)
self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
connect_nodes_bi(self.nodes, 0, 1)
self.sync_all()
- def run_test(self):
peer_node, rbf_node = self.nodes
rbf_node_address = rbf_node.getnewaddress()
@@ -167,7 +163,7 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
parent_id = spend_one_input(rbf_node, rbf_node_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"])
+ rbf_node.sendrawtransaction(tx["hex"])
assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py
index 39c4c0f47e..7d4d1a529b 100755
--- a/test/functional/create_cache.py
+++ b/test/functional/create_cache.py
@@ -12,13 +12,10 @@ tests are being run in parallel.
from test_framework.test_framework import BitcoinTestFramework
class CreateCache(BitcoinTestFramework):
+ # Test network and test nodes are not required:
- def __init__(self):
- super().__init__()
-
- # Test network and test nodes are not required:
+ def set_test_params(self):
self.num_nodes = 0
- self.nodes = []
def setup_network(self):
pass
diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py
index 8339305f5e..71424f641b 100755
--- a/test/functional/dbcrash.py
+++ b/test/functional/dbcrash.py
@@ -43,8 +43,7 @@ except AttributeError:
pass
class ChainstateWriteCrashTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 4
self.setup_clean_chain = False
@@ -64,7 +63,9 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]
def setup_network(self):
- self.setup_nodes()
+ # Need a bit of extra time for the nodes to start up for this test
+ self.add_nodes(self.num_nodes, timewait=90)
+ self.start_nodes()
# Leave them unconnected, we'll use submitblock directly in this test
def restart_node(self, node_index, expected_tip):
@@ -74,10 +75,10 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
after 60 seconds. Returns the utxo hash of the given node."""
time_start = time.time()
- while time.time() - time_start < 60:
+ while time.time() - time_start < 120:
try:
# Any of these RPC calls could throw due to node crash
- self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index])
+ self.start_node(node_index)
self.nodes[node_index].waitforblock(expected_tip)
utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2']
return utxo_hash
diff --git a/test/functional/decodescript.py b/test/functional/decodescript.py
index 21a9f1223f..6611da8831 100755
--- a/test/functional/decodescript.py
+++ b/test/functional/decodescript.py
@@ -10,9 +10,7 @@ from test_framework.mininode import *
from io import BytesIO
class DecodeScriptTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/disablewallet.py b/test/functional/disablewallet.py
index d344513414..c1d37963bc 100755
--- a/test/functional/disablewallet.py
+++ b/test/functional/disablewallet.py
@@ -11,11 +11,8 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-
class DisableWalletTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-disablewallet"]]
diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py
index 89b68aeb25..a6445b9b35 100755
--- a/test/functional/disconnect_ban.py
+++ b/test/functional/disconnect_ban.py
@@ -5,18 +5,17 @@
"""Test node disconnect and ban behavior"""
import time
-from test_framework.mininode import wait_until
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (assert_equal,
- assert_raises_jsonrpc,
- connect_nodes_bi)
+from test_framework.util import (
+ assert_equal,
+ assert_raises_jsonrpc,
+ connect_nodes_bi,
+ wait_until,
+)
class DisconnectBanTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
def run_test(self):
self.log.info("Test setban and listbanned RPCs")
@@ -24,7 +23,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("setban: successfully ban single IP address")
assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point
self.nodes[1].setban("127.0.0.1", "add")
- assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)
+ wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10)
assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point
assert_equal(len(self.nodes[1].listbanned()), 1)
@@ -66,8 +65,8 @@ class DisconnectBanTest(BitcoinTestFramework):
assert_equal(len(self.nodes[1].listbanned()), 3)
self.stop_node(1)
+ self.start_node(1)
- self.nodes[1] = self.start_node(1, self.options.tmpdir)
listAfterShutdown = self.nodes[1].listbanned()
assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
@@ -90,7 +89,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: successfully disconnect node by address")
address1 = self.nodes[0].getpeerinfo()[0]['addr']
self.nodes[0].disconnectnode(address=address1)
- assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
+ wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
self.log.info("disconnectnode: successfully reconnect node")
@@ -101,7 +100,7 @@ class DisconnectBanTest(BitcoinTestFramework):
self.log.info("disconnectnode: successfully disconnect node by node id")
id1 = self.nodes[0].getpeerinfo()[0]['id']
self.nodes[0].disconnectnode(nodeid=id1)
- assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
+ wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10)
assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]
if __name__ == '__main__':
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index 79940a4264..87d73ad14a 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -23,13 +23,13 @@ from test_framework.mininode import (
mininode_lock,
msg_block,
msg_getdata,
- wait_until,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes,
p2p_port,
+ wait_until,
)
# NodeConnCB is a class containing callbacks to be executed when a P2P
@@ -73,21 +73,19 @@ def custom_function():
class ExampleTest(BitcoinTestFramework):
# Each functional test is a subclass of the BitcoinTestFramework class.
- # Override the __init__(), add_options(), setup_chain(), setup_network()
+ # Override the set_test_params(), add_options(), setup_chain(), setup_network()
# and setup_nodes() methods to customize the test setup as required.
- def __init__(self):
- """Initialize the test
+ def set_test_params(self):
+ """Override test parameters for your individual test.
- Call super().__init__() first, and then override any test parameters
- for your individual test."""
- super().__init__()
+ This method must be overridden and num_nodes must be exlicitly set."""
self.setup_clean_chain = True
self.num_nodes = 3
# Use self.extra_args to change command-line arguments for the nodes
self.extra_args = [[], ["-logips"], []]
- # self.log.info("I've finished __init__") # Oops! Can't run self.log before run_test()
+ # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test()
# Use add_options() to add specific command-line options for your test.
# In practice this is not used very much, since the tests are mostly written
@@ -209,7 +207,7 @@ class ExampleTest(BitcoinTestFramework):
# wait_until() will loop until a predicate condition is met. Use it to test properties of the
# NodeConnCB objects.
- assert wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5)
+ wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5, lock=mininode_lock)
self.log.info("Check that each block was received only once")
# The network thread uses a global lock on data access to the NodeConn objects when sending and receiving
diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py
index 3bcf0a6795..afcad1f9cc 100755
--- a/test/functional/forknotify.py
+++ b/test/functional/forknotify.py
@@ -7,28 +7,18 @@ import os
import time
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
class ForkNotifyTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
def setup_network(self):
- self.nodes = []
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
with open(self.alert_filename, 'w', encoding='utf8'):
pass # Just open then close to create zero-length file
- self.nodes.append(self.start_node(0, self.options.tmpdir,
- ["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]))
- # Node1 mines block.version=211 blocks
- self.nodes.append(self.start_node(1, self.options.tmpdir,
- ["-blockversion=211"]))
- connect_nodes(self.nodes[1], 0)
-
- self.sync_all()
+ self.extra_args = [["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""],
+ ["-blockversion=211"]]
+ super().setup_network()
def run_test(self):
# Mine 51 up-version blocks
diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index f2f4efcf28..71e88009b6 100755
--- a/test/functional/fundrawtransaction.py
+++ b/test/functional/fundrawtransaction.py
@@ -4,7 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the fundrawtransaction RPC."""
-from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -14,13 +14,10 @@ def get_unspent(listunspent, amount):
return utx
raise AssertionError('Could not find unspent with amount={}'.format(amount))
-
class RawTransactionsTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
+ def set_test_params(self):
self.num_nodes = 4
+ self.setup_clean_chain = True
def setup_network(self, split=False):
self.setup_nodes()
@@ -312,7 +309,6 @@ class RawTransactionsTest(BitcoinTestFramework):
##############################################
# test a fundrawtransaction with invalid vin #
##############################################
- listunspent = self.nodes[2].listunspent()
inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin!
outputs = { self.nodes[0].getnewaddress() : 1.0}
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
@@ -449,11 +445,11 @@ class RawTransactionsTest(BitcoinTestFramework):
############################################################
# locked wallet test
self.stop_node(0)
+ self.nodes[1].node_encrypt_wallet("test")
self.stop_node(2)
self.stop_node(3)
- self.nodes[1].node_encrypt_wallet("test")
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir)
+ self.start_nodes()
# 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
for node in self.nodes:
diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py
index cca30e2688..89768bd2fb 100755
--- a/test/functional/getblocktemplate_longpoll.py
+++ b/test/functional/getblocktemplate_longpoll.py
@@ -23,10 +23,8 @@ class LongpollThread(threading.Thread):
self.node.getblocktemplate({'longpollid':self.longpollid})
class GetBlockTemplateLPTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
- self.num_nodes = 4
- self.setup_clean_chain = False
+ def set_test_params(self):
+ self.num_nodes = 2
def run_test(self):
self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.")
diff --git a/test/functional/getchaintips.py b/test/functional/getchaintips.py
index 15f96c565f..21b67bfc64 100755
--- a/test/functional/getchaintips.py
+++ b/test/functional/getchaintips.py
@@ -14,13 +14,10 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class GetChainTipsTest (BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 4
- self.setup_clean_chain = False
def run_test (self):
-
tips = self.nodes[0].getchaintips ()
assert_equal (len (tips), 1)
assert_equal (tips[0]['branchlen'], 0)
diff --git a/test/functional/httpbasics.py b/test/functional/httpbasics.py
index 4b32e8d9ca..c7682cb49d 100755
--- a/test/functional/httpbasics.py
+++ b/test/functional/httpbasics.py
@@ -11,10 +11,8 @@ import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 3
- self.setup_clean_chain = False
def setup_network(self):
self.setup_nodes()
diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py
index 4fc5078217..cb5b65c682 100755
--- a/test/functional/import-rescan.py
+++ b/test/functional/import-rescan.py
@@ -111,8 +111,7 @@ TIMESTAMP_WINDOW = 2 * 60 * 60
class ImportRescanTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2 + len(IMPORT_NODES)
def setup_network(self):
@@ -121,7 +120,8 @@ class ImportRescanTest(BitcoinTestFramework):
if import_node.prune:
extra_args[i] += ["-prune=1"]
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.add_nodes(self.num_nodes, extra_args)
+ self.start_nodes()
for i in range(1, self.num_nodes):
connect_nodes(self.nodes[i], 0)
@@ -161,7 +161,6 @@ class ImportRescanTest(BitcoinTestFramework):
variant.check()
# Create new transactions sending to each address.
- fee = self.nodes[0].getnetworkinfo()["relayfee"]
for i, variant in enumerate(IMPORT_VARIANTS):
variant.sent_amount = 10 - (2 * i + 1) / 8.0
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py
index e83e85de13..32f555c79b 100755
--- a/test/functional/importmulti.py
+++ b/test/functional/importmulti.py
@@ -7,8 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class ImportMultiTest (BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
@@ -21,16 +20,7 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- # keyword definition
- PRIV_KEY = 'privkey'
- PUB_KEY = 'pubkey'
- ADDRESS_KEY = 'address'
- SCRIPT_KEY = 'script'
-
-
node0_address1 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
- node0_address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
- node0_address3 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
#Check only one address
assert_equal(node0_address1['ismine'], True)
@@ -230,7 +220,6 @@ class ImportMultiTest (BitcoinTestFramework):
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- transaction = self.nodes[1].gettransaction(transactionid)
self.log.info("Should import a p2sh")
result = self.nodes[1].importmulti([{
@@ -258,7 +247,6 @@ class ImportMultiTest (BitcoinTestFramework):
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- transaction = self.nodes[1].gettransaction(transactionid)
self.log.info("Should import a p2sh with respective redeem script")
result = self.nodes[1].importmulti([{
@@ -286,7 +274,6 @@ class ImportMultiTest (BitcoinTestFramework):
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- transaction = self.nodes[1].gettransaction(transactionid)
self.log.info("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
@@ -314,7 +301,6 @@ class ImportMultiTest (BitcoinTestFramework):
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
- transaction = self.nodes[1].gettransaction(transactionid)
self.log.info("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
@@ -429,7 +415,7 @@ class ImportMultiTest (BitcoinTestFramework):
# restart nodes to check for proper serialization/deserialization of watch only address
self.stop_nodes()
- self.nodes = self.start_nodes(2, self.options.tmpdir)
+ self.start_nodes()
address_assert = self.nodes[1].validateaddress(watchonly_address)
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
diff --git a/test/functional/importprunedfunds.py b/test/functional/importprunedfunds.py
index 94753fe431..cb70010668 100755
--- a/test/functional/importprunedfunds.py
+++ b/test/functional/importprunedfunds.py
@@ -6,11 +6,8 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-
class ImportPrunedFundsTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
@@ -24,7 +21,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
address1 = self.nodes[0].getnewaddress()
# pubkey
address2 = self.nodes[0].getnewaddress()
- address2_pubkey = self.nodes[0].validateaddress(address2)['pubkey'] # Using pubkey
# privkey
address3 = self.nodes[0].getnewaddress()
address3_privkey = self.nodes[0].dumpprivkey(address3) # Using privkey
@@ -77,13 +73,13 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
#Import with affiliated address with no rescan
self.nodes[1].importaddress(address2, "add2", False)
- result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2)
+ self.nodes[1].importprunedfunds(rawtxn2, proof2)
balance2 = self.nodes[1].getbalance("add2", 0, True)
assert_equal(balance2, Decimal('0.05'))
#Import with private key with no rescan
self.nodes[1].importprivkey(address3_privkey, "add3", False)
- result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3)
+ self.nodes[1].importprunedfunds(rawtxn3, proof3)
balance3 = self.nodes[1].getbalance("add3", 0, False)
assert_equal(balance3, Decimal('0.025'))
balance3 = self.nodes[1].getbalance("*", 0, True)
diff --git a/test/functional/invalidateblock.py b/test/functional/invalidateblock.py
index c499d57b90..dd3daf1e07 100755
--- a/test/functional/invalidateblock.py
+++ b/test/functional/invalidateblock.py
@@ -8,9 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class InvalidateTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
diff --git a/test/functional/invalidblockrequest.py b/test/functional/invalidblockrequest.py
index eabc0db8df..9f44b44927 100755
--- a/test/functional/invalidblockrequest.py
+++ b/test/functional/invalidblockrequest.py
@@ -23,9 +23,9 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
+ self.setup_clean_chain = True
def run_test(self):
test = TestManager(self, self.options.tmpdir)
diff --git a/test/functional/invalidtxrequest.py b/test/functional/invalidtxrequest.py
index a9ac231f09..a22bd8f8cd 100755
--- a/test/functional/invalidtxrequest.py
+++ b/test/functional/invalidtxrequest.py
@@ -19,9 +19,9 @@ class InvalidTxRequestTest(ComparisonTestFramework):
''' Can either run this test as 1 node with expected answers, or two and compare them.
Change the "outcome" variable from each TestInstance object to only do the comparison. '''
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
+ self.setup_clean_chain = True
def run_test(self):
test = TestManager(self, self.options.tmpdir)
diff --git a/test/functional/keypool-topup.py b/test/functional/keypool-topup.py
index 0e0c0ea74b..b87433a9c5 100755
--- a/test/functional/keypool-topup.py
+++ b/test/functional/keypool-topup.py
@@ -20,8 +20,7 @@ from test_framework.util import (
)
class KeypoolRestoreTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=100', '-keypoolmin=20']]
@@ -35,7 +34,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
self.stop_node(1)
shutil.copyfile(self.tmpdir + "/node1/regtest/wallet.dat", self.tmpdir + "/wallet.bak")
- self.nodes[1] = self.start_node(1, self.tmpdir, self.extra_args[1])
+ self.start_node(1, self.extra_args[1])
connect_nodes_bi(self.nodes, 0, 1)
self.log.info("Generate keys for wallet")
@@ -61,7 +60,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
self.log.info("Verify keypool is restored and balance is correct")
- self.nodes[1] = self.start_node(1, self.tmpdir, self.extra_args[1])
+ self.start_node(1, self.extra_args[1])
connect_nodes_bi(self.nodes, 0, 1)
self.sync_all()
@@ -69,7 +68,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
assert_equal(self.nodes[1].listtransactions()[0]['category'], "receive")
# Check that we have marked all keys up to the used keypool key as used
- assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/0'/0'/111'")
+ assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
if __name__ == '__main__':
KeypoolRestoreTest().main()
diff --git a/test/functional/keypool.py b/test/functional/keypool.py
index 3e7bb0ee07..b823ca63bb 100755
--- a/test/functional/keypool.py
+++ b/test/functional/keypool.py
@@ -8,6 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class KeyPoolTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
def run_test(self):
nodes = self.nodes
@@ -19,7 +21,7 @@ class KeyPoolTest(BitcoinTestFramework):
# Encrypt wallet and wait to terminate
nodes[0].node_encrypt_wallet('test')
# Restart node 0
- nodes[0] = self.start_node(0, self.options.tmpdir)
+ self.start_node(0)
# Keep creating keys
addr = nodes[0].getnewaddress()
addr_data = nodes[0].validateaddress(addr)
@@ -78,10 +80,5 @@ class KeyPoolTest(BitcoinTestFramework):
assert_equal(wi['keypoolsize_hd_internal'], 100)
assert_equal(wi['keypoolsize'], 100)
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = False
- self.num_nodes = 1
-
if __name__ == '__main__':
KeyPoolTest().main()
diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py
index ce2d556ef0..6f428388ec 100755
--- a/test/functional/listsinceblock.py
+++ b/test/functional/listsinceblock.py
@@ -8,11 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class ListSinceBlockTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
+ def set_test_params(self):
self.num_nodes = 4
+ self.setup_clean_chain = True
def run_test(self):
self.nodes[2].generate(101)
diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py
index f75a8e29cc..e4522cc3b5 100755
--- a/test/functional/listtransactions.py
+++ b/test/functional/listtransactions.py
@@ -16,15 +16,9 @@ def txFromHex(hexstring):
return tx
class ListTransactionsTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
- self.num_nodes = 4
- self.setup_clean_chain = False
-
- def setup_nodes(self):
- #This test requires mocktime
+ def set_test_params(self):
+ self.num_nodes = 2
self.enable_mocktime()
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
# Simple send, 0 to 1:
diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py
index 66e5bd29e6..1f402798e7 100755
--- a/test/functional/maxuploadtarget.py
+++ b/test/functional/maxuploadtarget.py
@@ -31,8 +31,7 @@ class TestNode(NodeConnCB):
class MaxUploadTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-maxuploadtarget=800", "-blockmaxsize=999000"]]
@@ -147,7 +146,7 @@ class MaxUploadTest(BitcoinTestFramework):
#stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1
self.log.info("Restarting nodes with -whitelist=127.0.0.1")
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
+ self.start_node(0, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
#recreate/reconnect a test node
test_nodes = [TestNode()]
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index 2777291dd0..e24dc5a464 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -8,9 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class MempoolLimitTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]]
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index e225493816..2b09889661 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -12,10 +12,8 @@ MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
class MempoolPackagesTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]]
# Build a transaction that spends parent_txid:vout
@@ -213,7 +211,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
value = send_value
# Create tx1
- (tx1_id, tx1_value) = self.chain_transaction(self.nodes[0], tx0_id, 0, value, fee, 1)
+ tx1_id, _ = self.chain_transaction(self.nodes[0], tx0_id, 0, value, fee, 1)
# Create tx2-7
vout = 1
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index e0889fd5e9..149a01870d 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -28,21 +28,22 @@ Test is as follows:
- Restart node0 with -persistmempool. Verify that it has 5
transactions in its mempool. This tests that -persistmempool=0
does not overwrite a previously valid mempool stored on disk.
+ - Remove node0 mempool.dat and verify savemempool RPC recreates it
+ and verify that node1 can load it and has 5 transaction in its
+ mempool.
+ - Verify that savemempool throws when the RPC is called if
+ node1 can't write to disk.
"""
+import os
import time
-from test_framework.mininode import wait_until
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class MempoolPersistTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- # We need 3 nodes for this test. Node1 does not have a persistent mempool.
+ def set_test_params(self):
self.num_nodes = 3
- self.setup_clean_chain = False
self.extra_args = [[], ["-persistmempool=0"], []]
def run_test(self):
@@ -64,27 +65,46 @@ class MempoolPersistTest(BitcoinTestFramework):
self.log.debug("Stop-start node0 and node1. Verify that node0 has the transactions in its mempool and node1 does not.")
self.stop_nodes()
- self.nodes = []
- self.nodes.append(self.start_node(0, self.options.tmpdir))
- self.nodes.append(self.start_node(1, self.options.tmpdir))
+ self.start_node(0)
+ self.start_node(1)
# Give bitcoind a second to reload the mempool
time.sleep(1)
- assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
+ wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
assert_equal(len(self.nodes[1].getrawmempool()), 0)
self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
self.stop_nodes()
- self.nodes = []
- self.nodes.append(self.start_node(0, self.options.tmpdir, ["-persistmempool=0"]))
+ self.start_node(0, extra_args=["-persistmempool=0"])
# Give bitcoind a second to reload the mempool
time.sleep(1)
assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.")
self.stop_nodes()
- self.nodes = []
- self.nodes.append(self.start_node(0, self.options.tmpdir))
- assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
+ self.start_node(0)
+ wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
+
+ mempooldat0 = os.path.join(self.options.tmpdir, 'node0', 'regtest', 'mempool.dat')
+ mempooldat1 = os.path.join(self.options.tmpdir, 'node1', 'regtest', 'mempool.dat')
+ self.log.debug("Remove the mempool.dat file. Verify that savemempool to disk via RPC re-creates it")
+ os.remove(mempooldat0)
+ self.nodes[0].savemempool()
+ assert os.path.isfile(mempooldat0)
+
+ self.log.debug("Stop nodes, make node1 use mempool.dat from node0. Verify it has 5 transactions")
+ os.rename(mempooldat0, mempooldat1)
+ self.stop_nodes()
+ self.start_node(1, extra_args=[])
+ wait_until(lambda: len(self.nodes[1].getrawmempool()) == 5)
+
+ self.log.debug("Prevent bitcoind from writing mempool.dat to disk. Verify that `savemempool` fails")
+ # to test the exception we are setting bad permissions on a tmp file called mempool.dat.new
+ # which is an implementation detail that could change and break this test
+ mempooldotnew1 = mempooldat1 + '.new'
+ with os.fdopen(os.open(mempooldotnew1, os.O_CREAT, 0o000), 'w'):
+ pass
+ assert_raises_jsonrpc(-1, "Unable to dump mempool to disk", self.nodes[1].savemempool)
+ os.remove(mempooldotnew1)
if __name__ == '__main__':
MempoolPersistTest().main()
diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py
index 937bf4bab5..7dfddd3230 100755
--- a/test/functional/mempool_reorg.py
+++ b/test/functional/mempool_reorg.py
@@ -13,10 +13,8 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
self.extra_args = [["-checkmempool"]] * 2
alert_filename = None # Set by setup_network
diff --git a/test/functional/mempool_resurrect_test.py b/test/functional/mempool_resurrect_test.py
index a2f6228df9..1263c9306b 100755
--- a/test/functional/mempool_resurrect_test.py
+++ b/test/functional/mempool_resurrect_test.py
@@ -9,12 +9,8 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolCoinbaseTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = False
- # Just need one node for this test
self.extra_args = [["-checkmempool"]]
def run_test(self):
diff --git a/test/functional/mempool_spendcoinbase.py b/test/functional/mempool_spendcoinbase.py
index 277ea45ad5..58ccd3e373 100755
--- a/test/functional/mempool_spendcoinbase.py
+++ b/test/functional/mempool_spendcoinbase.py
@@ -17,11 +17,8 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class MempoolSpendCoinbaseTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = False
self.extra_args = [["-checkmempool"]]
def run_test(self):
diff --git a/test/functional/merkle_blocks.py b/test/functional/merkle_blocks.py
index bcc65c8408..a58334b2a5 100755
--- a/test/functional/merkle_blocks.py
+++ b/test/functional/merkle_blocks.py
@@ -8,11 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class MerkleBlockTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
+ def set_test_params(self):
self.num_nodes = 4
+ self.setup_clean_chain = True
# Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing
self.extra_args = [[], [], [], ["-txindex"]]
diff --git a/test/functional/minchainwork.py b/test/functional/minchainwork.py
new file mode 100755
index 0000000000..c7579d2548
--- /dev/null
+++ b/test/functional/minchainwork.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test logic for setting nMinimumChainWork on command line.
+
+Nodes don't consider themselves out of "initial block download" until
+their active chain has more work than nMinimumChainWork.
+
+Nodes don't download blocks from a peer unless the peer's best known block
+has more work than nMinimumChainWork.
+
+While in initial block download, nodes won't relay blocks to their peers, so
+test that this parameter functions as intended by verifying that block relay
+only succeeds past a given node once its nMinimumChainWork has been exceeded.
+"""
+
+import time
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import sync_blocks, connect_nodes, assert_equal
+
+# 2 hashes required per regtest block (with no difficulty adjustment)
+REGTEST_WORK_PER_BLOCK = 2
+
+class MinimumChainWorkTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+ self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]]
+ self.node_min_work = [0, 101, 101]
+
+ def setup_network(self):
+ # This test relies on the chain setup being:
+ # node0 <- node1 <- node2
+ # Before leaving IBD, nodes prefer to download blocks from outbound
+ # peers, so ensure that we're mining on an outbound peer and testing
+ # block relay to inbound peers.
+ self.setup_nodes()
+ for i in range(self.num_nodes-1):
+ connect_nodes(self.nodes[i+1], i)
+
+ def run_test(self):
+ # Start building a chain on node0. node2 shouldn't be able to sync until node1's
+ # minchainwork is exceeded
+ starting_chain_work = REGTEST_WORK_PER_BLOCK # Genesis block's work
+ self.log.info("Testing relay across node %d (minChainWork = %d)", 1, self.node_min_work[1])
+
+ starting_blockcount = self.nodes[2].getblockcount()
+
+ num_blocks_to_generate = int((self.node_min_work[1] - starting_chain_work) / REGTEST_WORK_PER_BLOCK)
+ self.log.info("Generating %d blocks on node0", num_blocks_to_generate)
+ hashes = self.nodes[0].generate(num_blocks_to_generate)
+
+ self.log.info("Node0 current chain work: %s", self.nodes[0].getblockheader(hashes[-1])['chainwork'])
+
+ # Sleep a few seconds and verify that node2 didn't get any new blocks
+ # or headers. We sleep, rather than sync_blocks(node0, node1) because
+ # it's reasonable either way for node1 to get the blocks, or not get
+ # them (since they're below node1's minchainwork).
+ time.sleep(3)
+
+ self.log.info("Verifying node 2 has no more blocks than before")
+ self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes])
+ # Node2 shouldn't have any new headers yet, because node1 should not
+ # have relayed anything.
+ assert_equal(len(self.nodes[2].getchaintips()), 1)
+ assert_equal(self.nodes[2].getchaintips()[0]['height'], 0)
+
+ assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash()
+ assert_equal(self.nodes[2].getblockcount(), starting_blockcount)
+
+ self.log.info("Generating one more block")
+ self.nodes[0].generate(1)
+
+ self.log.info("Verifying nodes are all synced")
+ self.sync_all()
+ self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes])
+
+if __name__ == '__main__':
+ MinimumChainWorkTest().main()
diff --git a/test/functional/mining.py b/test/functional/mining.py
index dbd4e29eca..93f9838896 100755
--- a/test/functional/mining.py
+++ b/test/functional/mining.py
@@ -4,16 +4,18 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test mining RPCs
+- getmininginfo
- getblocktemplate proposal mode
- submitblock"""
-from binascii import b2a_hex
import copy
+from binascii import b2a_hex
+from decimal import Decimal
from test_framework.blocktools import create_coinbase
-from test_framework.test_framework import BitcoinTestFramework
from test_framework.mininode import CBlock
-from test_framework.util import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal, assert_raises_jsonrpc
def b2x(b):
return b2a_hex(b).decode('ascii')
@@ -25,14 +27,24 @@ def assert_template(node, block, expect, rehash=True):
assert_equal(rsp, expect)
class MiningTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = False
def run_test(self):
node = self.nodes[0]
+
+ self.log.info('getmininginfo')
+ mining_info = node.getmininginfo()
+ assert_equal(mining_info['blocks'], 200)
+ assert_equal(mining_info['chain'], 'regtest')
+ assert_equal(mining_info['currentblocksize'], 0)
+ assert_equal(mining_info['currentblocktx'], 0)
+ assert_equal(mining_info['currentblockweight'], 0)
+ assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10'))
+ assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334'))
+ assert_equal(mining_info['pooledtx'], 0)
+
# Mine a block to leave initial block download
node.generate(1)
tmpl = node.getblocktemplate()
diff --git a/test/functional/multi_rpc.py b/test/functional/multi_rpc.py
index a30e15ace9..a2b346f274 100755
--- a/test/functional/multi_rpc.py
+++ b/test/functional/multi_rpc.py
@@ -12,10 +12,7 @@ import http.client
import urllib.parse
class HTTPBasicsTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = False
+ def set_test_params(self):
self.num_nodes = 2
def setup_chain(self):
diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py
index fc6e8e325f..e5453e9aad 100755
--- a/test/functional/multiwallet.py
+++ b/test/functional/multiwallet.py
@@ -12,9 +12,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_jsonrpc
class MultiWalletTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']]
@@ -23,17 +21,17 @@ class MultiWalletTest(BitcoinTestFramework):
self.stop_node(0)
# should not initialize if there are duplicate wallets
- self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.')
+ self.assert_start_raises_init_error(0, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.')
# should not initialize if wallet file is a directory
os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11'))
- self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.')
+ self.assert_start_raises_init_error(0, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.')
# should not initialize if wallet file is a symlink
os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12'))
- self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.')
+ self.assert_start_raises_init_error(0, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.')
- self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0])
+ self.start_node(0, self.extra_args[0])
w1 = self.nodes[0].get_wallet_rpc("w1")
w2 = self.nodes[0].get_wallet_rpc("w2")
diff --git a/test/functional/net.py b/test/functional/net.py
index 1e63d38035..830aeb45b4 100755
--- a/test/functional/net.py
+++ b/test/functional/net.py
@@ -17,10 +17,8 @@ from test_framework.util import (
p2p_port,
)
-
class NetTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py
index 9717add272..60d0d876df 100755
--- a/test/functional/nulldummy.py
+++ b/test/functional/nulldummy.py
@@ -37,8 +37,7 @@ def trueDummy(tx):
class NULLDUMMYTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness']]
diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py
index 322cb767db..293bc05539 100755
--- a/test/functional/p2p-acceptblock.py
+++ b/test/functional/p2p-acceptblock.py
@@ -60,8 +60,7 @@ class AcceptBlockTest(BitcoinTestFramework):
default=os.getenv("BITCOIND", "bitcoind"),
help="bitcoind binary to test")
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [[], ["-whitelist=127.0.0.1"]]
diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py
index ff76e49fba..94513d3f43 100755
--- a/test/functional/p2p-compactblocks.py
+++ b/test/functional/p2p-compactblocks.py
@@ -70,7 +70,7 @@ class TestNode(NodeConnCB):
def request_headers_and_sync(self, locator, hashstop=0):
self.clear_block_announcement()
self.get_headers(locator, hashstop)
- assert wait_until(self.received_block_announcement, timeout=30)
+ wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock)
self.clear_block_announcement()
# Block until a block announcement for a particular block hash is
@@ -78,7 +78,7 @@ class TestNode(NodeConnCB):
def wait_for_block_announcement(self, block_hash, timeout=30):
def received_hash():
return (block_hash in self.announced_blockhashes)
- return wait_until(received_hash, timeout=timeout)
+ wait_until(received_hash, timeout=timeout, lock=mininode_lock)
def send_await_disconnect(self, message, timeout=30):
"""Sends a message to the node and wait for disconnect.
@@ -86,15 +86,10 @@ class TestNode(NodeConnCB):
This is used when we want to send a message into the node that we expect
will get us disconnected, eg an invalid block."""
self.send_message(message)
- success = wait_until(lambda: not self.connected, timeout=timeout)
- if not success:
- logger.error("send_await_disconnect failed!")
- raise AssertionError("send_await_disconnect failed!")
- return success
+ wait_until(lambda: not self.connected, timeout=timeout, lock=mininode_lock)
class CompactBlocksTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
# Node0 = pre-segwit, node1 = segwit-aware
self.num_nodes = 2
@@ -150,9 +145,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Make sure we get a SENDCMPCT message from our peer
def received_sendcmpct():
return (len(test_node.last_sendcmpct) > 0)
- got_message = wait_until(received_sendcmpct, timeout=30)
- assert(received_sendcmpct())
- assert(got_message)
+ wait_until(received_sendcmpct, timeout=30, lock=mininode_lock)
with mininode_lock:
# Check that the first version received is the preferred one
assert_equal(test_node.last_sendcmpct[0].version, preferred_version)
@@ -167,7 +160,6 @@ class CompactBlocksTest(BitcoinTestFramework):
block_hash = int(node.generate(1)[0], 16)
peer.wait_for_block_announcement(block_hash, timeout=30)
assert(peer.block_announced)
- assert(got_message)
with mininode_lock:
assert predicate(peer), (
@@ -282,7 +274,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Wait until we've seen the block announcement for the resulting tip
tip = int(node.getbestblockhash(), 16)
- assert(test_node.wait_for_block_announcement(tip))
+ test_node.wait_for_block_announcement(tip)
# Make sure we will receive a fast-announce compact block
self.request_cb_announcements(test_node, node, version)
@@ -293,12 +285,12 @@ class CompactBlocksTest(BitcoinTestFramework):
# Store the raw block in our internal format.
block = FromHex(CBlock(), node.getblock("%02x" % block_hash, False))
- [tx.calc_sha256() for tx in block.vtx]
+ for tx in block.vtx:
+ tx.calc_sha256()
block.rehash()
# Wait until the block was announced (via compact blocks)
- wait_until(test_node.received_block_announcement, timeout=30)
- assert(test_node.received_block_announcement())
+ wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
# Now fetch and check the compact block
header_and_shortids = None
@@ -314,8 +306,7 @@ class CompactBlocksTest(BitcoinTestFramework):
inv = CInv(4, block_hash) # 4 == "CompactBlock"
test_node.send_message(msg_getdata([inv]))
- wait_until(test_node.received_block_announcement, timeout=30)
- assert(test_node.received_block_announcement())
+ wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
# Now fetch and check the compact block
header_and_shortids = None
@@ -386,13 +377,11 @@ class CompactBlocksTest(BitcoinTestFramework):
if announce == "inv":
test_node.send_message(msg_inv([CInv(2, block.sha256)]))
- success = wait_until(lambda: "getheaders" in test_node.last_message, timeout=30)
- assert(success)
+ wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock)
test_node.send_header_for_blocks([block])
else:
test_node.send_header_for_blocks([block])
- success = wait_until(lambda: "getdata" in test_node.last_message, timeout=30)
- assert(success)
+ wait_until(lambda: "getdata" in test_node.last_message, timeout=30, lock=mininode_lock)
assert_equal(len(test_node.last_message["getdata"].inv), 1)
assert_equal(test_node.last_message["getdata"].inv[0].type, 4)
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
@@ -571,8 +560,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
# We should receive a getdata request
- success = wait_until(lambda: "getdata" in test_node.last_message, timeout=10)
- assert(success)
+ wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock)
assert_equal(len(test_node.last_message["getdata"].inv), 1)
assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG)
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
@@ -599,8 +587,7 @@ class CompactBlocksTest(BitcoinTestFramework):
num_to_request = random.randint(1, len(block.vtx))
msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
test_node.send_message(msg)
- success = wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10)
- assert(success)
+ wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10, lock=mininode_lock)
[tx.calc_sha256() for tx in block.vtx]
with mininode_lock:
@@ -639,22 +626,20 @@ class CompactBlocksTest(BitcoinTestFramework):
for i in range(MAX_CMPCTBLOCK_DEPTH + 1):
test_node.clear_block_announcement()
new_blocks.append(node.generate(1)[0])
- wait_until(test_node.received_block_announcement, timeout=30)
+ wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement()
test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
- success = wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)
- assert(success)
+ wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement()
node.generate(1)
- wait_until(test_node.received_block_announcement, timeout=30)
+ wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock)
test_node.clear_block_announcement()
with mininode_lock:
test_node.last_message.pop("block", None)
test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))]))
- success = wait_until(lambda: "block" in test_node.last_message, timeout=30)
- assert(success)
+ wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock)
with mininode_lock:
test_node.last_message["block"].block.calc_sha256()
assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16))
@@ -705,7 +690,7 @@ class CompactBlocksTest(BitcoinTestFramework):
node.submitblock(ToHex(block))
for l in listeners:
- wait_until(lambda: l.received_block_announcement(), timeout=30)
+ wait_until(lambda: l.received_block_announcement(), timeout=30, lock=mininode_lock)
with mininode_lock:
for l in listeners:
assert "cmpctblock" in l.last_message
diff --git a/test/functional/p2p-feefilter.py b/test/functional/p2p-feefilter.py
index dbccb633a5..8c92365ced 100755
--- a/test/functional/p2p-feefilter.py
+++ b/test/functional/p2p-feefilter.py
@@ -37,11 +37,8 @@ class TestNode(NodeConnCB):
self.txinvs = []
class FeeFilterTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
- self.setup_clean_chain = False
def run_test(self):
node1 = self.nodes[1]
diff --git a/test/functional/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py
index e7fe7372c8..1d969fc7c1 100755
--- a/test/functional/p2p-fullblocktest.py
+++ b/test/functional/p2p-fullblocktest.py
@@ -49,12 +49,11 @@ class CBrokenBlock(CBlock):
return r
class FullBlockTest(ComparisonTestFramework):
-
# Can either run this test as 1 node with expected answers, or two and compare them.
# Change the "outcome" variable from each TestInstance object to only do the comparison.
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
+ self.setup_clean_chain = True
self.block_heights = {}
self.coinbase_key = CECKey()
self.coinbase_key.set_secretbytes(b"horsebattery")
@@ -397,7 +396,7 @@ class FullBlockTest(ComparisonTestFramework):
yield rejected(RejectResult(16, b'bad-cb-length'))
# Extend the b26 chain to make sure bitcoind isn't accepting b26
- b27 = block(27, spend=out[7])
+ block(27, spend=out[7])
yield rejected(False)
# Now try a too-large-coinbase script
@@ -409,7 +408,7 @@ class FullBlockTest(ComparisonTestFramework):
yield rejected(RejectResult(16, b'bad-cb-length'))
# Extend the b28 chain to make sure bitcoind isn't accepting b28
- b29 = block(29, spend=out[7])
+ block(29, spend=out[7])
yield rejected(False)
# b30 has a max-sized coinbase scriptSig.
@@ -581,7 +580,7 @@ class FullBlockTest(ComparisonTestFramework):
# same as b40, but one less sigop
tip(39)
- b41 = block(41, spend=None)
+ block(41, spend=None)
update_block(41, b40.vtx[1:-1])
b41_sigops_to_fill = b40_sigops_to_fill - 1
tx = CTransaction()
@@ -927,7 +926,7 @@ class FullBlockTest(ComparisonTestFramework):
# -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
#
tip(64)
- b65 = block(65)
+ block(65)
tx1 = create_and_sign_tx(out[19].tx, out[19].n, out[19].tx.vout[0].nValue)
tx2 = create_and_sign_tx(tx1, 0, 0)
update_block(65, [tx1, tx2])
@@ -939,7 +938,7 @@ class FullBlockTest(ComparisonTestFramework):
# -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19)
# \-> b66 (20)
tip(65)
- b66 = block(66)
+ block(66)
tx1 = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue)
tx2 = create_and_sign_tx(tx1, 0, 1)
update_block(66, [tx2, tx1])
@@ -952,7 +951,7 @@ class FullBlockTest(ComparisonTestFramework):
#
#
tip(65)
- b67 = block(67)
+ block(67)
tx1 = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue)
tx2 = create_and_sign_tx(tx1, 0, 1)
tx3 = create_and_sign_tx(tx1, 0, 2)
@@ -972,7 +971,7 @@ class FullBlockTest(ComparisonTestFramework):
# this succeeds
#
tip(65)
- b68 = block(68, additional_coinbase_value=10)
+ block(68, additional_coinbase_value=10)
tx = create_and_sign_tx(out[20].tx, out[20].n, out[20].tx.vout[0].nValue-9)
update_block(68, [tx])
yield rejected(RejectResult(16, b'bad-cb-amount'))
@@ -1175,7 +1174,7 @@ class FullBlockTest(ComparisonTestFramework):
#
# -> b81 (26) -> b82 (27) -> b83 (28)
#
- b83 = block(83)
+ block(83)
op_codes = [OP_IF, OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF]
script = CScript(op_codes)
tx1 = create_and_sign_tx(out[28].tx, out[28].n, out[28].tx.vout[0].nValue, script)
@@ -1195,7 +1194,7 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b85 (29) -> b86 (30) \-> b89a (32)
#
#
- b84 = block(84)
+ block(84)
tx1 = create_tx(out[29].tx, out[29].n, 0, CScript([OP_RETURN]))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
tx1.vout.append(CTxOut(0, CScript([OP_TRUE])))
diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py
index 5611c876ae..f27086c97e 100755
--- a/test/functional/p2p-leaktests.py
+++ b/test/functional/p2p-leaktests.py
@@ -92,8 +92,7 @@ class CNodeNoVerackIdle(CLazyNode):
conn.send_message(msg_getaddr())
class P2PLeakTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
self.extra_args = [['-banscore='+str(banscore)]]
@@ -119,11 +118,11 @@ class P2PLeakTest(BitcoinTestFramework):
NetworkThread().start() # Start up network handling in another thread
- assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10)
- assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10)
- assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10)
- assert wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10)
- assert wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10)
+ wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)
+ wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)
+ wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
+ wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10, lock=mininode_lock)
+ wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10, lock=mininode_lock)
# Mine a block and make sure that it's not sent to the connected nodes
self.nodes[0].generate(1)
@@ -158,8 +157,8 @@ class P2PLeakTest(BitcoinTestFramework):
allowed_service_bit5_node.add_connection(connections[5])
allowed_service_bit7_node.add_connection(connections[6])
- assert wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10)
- assert wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10)
+ wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10, lock=mininode_lock)
+ wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10, lock=mininode_lock)
if __name__ == '__main__':
P2PLeakTest().main()
diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py
index 34ef249eea..40fcde2605 100755
--- a/test/functional/p2p-mempool.py
+++ b/test/functional/p2p-mempool.py
@@ -13,9 +13,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class P2PMempoolTests(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [["-peerbloomfilters=0"]]
diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py
index 63dfbb8ae6..943bc2c6d2 100755
--- a/test/functional/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -17,7 +17,6 @@ from binascii import hexlify
# The versionbit bit used to signal activation of SegWit
VB_WITNESS_BIT = 1
VB_PERIOD = 144
-VB_ACTIVATION_THRESHOLD = 108
VB_TOP_BITS = 0x20000000
MAX_SIGOP_COST = 80000
@@ -33,8 +32,8 @@ def get_virtual_size(witness_block):
return vsize
class TestNode(NodeConnCB):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
+ self.num_nodes = 3
self.getdataset = set()
def on_getdata(self, conn, message):
@@ -109,9 +108,7 @@ def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key):
class SegWitTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
self.extra_args = [["-whitelist=127.0.0.1"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]]
@@ -1496,7 +1493,7 @@ class SegWitTest(BitcoinTestFramework):
# Restart with the new binary
self.stop_node(node_id)
- self.nodes[node_id] = self.start_node(node_id, self.options.tmpdir)
+ self.start_node(node_id, extra_args=[])
connect_nodes(self.nodes[0], node_id)
sync_blocks(self.nodes)
diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py
index c3b29c215b..51d4769efc 100755
--- a/test/functional/p2p-timeouts.py
+++ b/test/functional/p2p-timeouts.py
@@ -33,8 +33,7 @@ class TestNode(NodeConnCB):
pass
class TimeoutsTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py
index df7e8ce5c1..0848fcde64 100755
--- a/test/functional/p2p-versionbits-warning.py
+++ b/test/functional/p2p-versionbits-warning.py
@@ -28,8 +28,7 @@ class TestNode(NodeConnCB):
pass
class VersionBitsWarningTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -88,7 +87,6 @@ class VersionBitsWarningTest(BitcoinTestFramework):
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1)
# Check that we're not getting any versionbit-related errors in
# get*info()
- assert(not VB_PATTERN.match(self.nodes[0].getinfo()["errors"]))
assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["errors"]))
assert(not VB_PATTERN.match(self.nodes[0].getnetworkinfo()["warnings"]))
@@ -100,7 +98,6 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# have gotten a different alert due to more than 51/100 blocks
# being of unexpected version.
# Check that get*info() shows some kind of error.
- assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getinfo()["errors"])
assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["errors"])
assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getnetworkinfo()["warnings"])
@@ -112,18 +109,17 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# Empty out the alert file
with open(self.alert_filename, 'w', encoding='utf8') as _:
pass
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
+ self.start_nodes()
# Connecting one block should be enough to generate an error.
self.nodes[0].generate(1)
- assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getinfo()["errors"])
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"])
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"])
self.stop_nodes()
self.test_versionbits_in_alert_file()
# Test framework expects the node to still be running...
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
+ self.start_nodes()
if __name__ == '__main__':
VersionBitsWarningTest().main()
diff --git a/test/functional/preciousblock.py b/test/functional/preciousblock.py
index 04b41e76ba..1466f901c0 100755
--- a/test/functional/preciousblock.py
+++ b/test/functional/preciousblock.py
@@ -35,8 +35,7 @@ def node_sync_via_rpc(nodes):
unidirectional_node_sync_via_rpc(node_src, node_dest)
class PreciousTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
@@ -47,16 +46,16 @@ class PreciousTest(BitcoinTestFramework):
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)
+ hashZ = self.nodes[1].generate(2)[-1]
assert_equal(self.nodes[1].getblockcount(), 2)
node_sync_via_rpc(self.nodes[0:3])
assert_equal(self.nodes[0].getbestblockhash(), hashZ)
self.log.info("Mine blocks A-B-C on Node 0")
- (hashA, hashB, hashC) = self.nodes[0].generate(3)
+ hashC = self.nodes[0].generate(3)[-1]
assert_equal(self.nodes[0].getblockcount(), 5)
self.log.info("Mine competing blocks E-F-G on Node 1")
- (hashE, hashF, hashG) = self.nodes[1].generate(3)
+ hashG = self.nodes[1].generate(3)[-1]
assert_equal(self.nodes[1].getblockcount(), 5)
assert(hashC != hashG)
self.log.info("Connect nodes and check no reorg occurs")
diff --git a/test/functional/prioritise_transaction.py b/test/functional/prioritise_transaction.py
index 4fc03d2547..7ad368acd4 100755
--- a/test/functional/prioritise_transaction.py
+++ b/test/functional/prioritise_transaction.py
@@ -9,9 +9,7 @@ from test_framework.util import *
from test_framework.mininode import COIN, MAX_BLOCK_BASE_SIZE
class PrioritiseTransactionTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [["-printpriority=1"], ["-printpriority=1"]]
diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py
index ae6f843ddc..81b99d1bf4 100755
--- a/test/functional/proxy_test.py
+++ b/test/functional/proxy_test.py
@@ -41,12 +41,9 @@ from test_framework.netutil import test_ipv6_local
RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports
-
class ProxyTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 4
- self.setup_clean_chain = False
def setup_nodes(self):
self.have_ipv6 = test_ipv6_local()
@@ -89,7 +86,8 @@ class ProxyTest(BitcoinTestFramework):
]
if self.have_ipv6:
args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion']
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args)
+ self.add_nodes(self.num_nodes, extra_args=args)
+ self.start_nodes()
def node_test(self, node, proxies, auth, test_onion=True):
rv = []
diff --git a/test/functional/pruning.py b/test/functional/pruning.py
index 3e00a34ac4..f53fe82881 100755
--- a/test/functional/pruning.py
+++ b/test/functional/pruning.py
@@ -26,9 +26,7 @@ def calc_usage(blockdir):
return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.)
class PruneTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 6
@@ -56,6 +54,10 @@ class PruneTest(BitcoinTestFramework):
connect_nodes(self.nodes[0], 4)
sync_blocks(self.nodes[0:5])
+ def setup_nodes(self):
+ self.add_nodes(self.num_nodes, self.extra_args, timewait=900)
+ self.start_nodes()
+
def create_big_chain(self):
# Start by creating some coinbases we can spend later
self.nodes[1].generate(200)
@@ -98,7 +100,7 @@ class PruneTest(BitcoinTestFramework):
# 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]=self.start_node(0, self.options.tmpdir, self.full_node_default_args, timewait=900)
+ self.start_node(0, extra_args=self.full_node_default_args)
# Mine 24 blocks in node 1
for i in range(24):
if j == 0:
@@ -126,7 +128,7 @@ 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] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"])
height = self.nodes[1].getblockcount()
self.log.info("Current block height: %d" % height)
@@ -149,7 +151,7 @@ class PruneTest(BitcoinTestFramework):
# Reboot node1 to clear those giant tx's from mempool
self.stop_node(1)
- self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900)
+ self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"])
self.log.info("Generating new longer chain of 300 more blocks")
self.nodes[1].generate(300)
@@ -227,13 +229,15 @@ 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] = self.start_node(node_number, self.options.tmpdir, timewait=900)
+ self.start_node(node_number)
+ node = self.nodes[node_number]
assert_equal(node.getblockcount(), 995)
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] = self.start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900)
+ self.stop_node(node_number)
+ self.start_node(node_number, extra_args=["-prune=1"])
+ node = self.nodes[node_number]
assert_equal(node.getblockcount(), 995)
def height(index):
@@ -307,7 +311,7 @@ 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] = self.start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900)
+ self.start_node(node_number, extra_args=["-prune=550"])
self.log.info("Success")
@@ -315,7 +319,7 @@ class PruneTest(BitcoinTestFramework):
# check that the pruning node's wallet is still in good shape
self.log.info("Stop and start pruning node to trigger wallet rescan")
self.stop_node(2)
- self.nodes[2] = self.start_node(2, self.options.tmpdir, ["-prune=550"])
+ self.start_node(2, extra_args=["-prune=550"])
self.log.info("Success")
# check that wallet loads successfully when restarting a pruned node after IBD.
@@ -325,7 +329,7 @@ class PruneTest(BitcoinTestFramework):
nds = [self.nodes[0], self.nodes[5]]
sync_blocks(nds, wait=5, timeout=300)
self.stop_node(5) #stop and start to trigger rescan
- self.nodes[5] = self.start_node(5, self.options.tmpdir, ["-prune=550"])
+ self.start_node(5, extra_args=["-prune=550"])
self.log.info("Success")
def run_test(self):
diff --git a/test/functional/rawtransactions.py b/test/functional/rawtransactions.py
index b6b90d6781..d7255daa0a 100755
--- a/test/functional/rawtransactions.py
+++ b/test/functional/rawtransactions.py
@@ -17,9 +17,7 @@ from test_framework.util import *
# Create one-input, one-output, no-fee transaction:
class RawTransactionsTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
@@ -63,7 +61,6 @@ class RawTransactionsTest(BitcoinTestFramework):
addr2Obj = self.nodes[2].validateaddress(addr2)
mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])
- mSigObjValid = self.nodes[2].validateaddress(mSigObj)
#use balance deltas instead of absolute values
bal = self.nodes[2].getbalance()
@@ -87,7 +84,6 @@ class RawTransactionsTest(BitcoinTestFramework):
addr3Obj = self.nodes[2].validateaddress(addr3)
mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']])
- mSigObjValid = self.nodes[2].validateaddress(mSigObj)
txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
decTx = self.nodes[0].gettransaction(txId)
diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py
index 19d99c9c9e..db6fc86b82 100755
--- a/test/functional/receivedby.py
+++ b/test/functional/receivedby.py
@@ -23,16 +23,9 @@ def get_sub_array_from_array(object_array, to_match):
return []
class ReceivedByTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.num_nodes = 4
- self.setup_clean_chain = False
-
- def setup_nodes(self):
- #This test requires mocktime
+ def set_test_params(self):
+ self.num_nodes = 2
self.enable_mocktime()
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir)
def run_test(self):
'''
diff --git a/test/functional/reindex.py b/test/functional/reindex.py
index b446baa04d..1f684a1afe 100755
--- a/test/functional/reindex.py
+++ b/test/functional/reindex.py
@@ -15,8 +15,7 @@ import time
class ReindexTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -25,7 +24,7 @@ class ReindexTest(BitcoinTestFramework):
blockcount = self.nodes[0].getblockcount()
self.stop_nodes()
extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]]
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.start_nodes(extra_args)
while self.nodes[0].getblockcount() < blockcount:
time.sleep(0.1)
assert_equal(self.nodes[0].getblockcount(), blockcount)
diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py
index bc67654987..1d6494fe41 100755
--- a/test/functional/replace-by-fee.py
+++ b/test/functional/replace-by-fee.py
@@ -61,10 +61,8 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
class ReplaceByFeeTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 1
- self.setup_clean_chain = False
self.extra_args= [["-maxorphantx=1000",
"-whitelist=127.0.0.1",
"-limitancestorcount=50",
@@ -270,7 +268,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
tx1a_hex = txToHex(tx1a)
- tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ self.nodes[0].sendrawtransaction(tx1a_hex, True)
# Higher fee, but the fee per KB is much lower, so the replacement is
# rejected.
@@ -331,7 +329,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1.vin = [CTxIn(confirmed_utxo)]
tx1.vout = [CTxOut(1*COIN, CScript([b'a']))]
tx1_hex = txToHex(tx1)
- tx1_txid = self.nodes[0].sendrawtransaction(tx1_hex, True)
+ self.nodes[0].sendrawtransaction(tx1_hex, True)
tx2 = CTransaction()
tx2.vin = [CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)]
@@ -499,7 +497,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))]
tx2a_hex = txToHex(tx2a)
- tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True)
+ self.nodes[0].sendrawtransaction(tx2a_hex, True)
# Lower fee, but we'll prioritise it
tx2b = CTransaction()
diff --git a/test/functional/resendwallettransactions.py b/test/functional/resendwallettransactions.py
index 5059aa106e..d6ba591391 100755
--- a/test/functional/resendwallettransactions.py
+++ b/test/functional/resendwallettransactions.py
@@ -8,11 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_jsonrpc
class ResendWalletTransactionsTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.extra_args = [['--walletbroadcast=false']]
+ def set_test_params(self):
self.num_nodes = 1
+ self.extra_args = [['--walletbroadcast=false']]
def run_test(self):
# Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled.
@@ -20,7 +18,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# Should return an empty array if there aren't unconfirmed wallet transactions.
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir)
+ self.start_node(0, extra_args=[])
assert_equal(self.nodes[0].resendwallettransactions(), [])
# Should return an array with the unconfirmed wallet transaction.
diff --git a/test/functional/rest.py b/test/functional/rest.py
index a69dbb5013..437111a4d7 100755
--- a/test/functional/rest.py
+++ b/test/functional/rest.py
@@ -43,8 +43,7 @@ def http_post_call(host, port, path, requestdata = '', response_object = 0):
class RESTTest (BitcoinTestFramework):
FORMAT_SEPARATOR = "."
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py
index 20808207b2..0cf64beebd 100755
--- a/test/functional/rpcbind_test.py
+++ b/test/functional/rpcbind_test.py
@@ -11,19 +11,13 @@ from test_framework.test_framework import BitcoinTestFramework, SkipTest
from test_framework.util import *
from test_framework.netutil import *
-
class RPCBindTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
def setup_network(self):
- pass
-
- def setup_nodes(self):
- pass
+ self.add_nodes(self.num_nodes, None)
def run_bind_test(self, allow_ips, connect_to, addresses, expected):
'''
@@ -31,12 +25,14 @@ class RPCBindTest(BitcoinTestFramework):
then try to connect, and check if the set of bound addresses
matches the expected set.
'''
+ self.log.info("Bind test for %s" % str(addresses))
expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
base_args = ['-disablewallet', '-nolisten']
if allow_ips:
base_args += ['-rpcallowip=' + x for x in allow_ips]
binds = ['-rpcbind='+addr for addr in addresses]
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to)
+ self.nodes[0].rpchost = connect_to
+ self.start_node(0, base_args + binds)
pid = self.nodes[0].process.pid
assert_equal(set(get_bind_addrs(pid)), set(expected))
self.stop_nodes()
@@ -46,8 +42,10 @@ class RPCBindTest(BitcoinTestFramework):
Start a node with rpcallow IP, and request getnetworkinfo
at a non-localhost IP.
'''
+ self.log.info("Allow IP test for %s:%d" % (rpchost, rpcport))
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
+ self.nodes[0].rpchost = None
+ self.start_nodes([base_args])
# connect to node through non-loopback interface
node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir)
node.getnetworkinfo()
diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py
index 3b286000a1..b3cc681dad 100755
--- a/test/functional/rpcnamedargs.py
+++ b/test/functional/rpcnamedargs.py
@@ -10,23 +10,16 @@ from test_framework.util import (
assert_raises_jsonrpc,
)
-
class NamedArgumentTest(BitcoinTestFramework):
- """
- Test named arguments on RPC calls.
- """
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = False
+ def set_test_params(self):
self.num_nodes = 1
def run_test(self):
node = self.nodes[0]
- h = node.help(command='getinfo')
- assert(h.startswith('getinfo\n'))
+ h = node.help(command='getblockchaininfo')
+ assert(h.startswith('getblockchaininfo\n'))
- assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getinfo')
+ assert_raises_jsonrpc(-8, 'Unknown named parameter', node.help, random='getblockchaininfo')
h = node.getblockhash(height=0)
node.getblock(blockhash=h)
diff --git a/test/functional/segwit.py b/test/functional/segwit.py
index 51eaa34a54..f465c1683b 100755
--- a/test/functional/segwit.py
+++ b/test/functional/segwit.py
@@ -12,7 +12,6 @@ from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash16
from io import BytesIO
NODE_0 = 0
-NODE_1 = 1
NODE_2 = 2
WIT_V0 = 0
WIT_V1 = 1
@@ -75,9 +74,7 @@ def find_unspent(node, min_value):
return utxo
class SegWitTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0"],
@@ -282,6 +279,9 @@ class SegWitTest(BitcoinTestFramework):
assert(txid2 in template_txids)
assert(txid3 in template_txids)
+ # Check that wtxid is properly reported in mempool entry
+ assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True))
+
# Mine a block to clear the gbt cache again.
self.nodes[0].generate(1)
diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py
index e47e07fb86..fe577dc20a 100755
--- a/test/functional/sendheaders.py
+++ b/test/functional/sendheaders.py
@@ -128,7 +128,7 @@ class TestNode(NodeConnCB):
expect_headers = headers if headers != None else []
expect_inv = inv if inv != None else []
test_function = lambda: self.block_announced
- assert(wait_until(test_function, timeout=60))
+ wait_until(test_function, timeout=60, lock=mininode_lock)
with mininode_lock:
self.block_announced = False
@@ -155,12 +155,12 @@ class TestNode(NodeConnCB):
return
test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list
- assert(wait_until(test_function, timeout=timeout))
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
return
def wait_for_block_announcement(self, block_hash, timeout=60):
test_function = lambda: self.last_blockhash_announced == block_hash
- assert(wait_until(test_function, timeout=timeout))
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
return
def send_header_for_blocks(self, new_blocks):
@@ -174,8 +174,7 @@ class TestNode(NodeConnCB):
self.send_message(getblocks_message)
class SendHeadersTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
diff --git a/test/functional/signmessages.py b/test/functional/signmessages.py
index 42f6a9daaf..52ba6a5ad7 100755
--- a/test/functional/signmessages.py
+++ b/test/functional/signmessages.py
@@ -5,31 +5,34 @@
"""Test RPC commands for signing and verifying messages."""
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
class SignMessagesTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
def run_test(self):
message = 'This is just a test message'
- # Test the signing with a privkey
- privKey = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'
+ self.log.info('test signing with priv_key')
+ priv_key = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'
address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB'
- signature = self.nodes[0].signmessagewithprivkey(privKey, message)
-
- # Verify the message
+ expected_signature = 'INbVnW4e6PeRmsv2Qgu8NuopvrVjkcxob+sX8OcZG0SALhWybUjzMLPdAsXI46YZGb0KQTRii+wWIQzRpG/U+S0='
+ signature = self.nodes[0].signmessagewithprivkey(priv_key, message)
+ assert_equal(expected_signature, signature)
assert(self.nodes[0].verifymessage(address, signature, message))
- # Test the signing with an address with wallet
+ self.log.info('test signing with an address with wallet')
address = self.nodes[0].getnewaddress()
signature = self.nodes[0].signmessage(address, message)
-
- # Verify the message
assert(self.nodes[0].verifymessage(address, signature, message))
+ self.log.info('test verifying with another address should not work')
+ other_address = self.nodes[0].getnewaddress()
+ other_signature = self.nodes[0].signmessage(other_address, message)
+ assert(not self.nodes[0].verifymessage(other_address, signature, message))
+ assert(not self.nodes[0].verifymessage(address, other_signature, message))
+
if __name__ == '__main__':
SignMessagesTest().main()
diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py
index 415727268a..b47ef93955 100755
--- a/test/functional/signrawtransactions.py
+++ b/test/functional/signrawtransactions.py
@@ -9,8 +9,7 @@ from test_framework.util import *
class SignRawTransactionsTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py
index bc42a319df..76632fc578 100755
--- a/test/functional/smartfees.py
+++ b/test/functional/smartfees.py
@@ -141,11 +141,8 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True):
class EstimateFeeTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 3
- self.setup_clean_chain = False
def setup_network(self):
"""
@@ -153,57 +150,16 @@ class EstimateFeeTest(BitcoinTestFramework):
But first we need to use one node to create a lot of outputs
which we will use to generate our transactions.
"""
- self.nodes = []
+ self.add_nodes(3, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"],
+ ["-blockmaxsize=17000", "-maxorphantx=1000"],
+ ["-blockmaxsize=8000", "-maxorphantx=1000"]])
# Use node0 to mine blocks for input splitting
- self.nodes.append(self.start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
- "-whitelist=127.0.0.1"]))
-
- 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
- split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True)
-
- # Mine
- while (len(self.nodes[0].getrawmempool()) > 0):
- self.nodes[0].generate(1)
-
- # Repeatedly split those 2 outputs, doubling twice for each rep
- # Use txouts to monitor the available utxo, since these won't be tracked in wallet
- reps = 0
- while (reps < 5):
- #Double txouts to txouts2
- while (len(self.txouts)>0):
- split_inputs(self.nodes[0], self.txouts, self.txouts2)
- while (len(self.nodes[0].getrawmempool()) > 0):
- self.nodes[0].generate(1)
- #Double txouts2 to txouts
- while (len(self.txouts2)>0):
- split_inputs(self.nodes[0], self.txouts2, self.txouts)
- while (len(self.nodes[0].getrawmempool()) > 0):
- self.nodes[0].generate(1)
- reps += 1
- 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.
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
# (17k is room enough for 110 or so transactions)
- self.nodes.append(self.start_node(1, self.options.tmpdir,
- ["-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 = ["-blockmaxsize=8000", "-maxorphantx=1000"]
- self.nodes.append(self.start_node(2, self.options.tmpdir, node2args))
- connect_nodes(self.nodes[0], 2)
- connect_nodes(self.nodes[2], 1)
-
- self.sync_all()
def transact_and_mine(self, numblocks, mining_node):
min_fee = Decimal("0.00001")
@@ -232,9 +188,51 @@ class EstimateFeeTest(BitcoinTestFramework):
self.memutxo = newmem
def run_test(self):
+ self.log.info("This test is time consuming, please be patient")
+ self.log.info("Splitting inputs so we can generate tx's")
+
# Make log handler available to helper functions
global log
log = self.log
+
+ # Start node0
+ self.start_node(0)
+ self.txouts = []
+ self.txouts2 = []
+ # Split a coinbase into two transaction puzzle outputs
+ split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True)
+
+ # Mine
+ while (len(self.nodes[0].getrawmempool()) > 0):
+ self.nodes[0].generate(1)
+
+ # Repeatedly split those 2 outputs, doubling twice for each rep
+ # Use txouts to monitor the available utxo, since these won't be tracked in wallet
+ reps = 0
+ while (reps < 5):
+ #Double txouts to txouts2
+ while (len(self.txouts)>0):
+ split_inputs(self.nodes[0], self.txouts, self.txouts2)
+ while (len(self.nodes[0].getrawmempool()) > 0):
+ self.nodes[0].generate(1)
+ #Double txouts2 to txouts
+ while (len(self.txouts2)>0):
+ split_inputs(self.nodes[0], self.txouts2, self.txouts)
+ while (len(self.nodes[0].getrawmempool()) > 0):
+ self.nodes[0].generate(1)
+ reps += 1
+ 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
+ self.start_node(1)
+ self.start_node(2)
+ connect_nodes(self.nodes[1], 0)
+ connect_nodes(self.nodes[0], 2)
+ connect_nodes(self.nodes[2], 1)
+
+ self.sync_all()
+
self.fees_per_kb = []
self.memutxo = []
self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index 96bebe1ea1..180dac197e 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -44,16 +44,6 @@ def script_to_p2sh(script, main = False):
script = check_script(script)
return scripthash_to_p2sh(hash160(script), main)
-def key_to_p2sh_p2wpkh(key, main = False):
- key = check_key(key)
- p2shscript = CScript([OP_0, hash160(key)])
- return script_to_p2sh(p2shscript, main)
-
-def script_to_p2sh_p2wsh(script, main = False):
- script = check_script(script)
- p2shscript = CScript([OP_0, sha256(script)])
- return script_to_p2sh(p2shscript, main)
-
def check_key(key):
if (type(key) is str):
key = hex_str_to_bytes(key) # Assuming this is hex string
diff --git a/test/functional/test_framework/bignum.py b/test/functional/test_framework/bignum.py
index 024611da6e..db5ccd62c2 100644
--- a/test/functional/test_framework/bignum.py
+++ b/test/functional/test_framework/bignum.py
@@ -26,12 +26,6 @@ def bn2bin(v):
i -= 1
return s
-def bin2bn(s):
- l = 0
- for ch in s:
- l = (l << 8) | ch
- return l
-
def bn2mpi(v):
have_ext = False
if v.bit_length() > 0:
@@ -54,30 +48,6 @@ def bn2mpi(v):
v_bin[0] |= 0x80
return s + ext + v_bin
-def mpi2bn(s):
- if len(s) < 4:
- return None
- s_size = bytes(s[:4])
- v_len = struct.unpack(b">I", s_size)[0]
- if len(s) != (v_len + 4):
- return None
- if v_len == 0:
- return 0
-
- v_str = bytearray(s[4:])
- neg = False
- i = v_str[0]
- if i & 0x80:
- neg = True
- i &= ~0x80
- v_str[0] = i
-
- v = bin2bn(v_str)
-
- if neg:
- return -v
- return v
-
# bitcoin-specific little endian format, with implicit size
def mpi2vch(s):
r = s[4:] # strip size
@@ -86,12 +56,3 @@ def mpi2vch(s):
def bn2vch(v):
return bytes(mpi2vch(bn2mpi(v)))
-
-def vch2mpi(s):
- r = struct.pack(b">I", len(s)) # size
- r += s[::-1] # reverse string, converting LE->BE
- return r
-
-def vch2bn(s):
- return mpi2bn(vch2mpi(s))
-
diff --git a/test/functional/test_framework/blockstore.py b/test/functional/test_framework/blockstore.py
index 4cfd682bb5..4b2170a03f 100644
--- a/test/functional/test_framework/blockstore.py
+++ b/test/functional/test_framework/blockstore.py
@@ -143,16 +143,6 @@ class TxStore(object):
return None
return value
- def get_transaction(self, txhash):
- ret = None
- serialized_tx = self.get(txhash)
- if serialized_tx is not None:
- f = BytesIO(serialized_tx)
- ret = CTransaction()
- ret.deserialize(f)
- ret.calc_sha256()
- return ret
-
def add_transaction(self, tx):
tx.calc_sha256()
try:
diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py
index 9f062865a3..bfbc0c3b03 100755
--- a/test/functional/test_framework/comptool.py
+++ b/test/functional/test_framework/comptool.py
@@ -19,7 +19,7 @@ TestNode behaves as follows:
from .mininode import *
from .blockstore import BlockStore, TxStore
-from .util import p2p_port
+from .util import p2p_port, wait_until
import logging
@@ -189,7 +189,7 @@ class TestManager(object):
def wait_for_disconnections(self):
def disconnected():
return all(node.closed for node in self.test_nodes)
- return wait_until(disconnected, timeout=10)
+ wait_until(disconnected, timeout=10, lock=mininode_lock)
def wait_for_verack(self):
return all(node.wait_for_verack() for node in self.test_nodes)
@@ -197,7 +197,7 @@ class TestManager(object):
def wait_for_pings(self, counter):
def received_pongs():
return all(node.received_ping_response(counter) for node in self.test_nodes)
- return wait_until(received_pongs)
+ wait_until(received_pongs, lock=mininode_lock)
# sync_blocks: Wait for all connections to request the blockhash given
# then send get_headers to find out the tip of each node, and synchronize
@@ -210,8 +210,7 @@ class TestManager(object):
)
# --> error if not requested
- if not wait_until(blocks_requested, attempts=20*num_blocks):
- raise AssertionError("Not all nodes requested block")
+ wait_until(blocks_requested, attempts=20*num_blocks, lock=mininode_lock)
# Send getheaders message
[ c.cb.send_getheaders() for c in self.connections ]
@@ -231,8 +230,7 @@ class TestManager(object):
)
# --> error if not requested
- if not wait_until(transaction_requested, attempts=20*num_events):
- raise AssertionError("Not all nodes requested transaction")
+ wait_until(transaction_requested, attempts=20*num_events, lock=mininode_lock)
# Get the mempool
[ c.cb.send_mempool() for c in self.connections ]
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index a4d85501e7..2607b9b07c 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -35,7 +35,7 @@ import time
from threading import RLock, Thread
from test_framework.siphash import siphash256
-from test_framework.util import hex_str_to_bytes, bytes_to_hex_str
+from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, wait_until
BIP0031_VERSION = 60000
MY_VERSION = 70014 # past bip-31 for ping/pong
@@ -48,8 +48,8 @@ MAX_BLOCK_BASE_SIZE = 1000000
COIN = 100000000 # 1 btc in satoshis
NODE_NETWORK = (1 << 0)
-NODE_GETUTXO = (1 << 1)
-NODE_BLOOM = (1 << 2)
+# NODE_GETUTXO = (1 << 1)
+# NODE_BLOOM = (1 << 2)
NODE_WITNESS = (1 << 3)
NODE_UNSUPPORTED_SERVICE_BIT_5 = (1 << 5)
NODE_UNSUPPORTED_SERVICE_BIT_7 = (1 << 7)
@@ -1358,23 +1358,6 @@ class msg_reject(object):
return "msg_reject: %s %d %s [%064x]" \
% (self.message, self.code, self.reason, self.data)
-# Helper function
-def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf')):
- if attempts == float('inf') and timeout == float('inf'):
- timeout = 60
- attempt = 0
- elapsed = 0
-
- while attempt < attempts and elapsed < timeout:
- with mininode_lock:
- if predicate():
- return True
- attempt += 1
- elapsed += 0.05
- time.sleep(0.05)
-
- return False
-
class msg_feefilter(object):
command = b"feefilter"
@@ -1496,9 +1479,6 @@ class NodeConnCB(object):
# before acquiring the global lock and delivering the next message.
self.deliver_sleep_time = None
- # Remember the services our peer has advertised
- self.peer_services = None
-
# Message receiving methods
def deliver(self, conn, message):
@@ -1523,10 +1503,6 @@ class NodeConnCB(object):
print("ERROR delivering %s (%s)" % (repr(message),
sys.exc_info()[0]))
- def set_deliver_sleep_time(self, value):
- with mininode_lock:
- self.deliver_sleep_time = value
-
def get_deliver_sleep_time(self):
with mininode_lock:
return self.deliver_sleep_time
@@ -1591,21 +1567,21 @@ class NodeConnCB(object):
def wait_for_disconnect(self, timeout=60):
test_function = lambda: not self.connected
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
# Message receiving helper methods
def wait_for_block(self, blockhash, timeout=60):
test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_getdata(self, timeout=60):
test_function = lambda: self.last_message.get("getdata")
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_getheaders(self, timeout=60):
test_function = lambda: self.last_message.get("getheaders")
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_inv(self, expected_inv, timeout=60):
"""Waits for an INV message and checks that the first inv object in the message was as expected."""
@@ -1614,11 +1590,11 @@ class NodeConnCB(object):
test_function = lambda: self.last_message.get("inv") and \
self.last_message["inv"].inv[0].type == expected_inv[0].type and \
self.last_message["inv"].inv[0].hash == expected_inv[0].hash
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
def wait_for_verack(self, timeout=60):
test_function = lambda: self.message_count["verack"]
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
# Message sending helper functions
@@ -1636,7 +1612,7 @@ class NodeConnCB(object):
def sync_with_ping(self, timeout=60):
self.send_message(msg_ping(nonce=self.ping_counter))
test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
- assert wait_until(test_function, timeout=timeout)
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
self.ping_counter += 1
return True
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index 45d8e22d22..e5d415788f 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -15,17 +15,17 @@ import array
import os
from binascii import unhexlify, hexlify
-STATE_ESTABLISHED = '01'
-STATE_SYN_SENT = '02'
-STATE_SYN_RECV = '03'
-STATE_FIN_WAIT1 = '04'
-STATE_FIN_WAIT2 = '05'
-STATE_TIME_WAIT = '06'
-STATE_CLOSE = '07'
-STATE_CLOSE_WAIT = '08'
-STATE_LAST_ACK = '09'
+# STATE_ESTABLISHED = '01'
+# STATE_SYN_SENT = '02'
+# STATE_SYN_RECV = '03'
+# STATE_FIN_WAIT1 = '04'
+# STATE_FIN_WAIT2 = '05'
+# STATE_TIME_WAIT = '06'
+# STATE_CLOSE = '07'
+# STATE_CLOSE_WAIT = '08'
+# STATE_LAST_ACK = '09'
STATE_LISTEN = '0A'
-STATE_CLOSING = '0B'
+# STATE_CLOSING = '0B'
def get_socket_inodes(pid):
'''
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 3d9572788e..8f5339a02a 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -23,9 +23,7 @@ import struct
from .bignum import bn2vch
-MAX_SCRIPT_SIZE = 10000
MAX_SCRIPT_ELEMENT_SIZE = 520
-MAX_SCRIPT_OPCODES = 201
OPCODE_NAMES = {}
@@ -242,131 +240,6 @@ OP_PUBKEY = CScriptOp(0xfe)
OP_INVALIDOPCODE = CScriptOp(0xff)
-VALID_OPCODES = {
- OP_1NEGATE,
- OP_RESERVED,
- OP_1,
- OP_2,
- OP_3,
- OP_4,
- OP_5,
- OP_6,
- OP_7,
- OP_8,
- OP_9,
- OP_10,
- OP_11,
- OP_12,
- OP_13,
- OP_14,
- OP_15,
- OP_16,
-
- OP_NOP,
- OP_VER,
- OP_IF,
- OP_NOTIF,
- OP_VERIF,
- OP_VERNOTIF,
- OP_ELSE,
- OP_ENDIF,
- OP_VERIFY,
- OP_RETURN,
-
- OP_TOALTSTACK,
- OP_FROMALTSTACK,
- OP_2DROP,
- OP_2DUP,
- OP_3DUP,
- OP_2OVER,
- OP_2ROT,
- OP_2SWAP,
- OP_IFDUP,
- OP_DEPTH,
- OP_DROP,
- OP_DUP,
- OP_NIP,
- OP_OVER,
- OP_PICK,
- OP_ROLL,
- OP_ROT,
- OP_SWAP,
- OP_TUCK,
-
- OP_CAT,
- OP_SUBSTR,
- OP_LEFT,
- OP_RIGHT,
- OP_SIZE,
-
- OP_INVERT,
- OP_AND,
- OP_OR,
- OP_XOR,
- OP_EQUAL,
- OP_EQUALVERIFY,
- OP_RESERVED1,
- OP_RESERVED2,
-
- OP_1ADD,
- OP_1SUB,
- OP_2MUL,
- OP_2DIV,
- OP_NEGATE,
- OP_ABS,
- OP_NOT,
- OP_0NOTEQUAL,
-
- OP_ADD,
- OP_SUB,
- OP_MUL,
- OP_DIV,
- OP_MOD,
- OP_LSHIFT,
- OP_RSHIFT,
-
- OP_BOOLAND,
- OP_BOOLOR,
- OP_NUMEQUAL,
- OP_NUMEQUALVERIFY,
- OP_NUMNOTEQUAL,
- OP_LESSTHAN,
- OP_GREATERTHAN,
- OP_LESSTHANOREQUAL,
- OP_GREATERTHANOREQUAL,
- OP_MIN,
- OP_MAX,
-
- OP_WITHIN,
-
- OP_RIPEMD160,
- OP_SHA1,
- OP_SHA256,
- OP_HASH160,
- OP_HASH256,
- OP_CODESEPARATOR,
- OP_CHECKSIG,
- OP_CHECKSIGVERIFY,
- OP_CHECKMULTISIG,
- OP_CHECKMULTISIGVERIFY,
-
- OP_NOP1,
- OP_CHECKLOCKTIMEVERIFY,
- OP_CHECKSEQUENCEVERIFY,
- OP_NOP4,
- OP_NOP5,
- OP_NOP6,
- OP_NOP7,
- OP_NOP8,
- OP_NOP9,
- OP_NOP10,
-
- OP_SMALLINTEGER,
- OP_PUBKEYS,
- OP_PUBKEYHASH,
- OP_PUBKEY,
-}
-
OPCODE_NAMES.update({
OP_0 : 'OP_0',
OP_PUSHDATA1 : 'OP_PUSHDATA1',
@@ -486,124 +359,6 @@ OPCODE_NAMES.update({
OP_INVALIDOPCODE : 'OP_INVALIDOPCODE',
})
-OPCODES_BY_NAME = {
- 'OP_0' : OP_0,
- 'OP_PUSHDATA1' : OP_PUSHDATA1,
- 'OP_PUSHDATA2' : OP_PUSHDATA2,
- 'OP_PUSHDATA4' : OP_PUSHDATA4,
- 'OP_1NEGATE' : OP_1NEGATE,
- 'OP_RESERVED' : OP_RESERVED,
- 'OP_1' : OP_1,
- 'OP_2' : OP_2,
- 'OP_3' : OP_3,
- 'OP_4' : OP_4,
- 'OP_5' : OP_5,
- 'OP_6' : OP_6,
- 'OP_7' : OP_7,
- 'OP_8' : OP_8,
- 'OP_9' : OP_9,
- 'OP_10' : OP_10,
- 'OP_11' : OP_11,
- 'OP_12' : OP_12,
- 'OP_13' : OP_13,
- 'OP_14' : OP_14,
- 'OP_15' : OP_15,
- 'OP_16' : OP_16,
- 'OP_NOP' : OP_NOP,
- 'OP_VER' : OP_VER,
- 'OP_IF' : OP_IF,
- 'OP_NOTIF' : OP_NOTIF,
- 'OP_VERIF' : OP_VERIF,
- 'OP_VERNOTIF' : OP_VERNOTIF,
- 'OP_ELSE' : OP_ELSE,
- 'OP_ENDIF' : OP_ENDIF,
- 'OP_VERIFY' : OP_VERIFY,
- 'OP_RETURN' : OP_RETURN,
- 'OP_TOALTSTACK' : OP_TOALTSTACK,
- 'OP_FROMALTSTACK' : OP_FROMALTSTACK,
- 'OP_2DROP' : OP_2DROP,
- 'OP_2DUP' : OP_2DUP,
- 'OP_3DUP' : OP_3DUP,
- 'OP_2OVER' : OP_2OVER,
- 'OP_2ROT' : OP_2ROT,
- 'OP_2SWAP' : OP_2SWAP,
- 'OP_IFDUP' : OP_IFDUP,
- 'OP_DEPTH' : OP_DEPTH,
- 'OP_DROP' : OP_DROP,
- 'OP_DUP' : OP_DUP,
- 'OP_NIP' : OP_NIP,
- 'OP_OVER' : OP_OVER,
- 'OP_PICK' : OP_PICK,
- 'OP_ROLL' : OP_ROLL,
- 'OP_ROT' : OP_ROT,
- 'OP_SWAP' : OP_SWAP,
- 'OP_TUCK' : OP_TUCK,
- 'OP_CAT' : OP_CAT,
- 'OP_SUBSTR' : OP_SUBSTR,
- 'OP_LEFT' : OP_LEFT,
- 'OP_RIGHT' : OP_RIGHT,
- 'OP_SIZE' : OP_SIZE,
- 'OP_INVERT' : OP_INVERT,
- 'OP_AND' : OP_AND,
- 'OP_OR' : OP_OR,
- 'OP_XOR' : OP_XOR,
- 'OP_EQUAL' : OP_EQUAL,
- 'OP_EQUALVERIFY' : OP_EQUALVERIFY,
- 'OP_RESERVED1' : OP_RESERVED1,
- 'OP_RESERVED2' : OP_RESERVED2,
- 'OP_1ADD' : OP_1ADD,
- 'OP_1SUB' : OP_1SUB,
- 'OP_2MUL' : OP_2MUL,
- 'OP_2DIV' : OP_2DIV,
- 'OP_NEGATE' : OP_NEGATE,
- 'OP_ABS' : OP_ABS,
- 'OP_NOT' : OP_NOT,
- 'OP_0NOTEQUAL' : OP_0NOTEQUAL,
- 'OP_ADD' : OP_ADD,
- 'OP_SUB' : OP_SUB,
- 'OP_MUL' : OP_MUL,
- 'OP_DIV' : OP_DIV,
- 'OP_MOD' : OP_MOD,
- 'OP_LSHIFT' : OP_LSHIFT,
- 'OP_RSHIFT' : OP_RSHIFT,
- 'OP_BOOLAND' : OP_BOOLAND,
- 'OP_BOOLOR' : OP_BOOLOR,
- 'OP_NUMEQUAL' : OP_NUMEQUAL,
- 'OP_NUMEQUALVERIFY' : OP_NUMEQUALVERIFY,
- 'OP_NUMNOTEQUAL' : OP_NUMNOTEQUAL,
- 'OP_LESSTHAN' : OP_LESSTHAN,
- 'OP_GREATERTHAN' : OP_GREATERTHAN,
- 'OP_LESSTHANOREQUAL' : OP_LESSTHANOREQUAL,
- 'OP_GREATERTHANOREQUAL' : OP_GREATERTHANOREQUAL,
- 'OP_MIN' : OP_MIN,
- 'OP_MAX' : OP_MAX,
- 'OP_WITHIN' : OP_WITHIN,
- 'OP_RIPEMD160' : OP_RIPEMD160,
- 'OP_SHA1' : OP_SHA1,
- 'OP_SHA256' : OP_SHA256,
- 'OP_HASH160' : OP_HASH160,
- 'OP_HASH256' : OP_HASH256,
- 'OP_CODESEPARATOR' : OP_CODESEPARATOR,
- 'OP_CHECKSIG' : OP_CHECKSIG,
- 'OP_CHECKSIGVERIFY' : OP_CHECKSIGVERIFY,
- 'OP_CHECKMULTISIG' : OP_CHECKMULTISIG,
- 'OP_CHECKMULTISIGVERIFY' : OP_CHECKMULTISIGVERIFY,
- 'OP_NOP1' : OP_NOP1,
- 'OP_CHECKLOCKTIMEVERIFY' : OP_CHECKLOCKTIMEVERIFY,
- 'OP_CHECKSEQUENCEVERIFY' : OP_CHECKSEQUENCEVERIFY,
- 'OP_NOP4' : OP_NOP4,
- 'OP_NOP5' : OP_NOP5,
- 'OP_NOP6' : OP_NOP6,
- 'OP_NOP7' : OP_NOP7,
- 'OP_NOP8' : OP_NOP8,
- 'OP_NOP9' : OP_NOP9,
- 'OP_NOP10' : OP_NOP10,
- 'OP_SMALLINTEGER' : OP_SMALLINTEGER,
- 'OP_PUBKEYS' : OP_PUBKEYS,
- 'OP_PUBKEYHASH' : OP_PUBKEYHASH,
- 'OP_PUBKEY' : OP_PUBKEY,
-}
-
class CScriptInvalidError(Exception):
"""Base class for CScript exceptions"""
pass
diff --git a/test/functional/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index a08b03ed24..0070844168 100644
--- a/test/functional/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -91,7 +91,7 @@ class Socks5Connection(object):
self.conn.sendall(bytearray([0x01, 0x00]))
# Read connect request
- (ver,cmd,rsv,atyp) = recvall(self.conn, 4)
+ ver, cmd, _, atyp = recvall(self.conn, 4)
if ver != 0x05:
raise IOError('Invalid socks version %i in connect request' % ver)
if cmd != Command.CONNECT:
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 7903bb0045..a53eb51799 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -43,62 +43,33 @@ TEST_EXIT_PASSED = 0
TEST_EXIT_FAILED = 1
TEST_EXIT_SKIPPED = 77
-BITCOIND_PROC_WAIT_TIMEOUT = 60
-
class BitcoinTestFramework(object):
"""Base class for a bitcoin test script.
- Individual bitcoin test scripts should subclass this class and override the following methods:
+ Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods.
+
+ Individual tests can also override the following methods to customize the test setup:
- - __init__()
- add_options()
- setup_chain()
- setup_network()
- - run_test()
+ - setup_nodes()
- The main() method should not be overridden.
+ The __init__() and main() methods should not be overridden.
This class also contains various public and private helper methods."""
- # Methods to override in subclass test scripts.
def __init__(self):
- self.num_nodes = 4
+ """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method"""
self.setup_clean_chain = False
self.nodes = []
self.mocktime = 0
+ self.set_test_params()
- def add_options(self, parser):
- pass
-
- def setup_chain(self):
- self.log.info("Initializing test directory " + self.options.tmpdir)
- if self.setup_clean_chain:
- self._initialize_chain_clean(self.options.tmpdir, self.num_nodes)
- else:
- self._initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir)
-
- def setup_network(self):
- self.setup_nodes()
-
- # Connect the nodes as a "chain". This allows us
- # to split the network between nodes 1 and 2 to get
- # two halves that can work on competing chains.
- for i in range(self.num_nodes - 1):
- connect_nodes_bi(self.nodes, i, i + 1)
- self.sync_all()
-
- def setup_nodes(self):
- extra_args = None
- if hasattr(self, "extra_args"):
- extra_args = self.extra_args
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
-
- def run_test(self):
- raise NotImplementedError
-
- # Main function. This should not be overridden by the subclass test scripts.
+ assert hasattr(self, "num_nodes"), "Test must set self.num_nodes in set_test_params()"
def main(self):
+ """Main function. This should not be overridden by the subclass test scripts."""
parser = optparse.OptionParser(usage="%prog [options]")
parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
@@ -202,26 +173,50 @@ class BitcoinTestFramework(object):
logging.shutdown()
sys.exit(TEST_EXIT_FAILED)
- # Public helper methods. These can be accessed by the subclass test scripts.
+ # Methods to override in subclass test scripts.
+ def set_test_params(self):
+ """Tests must this method to change default values for number of nodes, topology, etc"""
+ raise NotImplementedError
- def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None):
- """Start a bitcoind and return RPC connection to it"""
+ def add_options(self, parser):
+ """Override this method to add command-line options to the test"""
+ pass
- if extra_args is None:
- extra_args = []
- if binary is None:
- binary = os.getenv("BITCOIND", "bitcoind")
- node = TestNode(i, dirname, extra_args, rpchost, timewait, binary, stderr, self.mocktime, coverage_dir=self.options.coveragedir)
- node.start()
- node.wait_for_rpc_connection()
+ def setup_chain(self):
+ """Override this method to customize blockchain setup"""
+ self.log.info("Initializing test directory " + self.options.tmpdir)
+ if self.setup_clean_chain:
+ self._initialize_chain_clean()
+ else:
+ self._initialize_chain()
- if self.options.coveragedir is not None:
- coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc)
+ def setup_network(self):
+ """Override this method to customize test network topology"""
+ self.setup_nodes()
+
+ # Connect the nodes as a "chain". This allows us
+ # to split the network between nodes 1 and 2 to get
+ # two halves that can work on competing chains.
+ for i in range(self.num_nodes - 1):
+ connect_nodes_bi(self.nodes, i, i + 1)
+ self.sync_all()
+
+ def setup_nodes(self):
+ """Override this method to customize test node setup"""
+ extra_args = None
+ if hasattr(self, "extra_args"):
+ extra_args = self.extra_args
+ self.add_nodes(self.num_nodes, extra_args)
+ self.start_nodes()
- return node
+ def run_test(self):
+ """Tests must override this method to define test logic"""
+ raise NotImplementedError
- def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
- """Start multiple bitcoinds, return RPC connections to them"""
+ # Public helper methods. These can be accessed by the subclass test scripts.
+
+ def add_nodes(self, num_nodes, extra_args=None, rpchost=None, timewait=None, binary=None):
+ """Instantiate TestNode objects"""
if extra_args is None:
extra_args = [[]] * num_nodes
@@ -229,12 +224,30 @@ class BitcoinTestFramework(object):
binary = [None] * num_nodes
assert_equal(len(extra_args), num_nodes)
assert_equal(len(binary), num_nodes)
- nodes = []
+ for i in range(num_nodes):
+ self.nodes.append(TestNode(i, self.options.tmpdir, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir))
+
+ def start_node(self, i, extra_args=None, stderr=None):
+ """Start a bitcoind"""
+
+ node = self.nodes[i]
+
+ node.start(extra_args, stderr)
+ node.wait_for_rpc_connection()
+
+ if self.options.coveragedir is not None:
+ coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc)
+
+ def start_nodes(self, extra_args=None):
+ """Start multiple bitcoinds"""
+
+ if extra_args is None:
+ extra_args = [None] * self.num_nodes
+ assert_equal(len(extra_args), self.num_nodes)
try:
- for i in range(num_nodes):
- nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir))
- nodes[i].start()
- for node in nodes:
+ for i, node in enumerate(self.nodes):
+ node.start(extra_args[i])
+ for node in self.nodes:
node.wait_for_rpc_connection()
except:
# If one node failed to start, stop the others
@@ -242,16 +255,13 @@ class BitcoinTestFramework(object):
raise
if self.options.coveragedir is not None:
- for node in nodes:
+ for node in self.nodes:
coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc)
- return nodes
-
def stop_node(self, i):
"""Stop a bitcoind test node"""
self.nodes[i].stop_node()
- while not self.nodes[i].is_node_stopped():
- time.sleep(0.1)
+ self.nodes[i].wait_until_stopped()
def stop_nodes(self):
"""Stop multiple bitcoind test nodes"""
@@ -261,13 +271,12 @@ class BitcoinTestFramework(object):
for node in self.nodes:
# Wait for nodes to stop
- while not node.is_node_stopped():
- time.sleep(0.1)
+ node.wait_until_stopped()
- def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_msg=None):
+ def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None):
with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr:
try:
- self.start_node(i, dirname, extra_args, stderr=log_stderr)
+ self.start_node(i, extra_args, stderr=log_stderr)
self.stop_node(i)
except Exception as e:
assert 'bitcoind exited' in str(e) # node must have shutdown
@@ -356,16 +365,16 @@ class BitcoinTestFramework(object):
rpc_handler.setLevel(logging.DEBUG)
rpc_logger.addHandler(rpc_handler)
- def _initialize_chain(self, test_dir, num_nodes, cachedir):
+ def _initialize_chain(self):
"""Initialize a pre-mined blockchain for use by the test.
Create a cache of a 200-block-long chain (with wallet) for MAX_NODES
Afterward, create num_nodes copies from the cache."""
- assert num_nodes <= MAX_NODES
+ assert self.num_nodes <= MAX_NODES
create_cache = False
for i in range(MAX_NODES):
- if not os.path.isdir(os.path.join(cachedir, 'node' + str(i))):
+ if not os.path.isdir(os.path.join(self.options.cachedir, 'node' + str(i))):
create_cache = True
break
@@ -374,18 +383,18 @@ class BitcoinTestFramework(object):
# find and delete old cache directories if any exist
for i in range(MAX_NODES):
- if os.path.isdir(os.path.join(cachedir, "node" + str(i))):
- shutil.rmtree(os.path.join(cachedir, "node" + str(i)))
+ if os.path.isdir(os.path.join(self.options.cachedir, "node" + str(i))):
+ shutil.rmtree(os.path.join(self.options.cachedir, "node" + str(i)))
# Create cache directories, run bitcoinds:
for i in range(MAX_NODES):
- datadir = initialize_datadir(cachedir, i)
+ datadir = initialize_datadir(self.options.cachedir, i)
args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"]
if i > 0:
args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
- self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None))
+ self.nodes.append(TestNode(i, self.options.cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None))
self.nodes[i].args = args
- self.nodes[i].start()
+ self.start_node(i)
# Wait for RPC connections to be ready
for node in self.nodes:
@@ -414,24 +423,24 @@ class BitcoinTestFramework(object):
self.nodes = []
self.disable_mocktime()
for i in range(MAX_NODES):
- os.remove(log_filename(cachedir, i, "debug.log"))
- os.remove(log_filename(cachedir, i, "db.log"))
- os.remove(log_filename(cachedir, i, "peers.dat"))
- os.remove(log_filename(cachedir, i, "fee_estimates.dat"))
-
- for i in range(num_nodes):
- from_dir = os.path.join(cachedir, "node" + str(i))
- to_dir = os.path.join(test_dir, "node" + str(i))
+ os.remove(log_filename(self.options.cachedir, i, "debug.log"))
+ os.remove(log_filename(self.options.cachedir, i, "db.log"))
+ os.remove(log_filename(self.options.cachedir, i, "peers.dat"))
+ os.remove(log_filename(self.options.cachedir, i, "fee_estimates.dat"))
+
+ for i in range(self.num_nodes):
+ from_dir = os.path.join(self.options.cachedir, "node" + str(i))
+ to_dir = os.path.join(self.options.tmpdir, "node" + str(i))
shutil.copytree(from_dir, to_dir)
- initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf
+ initialize_datadir(self.options.tmpdir, i) # Overwrite port/rpcport in bitcoin.conf
- def _initialize_chain_clean(self, test_dir, num_nodes):
+ def _initialize_chain_clean(self):
"""Initialize empty blockchain for use by the test.
Create an empty blockchain and num_nodes wallets.
Useful if a test case wants complete control over initialization."""
- for i in range(num_nodes):
- initialize_datadir(test_dir, i)
+ for i in range(self.num_nodes):
+ initialize_datadir(self.options.tmpdir, i)
class ComparisonTestFramework(BitcoinTestFramework):
"""Test framework for doing p2p comparison testing
@@ -441,8 +450,7 @@ class ComparisonTestFramework(BitcoinTestFramework):
- 2 binaries: 1 test binary, 1 ref binary
- n>2 binaries: 1 test binary, n-1 ref binaries"""
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
@@ -455,13 +463,13 @@ class ComparisonTestFramework(BitcoinTestFramework):
help="bitcoind binary to use for reference nodes (if any)")
def setup_network(self):
- extra_args = [['-whitelist=127.0.0.1']]*self.num_nodes
+ extra_args = [['-whitelist=127.0.0.1']] * self.num_nodes
if hasattr(self, "extra_args"):
extra_args = self.extra_args
- self.nodes = self.start_nodes(
- self.num_nodes, self.options.tmpdir, extra_args,
- binary=[self.options.testbinary] +
- [self.options.refbinary] * (self.num_nodes - 1))
+ self.add_nodes(self.num_nodes, extra_args,
+ binary=[self.options.testbinary] +
+ [self.options.refbinary] * (self.num_nodes - 1))
+ self.start_nodes()
class SkipTest(Exception):
"""This exception is raised to skip a test"""
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 66f89d43f4..12dab57a02 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -4,8 +4,10 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Class for bitcoind node under test"""
+import decimal
import errno
import http.client
+import json
import logging
import os
import subprocess
@@ -15,9 +17,12 @@ from .util import (
assert_equal,
get_rpc_proxy,
rpc_url,
+ wait_until,
)
from .authproxy import JSONRPCException
+BITCOIND_PROC_WAIT_TIMEOUT = 60
+
class TestNode():
"""A class for representing a bitcoind node under test.
@@ -34,7 +39,11 @@ class TestNode():
self.index = i
self.datadir = os.path.join(dirname, "node" + str(i))
self.rpchost = rpchost
- self.rpc_timeout = timewait
+ if timewait:
+ self.rpc_timeout = timewait
+ else:
+ # Wait for up to 60 seconds for the RPC server to respond
+ self.rpc_timeout = 60
if binary is None:
self.binary = os.getenv("BITCOIND", "bitcoind")
else:
@@ -45,6 +54,8 @@ class TestNode():
self.extra_args = extra_args
self.args = [self.binary, "-datadir=" + self.datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime), "-uacomment=testnode%d" % i]
+ self.cli = TestNodeCLI(os.getenv("BITCOINCLI", "bitcoin-cli"), self.datadir)
+
self.running = False
self.process = None
self.rpc_connected = False
@@ -57,20 +68,24 @@ class TestNode():
assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection"
return self.rpc.__getattr__(*args, **kwargs)
- def start(self):
+ def start(self, extra_args=None, stderr=None):
"""Start the node."""
- self.process = subprocess.Popen(self.args + self.extra_args, stderr=self.stderr)
+ if extra_args is None:
+ extra_args = self.extra_args
+ if stderr is None:
+ stderr = self.stderr
+ self.process = subprocess.Popen(self.args + extra_args, stderr=stderr)
self.running = True
self.log.debug("bitcoind started, waiting for RPC to come up")
def wait_for_rpc_connection(self):
"""Sets up an RPC connection to the bitcoind process. Returns False if unable to connect."""
-
- # Wait for up to 10 seconds for the RPC server to respond
- for _ in range(40):
- assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode
+ # Poll at a rate of four times per second
+ poll_per_s = 4
+ for _ in range(poll_per_s * self.rpc_timeout):
+ assert self.process.poll() is None, "bitcoind exited with status %i during initialization" % self.process.returncode
try:
- self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir)
+ self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)
self.rpc.getblockcount()
# If the call to getblockcount() succeeds then the RPC connection is up
self.rpc_connected = True
@@ -86,7 +101,7 @@ class TestNode():
except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting
if "No RPC credentials" not in str(e):
raise
- time.sleep(0.25)
+ time.sleep(1.0 / poll_per_s)
raise AssertionError("Unable to connect to bitcoind")
def get_wallet_rpc(self, wallet_name):
@@ -113,14 +128,20 @@ class TestNode():
if not self.running:
return True
return_code = self.process.poll()
- if return_code is not None:
- # process has stopped. Assert that it didn't return an error code.
- assert_equal(return_code, 0)
- self.running = False
- self.process = None
- self.log.debug("Node stopped")
- return True
- return False
+ if return_code is None:
+ return False
+
+ # process has stopped. Assert that it didn't return an error code.
+ assert_equal(return_code, 0)
+ self.running = False
+ self.process = None
+ self.rpc_connected = False
+ self.rpc = None
+ self.log.debug("Node stopped")
+ return True
+
+ def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
+ wait_until(self.is_node_stopped, timeout=timeout)
def node_encrypt_wallet(self, passphrase):
""""Encrypts the wallet.
@@ -128,7 +149,42 @@ class TestNode():
This causes bitcoind to shutdown, so this method takes
care of cleaning up resources."""
self.encryptwallet(passphrase)
- while not self.is_node_stopped():
- time.sleep(0.1)
- self.rpc = None
- self.rpc_connected = False
+ self.wait_until_stopped()
+
+class TestNodeCLI():
+ """Interface to bitcoin-cli for an individual node"""
+
+ def __init__(self, binary, datadir):
+ self.args = []
+ self.binary = binary
+ self.datadir = datadir
+ self.input = None
+
+ def __call__(self, *args, input=None):
+ # TestNodeCLI is callable with bitcoin-cli command-line args
+ self.args = [str(arg) for arg in args]
+ self.input = input
+ return self
+
+ def __getattr__(self, command):
+ def dispatcher(*args, **kwargs):
+ return self.send_cli(command, *args, **kwargs)
+ return dispatcher
+
+ def send_cli(self, command, *args, **kwargs):
+ """Run bitcoin-cli command. Deserializes returned string as python object."""
+
+ pos_args = [str(arg) for arg in args]
+ named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()]
+ assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call"
+ p_args = [self.binary, "-datadir=" + self.datadir] + self.args
+ if named_args:
+ p_args += ["-named"]
+ p_args += [command] + pos_args + named_args
+ process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ cli_stdout, cli_stderr = process.communicate(input=self.input)
+ returncode = process.poll()
+ if returncode:
+ # Ignore cli_stdout, raise with cli_stderr
+ raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr)
+ return json.loads(cli_stdout, parse_float=decimal.Decimal)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 4098fd8615..b2d8199d12 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -12,6 +12,7 @@ import logging
import os
import random
import re
+from subprocess import CalledProcessError
import time
from . import coverage
@@ -57,18 +58,42 @@ def assert_raises_message(exc, message, fun, *args, **kwds):
else:
raise AssertionError("No exception raised")
+def assert_raises_process_error(returncode, output, fun, *args, **kwds):
+ """Execute a process and asserts the process return code and output.
+
+ Calls function `fun` with arguments `args` and `kwds`. Catches a CalledProcessError
+ and verifies that the return code and output are as expected. Throws AssertionError if
+ no CalledProcessError was raised or if the return code and output are not as expected.
+
+ Args:
+ returncode (int): the process return code.
+ output (string): [a substring of] the process output.
+ fun (function): the function to call. This should execute a process.
+ args*: positional arguments for the function.
+ kwds**: named arguments for the function.
+ """
+ try:
+ fun(*args, **kwds)
+ except CalledProcessError as e:
+ if returncode != e.returncode:
+ raise AssertionError("Unexpected returncode %i" % e.returncode)
+ if output not in e.output:
+ raise AssertionError("Expected substring not found:" + e.output)
+ else:
+ raise AssertionError("No exception raised")
+
def assert_raises_jsonrpc(code, message, fun, *args, **kwds):
"""Run an RPC and verify that a specific JSONRPC exception code and message is raised.
Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException
and verifies that the error code and message are as expected. Throws AssertionError if
- no JSONRPCException was returned or if the error code/message are not as expected.
+ no JSONRPCException was raised or if the error code/message are not as expected.
Args:
code (int), optional: the error code returned by the RPC call (defined
in src/rpc/protocol.h). Set to None if checking the error code is not required.
message (string), optional: [a substring of] the error string returned by the
- RPC call. Set to None if checking the error string is not required
+ RPC call. Set to None if checking the error string is not required.
fun (function): the function to call. This should be the name of an RPC.
args*: positional arguments for the function.
kwds**: named arguments for the function.
@@ -157,6 +182,28 @@ def str_to_b64str(string):
def satoshi_round(amount):
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
+def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None):
+ if attempts == float('inf') and timeout == float('inf'):
+ timeout = 60
+ attempt = 0
+ timeout += time.time()
+
+ while attempt < attempts and time.time() < timeout:
+ if lock:
+ with lock:
+ if predicate():
+ return
+ else:
+ if predicate():
+ return
+ attempt += 1
+ time.sleep(0.05)
+
+ # Print the cause of the timeout
+ assert_greater_than(attempts, attempt)
+ assert_greater_than(timeout, time.time())
+ raise RuntimeError('Unreachable')
+
# RPC/P2P connection constants and functions
############################################
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index d248a6c005..8dbe6247ee 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -81,6 +81,7 @@ BASE_SCRIPTS= [
# vv Tests less than 30s vv
'keypool-topup.py',
'zmq_test.py',
+ 'bitcoin_cli.py',
'mempool_resurrect_test.py',
'txn_doublespend.py --mineblock',
'txn_clone.py',
@@ -120,6 +121,7 @@ BASE_SCRIPTS= [
'bip65-cltv-p2p.py',
'uptime.py',
'resendwallettransactions.py',
+ 'minchainwork.py',
]
EXTENDED_SCRIPTS = [
@@ -279,6 +281,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove
#Set env vars
if "BITCOIND" not in os.environ:
os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext
+ os.environ["BITCOINCLI"] = build_dir + '/src/bitcoin-cli' + exeext
tests_dir = src_dir + '/test/functional/'
diff --git a/test/functional/txn_clone.py b/test/functional/txn_clone.py
index 9b81af96cf..740bb2d4c5 100755
--- a/test/functional/txn_clone.py
+++ b/test/functional/txn_clone.py
@@ -8,11 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class TxnMallTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 4
- self.setup_clean_chain = False
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
diff --git a/test/functional/txn_doublespend.py b/test/functional/txn_doublespend.py
index 1bd3b3271c..69629ef951 100755
--- a/test/functional/txn_doublespend.py
+++ b/test/functional/txn_doublespend.py
@@ -8,11 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class TxnMallTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 4
- self.setup_clean_chain = False
def add_options(self, parser):
parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true",
diff --git a/test/functional/uptime.py b/test/functional/uptime.py
index b20d6f5cb6..78236b2393 100755
--- a/test/functional/uptime.py
+++ b/test/functional/uptime.py
@@ -13,9 +13,7 @@ from test_framework.test_framework import BitcoinTestFramework
class UptimeTest(BitcoinTestFramework):
- def __init__(self):
- super().__init__()
-
+ def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py
index 158aa9ae89..40726d2a76 100755
--- a/test/functional/wallet-accounts.py
+++ b/test/functional/wallet-accounts.py
@@ -17,9 +17,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
class WalletAccountsTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
self.extra_args = [[]]
diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py
index 61ad00330b..e4757c8c03 100755
--- a/test/functional/wallet-dump.py
+++ b/test/functional/wallet-dump.py
@@ -56,10 +56,7 @@ def read_dump(file_name, addrs, hd_master_addr_old):
class WalletDumpTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = False
+ def set_test_params(self):
self.num_nodes = 1
self.extra_args = [["-keypool=90"]]
@@ -68,7 +65,8 @@ class WalletDumpTest(BitcoinTestFramework):
# longer than the default 30 seconds due to an expensive
# CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in
# the test often takes even longer.
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60)
+ self.add_nodes(self.num_nodes, self.extra_args, timewait=60)
+ self.start_nodes()
def run_test (self):
tmpdir = self.options.tmpdir
@@ -95,13 +93,13 @@ class WalletDumpTest(BitcoinTestFramework):
#encrypt wallet, restart, unlock and dump
self.nodes[0].node_encrypt_wallet('test')
- self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0])
+ self.start_node(0)
self.nodes[0].walletpassphrase('test', 10)
# Should be a no-op:
self.nodes[0].keypoolrefill()
self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.encrypted.dump")
- found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_enc = \
+ found_addr, found_addr_chg, found_addr_rsv, _ = \
read_dump(tmpdir + "/node0/wallet.encrypted.dump", addrs, hd_master_addr_unenc)
assert_equal(found_addr, test_addr_count)
assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now
diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py
index 8fea4140db..ce1e7744e9 100755
--- a/test/functional/wallet-encryption.py
+++ b/test/functional/wallet-encryption.py
@@ -6,16 +6,14 @@
import time
-from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_jsonrpc,
)
class WalletEncryptionTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
@@ -31,7 +29,7 @@ class WalletEncryptionTest(BitcoinTestFramework):
# Encrypt the wallet
self.nodes[0].node_encrypt_wallet(passphrase)
- self.nodes[0] = self.start_node(0, self.options.tmpdir)
+ self.start_node(0)
# Test that the wallet is encrypted
assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address)
diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py
index 821575ed19..a6b96b7455 100755
--- a/test/functional/wallet-hd.py
+++ b/test/functional/wallet-hd.py
@@ -11,11 +11,8 @@ from test_framework.util import (
)
import shutil
-
class WalletHDTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=0']]
@@ -25,8 +22,8 @@ class WalletHDTest(BitcoinTestFramework):
# Make sure can't switch off usehd after wallet creation
self.stop_node(1)
- self.assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet')
- self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])
+ self.assert_start_raises_init_error(1, ['-usehd=0'], 'already existing HD wallet')
+ self.start_node(1)
connect_nodes_bi(self.nodes, 0, 1)
# Make sure we use hd, keep masterkeyid
@@ -42,7 +39,7 @@ class WalletHDTest(BitcoinTestFramework):
non_hd_add = self.nodes[0].getnewaddress()
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
- # This should be enough to keep the master key and the non-HD key
+ # This should be enough to keep the master key and the non-HD key
self.nodes[1].backupwallet(tmpdir + "/hd.bak")
#self.nodes[1].dumpwallet(tmpdir + "/hd.dump")
@@ -54,7 +51,7 @@ class WalletHDTest(BitcoinTestFramework):
for i in range(num_hd_adds):
hd_add = self.nodes[1].getnewaddress()
hd_info = self.nodes[1].validateaddress(hd_add)
- assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i+1)+"'")
+ assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'")
assert_equal(hd_info["hdmasterkeyid"], masterkeyid)
self.nodes[0].sendtoaddress(hd_add, 1)
self.nodes[0].generate(1)
@@ -76,14 +73,14 @@ class WalletHDTest(BitcoinTestFramework):
shutil.rmtree(tmpdir + "/node1/regtest/blocks")
shutil.rmtree(tmpdir + "/node1/regtest/chainstate")
shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
- self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1])
+ self.start_node(1)
# Assert that derivation is deterministic
hd_add_2 = None
for _ in range(num_hd_adds):
hd_add_2 = self.nodes[1].getnewaddress()
hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
- assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_+1)+"'")
+ assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_)+"'")
assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid)
assert_equal(hd_add, hd_add_2)
connect_nodes_bi(self.nodes, 0, 1)
@@ -91,7 +88,7 @@ class WalletHDTest(BitcoinTestFramework):
# Needs rescan
self.stop_node(1)
- self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan'])
+ self.start_node(1, extra_args=self.extra_args[1] + ['-rescan'])
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
# send a tx and make sure its using the internal chain for the changeoutput
@@ -101,7 +98,7 @@ class WalletHDTest(BitcoinTestFramework):
for out in outs:
if out['value'] != 1:
keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']
-
+
assert_equal(keypath[0:7], "m/0'/1'")
if __name__ == '__main__':
diff --git a/test/functional/wallet.py b/test/functional/wallet.py
index 3e3e8fcddb..27089e8845 100755
--- a/test/functional/wallet.py
+++ b/test/functional/wallet.py
@@ -7,28 +7,28 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class WalletTest(BitcoinTestFramework):
-
- def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
- """Return curr_balance after asserting the fee was in range"""
- fee = balance_with_fee - curr_balance
- assert_fee_amount(fee, tx_size, fee_per_byte * 1000)
- return curr_balance
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
+ def set_test_params(self):
self.num_nodes = 4
+ self.setup_clean_chain = True
self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)]
def setup_network(self):
- self.nodes = self.start_nodes(3, self.options.tmpdir, self.extra_args[:3])
+ self.add_nodes(4, self.extra_args)
+ self.start_node(0)
+ self.start_node(1)
+ self.start_node(2)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
- def run_test(self):
+ def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
+ """Return curr_balance after asserting the fee was in range"""
+ fee = balance_with_fee - curr_balance
+ assert_fee_amount(fee, tx_size, fee_per_byte * 1000)
+ return curr_balance
+ def run_test(self):
# Check that there's no UTXO on none of the nodes
assert_equal(len(self.nodes[0].listunspent()), 0)
assert_equal(len(self.nodes[1].listunspent()), 0)
@@ -42,9 +42,9 @@ class WalletTest(BitcoinTestFramework):
assert_equal(walletinfo['immature_balance'], 50)
assert_equal(walletinfo['balance'], 0)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
self.nodes[1].generate(101)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
assert_equal(self.nodes[0].getbalance(), 50)
assert_equal(self.nodes[1].getbalance(), 50)
@@ -56,6 +56,15 @@ class WalletTest(BitcoinTestFramework):
assert_equal(len(self.nodes[1].listunspent()), 1)
assert_equal(len(self.nodes[2].listunspent()), 0)
+ self.log.info("test gettxout")
+ confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"]
+ # First, outputs that are unspent both in the chain and in the
+ # mempool should appear with or without include_mempool
+ txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False)
+ assert_equal(txout['value'], 50)
+ txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True)
+ assert_equal(txout['value'], 50)
+
# Send 21 BTC from 0 to 2 using sendtoaddress call.
# Locked memory should use at least 32 bytes to sign each transaction
self.log.info("test getmemoryinfo")
@@ -65,10 +74,9 @@ class WalletTest(BitcoinTestFramework):
memory_after = self.nodes[0].getmemoryinfo()
assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used'])
- self.log.info("test gettxout")
+ self.log.info("test gettxout (second part)")
# utxo spent in mempool should be visible if you exclude mempool
# but invisible if you include mempool
- confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"]
txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False)
assert_equal(txout['value'], 50)
txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True)
@@ -88,7 +96,7 @@ class WalletTest(BitcoinTestFramework):
# Have node0 mine a block, thus it will collect its own fee.
self.nodes[0].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
# Exercise locking of unspent outputs
unspent_0 = self.nodes[2].listunspent()[0]
@@ -101,7 +109,7 @@ class WalletTest(BitcoinTestFramework):
# Have node1 generate 100 blocks (so node0 can recover the fee)
self.nodes[1].generate(100)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
# node0 should end up with 100 btc in block rewards plus fees, but
# minus the 21 plus fees sent to node2
@@ -130,7 +138,7 @@ class WalletTest(BitcoinTestFramework):
# Have node1 mine a block to confirm transactions:
self.nodes[1].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
assert_equal(self.nodes[0].getbalance(), 0)
assert_equal(self.nodes[2].getbalance(), 94)
@@ -142,14 +150,14 @@ class WalletTest(BitcoinTestFramework):
self.nodes[2].settxfee(fee_per_byte * 1000)
txid = self.nodes[2].sendtoaddress(address, 10, "", "", False)
self.nodes[2].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
assert_equal(self.nodes[0].getbalance(), Decimal('10'))
# Send 10 BTC with subtract fee from amount
txid = self.nodes[2].sendtoaddress(address, 10, "", "", True)
self.nodes[2].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
@@ -157,7 +165,7 @@ class WalletTest(BitcoinTestFramework):
# Sendmany 10 BTC
txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [])
self.nodes[2].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
node_0_bal += Decimal('10')
node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
assert_equal(self.nodes[0].getbalance(), node_0_bal)
@@ -165,7 +173,7 @@ class WalletTest(BitcoinTestFramework):
# Sendmany 10 BTC with subtract fee from amount
txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address])
self.nodes[2].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
@@ -176,9 +184,9 @@ class WalletTest(BitcoinTestFramework):
# EXPECT: nodes[3] should have those transactions in its mempool.
txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- sync_mempools(self.nodes)
+ sync_mempools(self.nodes[0:2])
- self.nodes.append(self.start_node(3, self.options.tmpdir, self.extra_args[3]))
+ self.start_node(3)
connect_nodes_bi(self.nodes, 0, 3)
sync_blocks(self.nodes)
@@ -206,7 +214,7 @@ class WalletTest(BitcoinTestFramework):
signedRawTx = self.nodes[1].signrawtransaction(rawTx)
decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
zeroValueTxid= decRawTx['txid']
- sendResp = self.nodes[1].sendrawtransaction(signedRawTx['hex'])
+ self.nodes[1].sendrawtransaction(signedRawTx['hex'])
self.sync_all()
self.nodes[1].generate(1) #mine a block
@@ -222,22 +230,24 @@ class WalletTest(BitcoinTestFramework):
#do some -walletbroadcast tests
self.stop_nodes()
- self.nodes = self.start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]])
+ self.start_node(0, ["-walletbroadcast=0"])
+ self.start_node(1, ["-walletbroadcast=0"])
+ self.start_node(2, ["-walletbroadcast=0"])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
self.nodes[1].generate(1) #mine a block, tx should not be in there
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
assert_equal(self.nodes[2].getbalance(), node_2_bal) #should not be changed because tx was not broadcasted
#now broadcast from another node, mine a block, sync, and check the balance
self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
self.nodes[1].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
node_2_bal += 2
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
assert_equal(self.nodes[2].getbalance(), node_2_bal)
@@ -247,14 +257,16 @@ class WalletTest(BitcoinTestFramework):
#restart the nodes with -walletbroadcast=1
self.stop_nodes()
- self.nodes = self.start_nodes(3, self.options.tmpdir)
+ self.start_node(0)
+ self.start_node(1)
+ self.start_node(2)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
- sync_blocks(self.nodes)
+ sync_blocks(self.nodes[0:3])
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ sync_blocks(self.nodes[0:3])
node_2_bal += 2
#tx should be added to balance because after restarting the nodes tx should be broadcastet
@@ -285,7 +297,7 @@ class WalletTest(BitcoinTestFramework):
address_to_import = self.nodes[2].getnewaddress()
txid = self.nodes[0].sendtoaddress(address_to_import, 1)
self.nodes[0].generate(1)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
# 2. Import address from node2 to node1
self.nodes[1].importaddress(address_to_import)
@@ -311,15 +323,15 @@ class WalletTest(BitcoinTestFramework):
cbAddr = self.nodes[1].getnewaddress()
blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0]
cbTxId = self.nodes[0].getblock(blkHash)['tx'][0]
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
# Check that the txid and balance is found by node1
self.nodes[1].gettransaction(cbTxId)
# check if wallet or blockchain maintenance changes the balance
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
blocks = self.nodes[0].generate(2)
- self.sync_all()
+ self.sync_all([self.nodes[0:3]])
balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
block_count = self.nodes[0].getblockcount()
@@ -350,7 +362,9 @@ class WalletTest(BitcoinTestFramework):
self.log.info("check " + m)
self.stop_nodes()
# set lower ancestor limit for later
- self.nodes = self.start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3)
+ self.start_node(0, [m, "-limitancestorcount="+str(chainlimit)])
+ self.start_node(1, [m, "-limitancestorcount="+str(chainlimit)])
+ self.start_node(2, [m, "-limitancestorcount="+str(chainlimit)])
while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]:
# reindex will leave rpc warm up "early"; Wait for it to finish
time.sleep(0.1)
@@ -398,7 +412,7 @@ class WalletTest(BitcoinTestFramework):
# Try with walletrejectlongchains
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)])
+ self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)])
# wait for loadmempool
timeout = 10
diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py
index ff51cba4b3..15ea26afa1 100755
--- a/test/functional/walletbackup.py
+++ b/test/functional/walletbackup.py
@@ -37,11 +37,9 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
class WalletBackupTest(BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
+ def set_test_params(self):
self.num_nodes = 4
+ self.setup_clean_chain = True
# nodes 1, 2,3 are spenders, let's give them a keypool=100
self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
@@ -78,9 +76,9 @@ class WalletBackupTest(BitcoinTestFramework):
# As above, this mirrors the original bash test.
def start_three(self):
- self.nodes[0] = self.start_node(0, self.options.tmpdir)
- self.nodes[1] = self.start_node(1, self.options.tmpdir)
- self.nodes[2] = self.start_node(2, self.options.tmpdir)
+ self.start_node(0)
+ self.start_node(1)
+ self.start_node(2)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)
diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py
index af867d7a52..c001517a6d 100755
--- a/test/functional/zapwallettxes.py
+++ b/test/functional/zapwallettxes.py
@@ -20,9 +20,7 @@ from test_framework.util import (assert_equal,
)
class ZapWalletTXesTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
@@ -48,7 +46,7 @@ class ZapWalletTXesTest (BitcoinTestFramework):
# Stop-start node0. Both confirmed and unconfirmed transactions remain in the wallet.
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir)
+ self.start_node(0)
assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)
assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)
@@ -56,7 +54,7 @@ class ZapWalletTXesTest (BitcoinTestFramework):
# Stop node0 and restart with zapwallettxes and persistmempool. The unconfirmed
# transaction is zapped from the wallet, but is re-added when the mempool is reloaded.
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-persistmempool=1", "-zapwallettxes=2"])
+ self.start_node(0, ["-persistmempool=1", "-zapwallettxes=2"])
assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)
assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2)
@@ -64,7 +62,7 @@ class ZapWalletTXesTest (BitcoinTestFramework):
# Stop node0 and restart with zapwallettxes, but not persistmempool.
# The unconfirmed transaction is zapped and is no longer in the wallet.
self.stop_node(0)
- self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-zapwallettxes=2"])
+ self.start_node(0, ["-zapwallettxes=2"])
# tx1 is still be available because it was confirmed
assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1)
diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py
index 26c946d215..3f2668ee87 100755
--- a/test/functional/zmq_test.py
+++ b/test/functional/zmq_test.py
@@ -13,9 +13,7 @@ from test_framework.util import (assert_equal,
)
class ZMQTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
+ def set_test_params(self):
self.num_nodes = 2
def setup_nodes(self):
@@ -41,8 +39,9 @@ class ZMQTest (BitcoinTestFramework):
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
ip_address = "tcp://127.0.0.1:28332"
self.zmqSubSocket.connect(ip_address)
- extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []]
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []]
+ self.add_nodes(self.num_nodes, self.extra_args)
+ self.start_nodes()
def run_test(self):
try: