aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am51
-rw-r--r--configure.ac12
-rwxr-xr-xcontrib/devtools/check-doc.py2
-rwxr-xr-xcontrib/filter-lcov.py25
-rw-r--r--contrib/rpm/README.md2
-rw-r--r--contrib/rpm/bitcoin.if2
-rw-r--r--contrib/verifybinaries/README.md8
-rwxr-xr-xcontrib/verifybinaries/verify.sh43
-rw-r--r--depends/packages/expat.mk4
-rw-r--r--doc/developer-notes.md19
-rw-r--r--share/pixmaps/nsis-header.bmpbin25818 -> 25820 bytes
-rw-r--r--share/pixmaps/nsis-wizard.bmpbin154542 -> 154544 bytes
-rw-r--r--src/addrdb.cpp214
-rw-r--r--src/addrdb.h2
-rw-r--r--src/arith_uint256.cpp2
-rw-r--r--src/arith_uint256.h10
-rw-r--r--src/base58.cpp2
-rw-r--r--src/bench/bench_bitcoin.cpp2
-rw-r--r--src/bench/checkblock.cpp2
-rw-r--r--src/chain.cpp2
-rw-r--r--src/chainparams.cpp20
-rw-r--r--src/chainparams.h4
-rw-r--r--src/coins.cpp10
-rw-r--r--src/coins.h8
-rw-r--r--src/compat/glibc_sanity.cpp2
-rw-r--r--src/compat/glibcxx_sanity.cpp2
-rw-r--r--src/consensus/consensus.h8
-rw-r--r--src/cuckoocache.h35
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/httprpc.cpp53
-rw-r--r--src/httpserver.cpp44
-rw-r--r--src/httpserver.h4
-rw-r--r--src/init.cpp159
-rw-r--r--src/leveldb/db/version_set.h2
-rw-r--r--src/net.cpp91
-rw-r--r--src/net.h11
-rw-r--r--src/net_processing.cpp4
-rw-r--r--src/netaddress.cpp48
-rw-r--r--src/netaddress.h8
-rw-r--r--src/netbase.cpp9
-rw-r--r--src/policy/fees.h2
-rw-r--r--src/protocol.cpp2
-rw-r--r--src/pubkey.cpp2
-rw-r--r--src/qt/clientmodel.cpp5
-rw-r--r--src/qt/coincontroldialog.cpp13
-rw-r--r--src/qt/forms/optionsdialog.ui6
-rw-r--r--src/qt/modaloverlay.cpp2
-rw-r--r--src/qt/rpcconsole.cpp4
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/rest.cpp2
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/mining.cpp11
-rw-r--r--src/rpc/net.cpp18
-rw-r--r--src/rpc/server.cpp17
-rw-r--r--src/script/bitcoinconsensus.cpp2
-rw-r--r--src/script/interpreter.cpp4
-rw-r--r--src/script/sigcache.cpp2
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/standard.cpp2
-rw-r--r--src/secp256k1/sage/group_prover.sage2
-rw-r--r--src/secp256k1/src/asm/field_10x26_arm.s2
-rw-r--r--src/support/events.h10
-rw-r--r--src/test/arith_uint256_tests.cpp2
-rw-r--r--src/test/coins_tests.cpp24
-rw-r--r--src/test/data/script_tests.json2
-rw-r--r--src/test/data/tx_valid.json2
-rw-r--r--src/test/netbase_tests.cpp18
-rw-r--r--src/test/script_tests.cpp2
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txdb.cpp8
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp10
-rw-r--r--src/txmempool.h3
-rw-r--r--src/util.cpp12
-rw-r--r--src/util.h17
-rw-r--r--src/utilstrencodings.cpp8
-rw-r--r--src/validation.cpp6
-rw-r--r--src/versionbits.cpp2
-rw-r--r--src/wallet/rpcdump.cpp28
-rw-r--r--src/wallet/wallet.cpp72
-rw-r--r--src/wallet/wallet.h3
-rw-r--r--test/README.md154
-rw-r--r--test/functional/README.md174
-rwxr-xr-xtest/functional/bumpfee.py2
-rwxr-xr-xtest/functional/example_test.py219
-rwxr-xr-xtest/functional/pruning.py2
-rwxr-xr-xtest/functional/rest.py22
-rwxr-xr-xtest/functional/smartfees.py2
-rwxr-xr-xtest/functional/test_framework/mininode.py2
-rw-r--r--test/functional/test_framework/util.py2
-rwxr-xr-xtest/functional/test_runner.py2
-rwxr-xr-xtest/functional/uptime.py32
-rwxr-xr-xtest/functional/zapwallettxes.py2
93 files changed, 1201 insertions, 678 deletions
diff --git a/Makefile.am b/Makefile.am
index 40114a551f..8216b7d608 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,10 +59,10 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
$(top_srcdir)/contrib/macdeploy/detached-sig-create.sh
-COVERAGE_INFO = baseline_filtered_combined.info baseline.info \
- leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \
+COVERAGE_INFO = baseline.info \
+ test_bitcoin_filtered.info total_coverage.info \
baseline_filtered.info functional_test.info functional_test_filtered.info \
- leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info
+ test_bitcoin_coverage.info test_bitcoin.info
dist-hook:
-$(GIT) archive --format=tar HEAD -- src/clientversion.cpp | $(AMTAR) -C $(top_distdir) -xf -
@@ -166,52 +166,45 @@ $(BITCOIN_CLI_BIN): FORCE
$(MAKE) -C src $(@F)
if USE_LCOV
+LCOV_FILTER_PATTERN=-p "/usr/include/" -p "src/leveldb/" -p "src/bench/" -p "src/univalue" -p "src/crypto/ctaes" -p "src/secp256k1"
baseline.info:
$(LCOV) -c -i -d $(abs_builddir)/src -o $@
baseline_filtered.info: baseline.info
- $(LCOV) -r $< "/usr/include/*" -o $@
+ $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
+ $(LCOV) -a $@ $(LCOV_OPTS) -o $@
-leveldb_baseline.info: baseline_filtered.info
- $(LCOV) -c -i -d $(abs_builddir)/src/leveldb -b $(abs_builddir)/src/leveldb -o $@
-
-leveldb_baseline_filtered.info: leveldb_baseline.info
- $(LCOV) -r $< "/usr/include/*" -o $@
-
-baseline_filtered_combined.info: leveldb_baseline_filtered.info baseline_filtered.info
- $(LCOV) -a leveldb_baseline_filtered.info -a baseline_filtered.info -o $@
-
-test_bitcoin.info: baseline_filtered_combined.info
+test_bitcoin.info: baseline_filtered.info
$(MAKE) -C src/ check
- $(LCOV) -c -d $(abs_builddir)/src -t test_bitcoin -o $@
- $(LCOV) -z -d $(abs_builddir)/src
- $(LCOV) -z -d $(abs_builddir)/src/leveldb
+ $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src -t test_bitcoin -o $@
+ $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src
test_bitcoin_filtered.info: test_bitcoin.info
- $(LCOV) -r $< "/usr/include/*" -o $@
+ $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
+ $(LCOV) -a $@ $(LCOV_OPTS) -o $@
functional_test.info: test_bitcoin_filtered.info
- -@TIMEOUT=15 python test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)
- $(LCOV) -c -d $(abs_builddir)/src --t functional-tests -o $@
- $(LCOV) -z -d $(abs_builddir)/src
- $(LCOV) -z -d $(abs_builddir)/src/leveldb
+ -@TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)
+ $(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t functional-tests -o $@
+ $(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src
functional_test_filtered.info: functional_test.info
- $(LCOV) -r $< "/usr/include/*" -o $@
+ $(abs_builddir)/contrib/filter-lcov.py $(LCOV_FILTER_PATTERN) $< $@
+ $(LCOV) -a $@ $(LCOV_OPTS) -o $@
-test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info
- $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@
+test_bitcoin_coverage.info: baseline_filtered.info test_bitcoin_filtered.info
+ $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -o $@
-total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info functional_test_filtered.info
- $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
+total_coverage.info: test_bitcoin_filtered.info functional_test_filtered.info
+ $(LCOV) -a $(LCOV_OPTS) baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt
test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info
- $(GENHTML) -s $< -o $(@D)
+ $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
@touch $@
total.coverage/.dirstamp: total_coverage.info
- $(GENHTML) -s $< -o $(@D)
+ $(GENHTML) -s $(LCOV_OPTS) $< -o $(@D)
@touch $@
cov: test_bitcoin.coverage/.dirstamp total.coverage/.dirstamp
diff --git a/configure.ac b/configure.ac
index 5ad01d44e8..a90063d9de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -158,6 +158,12 @@ AC_ARG_ENABLE([lcov],
[enable lcov testing (default is no)])],
[use_lcov=yes],
[use_lcov=no])
+
+AC_ARG_ENABLE([lcov-branch-coverage],
+ [AS_HELP_STRING([--enable-lcov-branch-coverage],
+ [enable lcov testing branch coverage (default is no)])],
+ [use_lcov_branch=yes],
+ [use_lcov_branch=no])
AC_ARG_ENABLE([glibc-back-compat],
[AS_HELP_STRING([--enable-glibc-back-compat],
@@ -442,6 +448,12 @@ if test x$use_lcov = xyes; then
[AC_MSG_ERROR("lcov testing requested but --coverage linker flag does not work")])
AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"],
[AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")])
+ AC_DEFINE(USE_COVERAGE, 1, [Define this symbol if coverage is enabled])
+ CXXFLAGS="$CXXFLAGS -Og"
+fi
+
+if test x$use_lcov_branch != xno; then
+ AC_SUBST(LCOV_OPTS, "$LCOV_OPTS --rc lcov_branch_coverage=1")
fi
dnl Check for endianness
diff --git a/contrib/devtools/check-doc.py b/contrib/devtools/check-doc.py
index 445175ec2b..249214e931 100755
--- a/contrib/devtools/check-doc.py
+++ b/contrib/devtools/check-doc.py
@@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO
REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"')
REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")')
# list unsupported, deprecated and duplicate args as they need no documentation
-SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions'])
+SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize'])
def main():
used = check_output(CMD_GREP_ARGS, shell=True)
diff --git a/contrib/filter-lcov.py b/contrib/filter-lcov.py
new file mode 100755
index 0000000000..299377d691
--- /dev/null
+++ b/contrib/filter-lcov.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python3
+
+import argparse
+
+parser = argparse.ArgumentParser(description='Remove the coverage data from a tracefile for all files matching the pattern.')
+parser.add_argument('--pattern', '-p', action='append', help='the pattern of files to remove', required=True)
+parser.add_argument('tracefile', help='the tracefile to remove the coverage data from')
+parser.add_argument('outfile', help='filename for the output to be written to')
+
+args = parser.parse_args()
+tracefile = args.tracefile
+pattern = args.pattern
+outfile = args.outfile
+
+in_remove = False
+with open(tracefile, 'r') as f:
+ with open(outfile, 'w') as wf:
+ for line in f:
+ for p in pattern:
+ if line.startswith("SF:") and p in line:
+ in_remove = True
+ if not in_remove:
+ wf.write(line)
+ if line == 'end_of_record\n':
+ in_remove = False
diff --git a/contrib/rpm/README.md b/contrib/rpm/README.md
index e1fd0b317b..4ab2f35680 100644
--- a/contrib/rpm/README.md
+++ b/contrib/rpm/README.md
@@ -181,5 +181,5 @@ knows what they are getting when installing the GUI package.
As far as minor differences, I generally prefer to assign the file permissions
in the `%files` portion of an RPM spec file rather than specifying the
-permissions of a file during `%install` and other minor things like that that
+permissions of a file during `%install` and other minor things like that
are largely just cosmetic.
diff --git a/contrib/rpm/bitcoin.if b/contrib/rpm/bitcoin.if
index 2b096c24dc..b206866cc5 100644
--- a/contrib/rpm/bitcoin.if
+++ b/contrib/rpm/bitcoin.if
@@ -121,7 +121,7 @@ interface(`bitcoin_manage_lib_dirs',`
########################################
## <summary>
## All of the rules required to administrate
-## an bitcoin environment
+## a bitcoin environment
## </summary>
## <param name="domain">
## <summary>
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
index ed3e14fb6c..3ffe0a2f28 100644
--- a/contrib/verifybinaries/README.md
+++ b/contrib/verifybinaries/README.md
@@ -26,6 +26,14 @@ The script returns 0 if everything passes the checks. It returns 1 if either the
./verify.sh bitcoin-core-0.13.0-rc3
```
+If you only want to download the binaries of certain platform, add the corresponding suffix, e.g.:
+
+```sh
+./verify.sh bitcoin-core-0.11.2-osx
+./verify.sh 0.12.0-linux
+./verify.sh bitcoin-core-0.13.0-rc3-win64
+```
+
If you do not want to keep the downloaded binaries, specify anything as the second parameter.
```sh
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index e20770c96a..c2cc2b7013 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -42,13 +42,36 @@ if [ -n "$1" ]; then
VERSION="$VERSIONPREFIX$1"
fi
- #now let's see if the version string contains "rc", and strip it off if it does
- # and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME
- if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then
- BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/"
- BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/"
+ STRIPPEDLAST="${VERSION%-*}"
+
+ #now let's see if the version string contains "rc" or a platform name (e.g. "osx")
+ if [[ "$STRIPPEDLAST-" == "$VERSIONPREFIX" ]]; then
+ BASEDIR="$BASEDIR$VERSION/"
else
+ # let's examine the last part to see if it's rc and/or platform name
+ STRIPPEDNEXTTOLAST="${STRIPPEDLAST%-*}"
+ if [[ "$STRIPPEDNEXTTOLAST-" == "$VERSIONPREFIX" ]]; then
+
+ LASTSUFFIX="${VERSION##*-}"
+ VERSION="$STRIPPEDLAST"
+
+ if [[ $LASTSUFFIX == *"$RCVERSIONSTRING"* ]]; then
+ RCVERSION="$LASTSUFFIX"
+ else
+ PLATFORM="$LASTSUFFIX"
+ fi
+
+ else
+ RCVERSION="${STRIPPEDLAST##*-}"
+ PLATFORM="${VERSION##*-}"
+
+ VERSION="$STRIPPEDNEXTTOLAST"
+ fi
+
BASEDIR="$BASEDIR$VERSION/"
+ if [[ $RCVERSION == *"$RCVERSIONSTRING"* ]]; then
+ BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSION/"
+ fi
fi
SIGNATUREFILE="$BASEDIR$SIGNATUREFILENAME"
@@ -92,12 +115,22 @@ if [ $RET -ne 0 ]; then
exit "$RET"
fi
+if [ -n "$PLATFORM" ]; then
+ grep $PLATFORM $TMPFILE > "$TMPFILE-plat"
+ TMPFILESIZE=$(stat -c%s "$TMPFILE-plat")
+ if [ $TMPFILESIZE -eq 0 ]; then
+ echo "error: no files matched the platform specified" && exit 3
+ fi
+ mv "$TMPFILE-plat" $TMPFILE
+fi
+
#here we extract the filenames from the signature file
FILES=$(awk '{print $2}' "$TMPFILE")
#and download these one by one
for file in $FILES
do
+ echo "Downloading $file"
wget --quiet -N "$BASEDIR$file"
done
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index 81a660e83a..7f484724a4 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -1,8 +1,8 @@
package=expat
-$(package)_version=2.2.0
+$(package)_version=2.2.1
$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=d9e50ff2d19b3538bd2127902a89987474e1a4db8e43a66a4d1a712ab9a504ff
+$(package)_sha256_hash=1868cadae4c82a018e361e2b2091de103cd820aaacb0d6cfa49bd2cd83978885
define $(package)_set_vars
$(package)_config_opts=--disable-static
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index a596ea0117..81bdcc9fdb 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -68,7 +68,7 @@ public:
return true;
}
}
-}
+} // namespace foo
```
Doxygen comments
@@ -287,7 +287,7 @@ General C++
- Assertions should not have side-effects
- - *Rationale*: Even though the source code is set to to refuse to compile
+ - *Rationale*: Even though the source code is set to refuse to compile
with assertions disabled, having side-effects in assertions is unexpected and
makes the code harder to understand
@@ -438,6 +438,21 @@ Source code organization
- *Rationale*: Avoids symbol conflicts
+- Terminate namespaces with a comment (`// namespace mynamespace`). The comment
+ should be placed on the same line as the brace closing the namespace, e.g.
+
+```c++
+namespace mynamespace {
+ ...
+} // namespace mynamespace
+
+namespace {
+ ...
+} // namespace
+```
+
+ - *Rationale*: Avoids confusion about the namespace context
+
GUI
-----
diff --git a/share/pixmaps/nsis-header.bmp b/share/pixmaps/nsis-header.bmp
index 9ab0ce2591..f54e249a0c 100644
--- a/share/pixmaps/nsis-header.bmp
+++ b/share/pixmaps/nsis-header.bmp
Binary files differ
diff --git a/share/pixmaps/nsis-wizard.bmp b/share/pixmaps/nsis-wizard.bmp
index 71255c6850..1434952885 100644
--- a/share/pixmaps/nsis-wizard.bmp
+++ b/share/pixmaps/nsis-wizard.bmp
Binary files differ
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index a3743cd0d4..7f85c16585 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -15,25 +15,31 @@
#include "tinyformat.h"
#include "util.h"
+namespace {
-CBanDB::CBanDB()
+template <typename Stream, typename Data>
+bool SerializeDB(Stream& stream, const Data& data)
{
- pathBanlist = GetDataDir() / "banlist.dat";
+ // Write and commit header, data
+ try {
+ CHashWriter hasher(SER_DISK, CLIENT_VERSION);
+ stream << FLATDATA(Params().MessageStart()) << data;
+ hasher << FLATDATA(Params().MessageStart()) << data;
+ stream << hasher.GetHash();
+ } catch (const std::exception& e) {
+ return error("%s: Serialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
}
-bool CBanDB::Write(const banmap_t& banSet)
+template <typename Data>
+bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data& data)
{
// Generate random temporary filename
unsigned short randv = 0;
GetRandBytes((unsigned char*)&randv, sizeof(randv));
- std::string tmpfn = strprintf("banlist.dat.%04x", randv);
-
- // serialize banlist, checksum data up to that point, then append csum
- CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);
- ssBanlist << FLATDATA(Params().MessageStart());
- ssBanlist << banSet;
- uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());
- ssBanlist << hash;
+ std::string tmpfn = strprintf("%s.%04x", prefix, randv);
// open temp output file, and associate with CAutoFile
fs::path pathTmp = GetDataDir() / tmpfn;
@@ -42,69 +48,41 @@ bool CBanDB::Write(const banmap_t& banSet)
if (fileout.IsNull())
return error("%s: Failed to open file %s", __func__, pathTmp.string());
- // Write and commit header, data
- try {
- fileout << ssBanlist;
- }
- catch (const std::exception& e) {
- return error("%s: Serialize or I/O error - %s", __func__, e.what());
- }
+ // Serialize
+ if (!SerializeDB(fileout, data)) return false;
FileCommit(fileout.Get());
fileout.fclose();
- // replace existing banlist.dat, if any, with new banlist.dat.XXXX
- if (!RenameOver(pathTmp, pathBanlist))
+ // replace existing file, if any, with new file
+ if (!RenameOver(pathTmp, path))
return error("%s: Rename-into-place failed", __func__);
return true;
}
-bool CBanDB::Read(banmap_t& banSet)
+template <typename Stream, typename Data>
+bool DeserializeDB(Stream& stream, Data& data, bool fCheckSum = true)
{
- // open input file, and associate with CAutoFile
- FILE *file = fsbridge::fopen(pathBanlist, "rb");
- CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
- if (filein.IsNull())
- return error("%s: Failed to open file %s", __func__, pathBanlist.string());
-
- // use file size to size memory buffer
- uint64_t fileSize = fs::file_size(pathBanlist);
- uint64_t dataSize = 0;
- // Don't try to resize to a negative number if file is small
- if (fileSize >= sizeof(uint256))
- dataSize = fileSize - sizeof(uint256);
- std::vector<unsigned char> vchData;
- vchData.resize(dataSize);
- uint256 hashIn;
-
- // read data and checksum from file
- try {
- filein.read((char *)&vchData[0], dataSize);
- filein >> hashIn;
- }
- catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
- }
- filein.fclose();
-
- CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION);
-
- // verify stored checksum matches input data
- uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end());
- if (hashIn != hashTmp)
- return error("%s: Checksum mismatch, data corrupted", __func__);
-
- unsigned char pchMsgTmp[4];
try {
+ CHashVerifier<Stream> verifier(&stream);
// de-serialize file header (network specific magic number) and ..
- ssBanlist >> FLATDATA(pchMsgTmp);
-
+ unsigned char pchMsgTmp[4];
+ verifier >> FLATDATA(pchMsgTmp);
// ... verify the network matches ours
if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
return error("%s: Invalid network magic number", __func__);
- // de-serialize ban data
- ssBanlist >> banSet;
+ // de-serialize data
+ verifier >> data;
+
+ // verify checksum
+ if (fCheckSum) {
+ uint256 hashTmp;
+ stream >> hashTmp;
+ if (hashTmp != verifier.GetHash()) {
+ return error("%s: Checksum mismatch, data corrupted", __func__);
+ }
+ }
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
@@ -113,106 +91,56 @@ bool CBanDB::Read(banmap_t& banSet)
return true;
}
-CAddrDB::CAddrDB()
+template <typename Data>
+bool DeserializeFileDB(const fs::path& path, Data& data)
{
- pathAddr = GetDataDir() / "peers.dat";
+ // open input file, and associate with CAutoFile
+ FILE *file = fsbridge::fopen(path, "rb");
+ CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
+ if (filein.IsNull())
+ return error("%s: Failed to open file %s", __func__, path.string());
+
+ return DeserializeDB(filein, data);
}
-bool CAddrDB::Write(const CAddrMan& addr)
-{
- // Generate random temporary filename
- unsigned short randv = 0;
- GetRandBytes((unsigned char*)&randv, sizeof(randv));
- std::string tmpfn = strprintf("peers.dat.%04x", randv);
+}
- // serialize addresses, checksum data up to that point, then append csum
- CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
- ssPeers << FLATDATA(Params().MessageStart());
- ssPeers << addr;
- uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
- ssPeers << hash;
+CBanDB::CBanDB()
+{
+ pathBanlist = GetDataDir() / "banlist.dat";
+}
- // open temp output file, and associate with CAutoFile
- fs::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fsbridge::fopen(pathTmp, "wb");
- CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (fileout.IsNull())
- return error("%s: Failed to open file %s", __func__, pathTmp.string());
+bool CBanDB::Write(const banmap_t& banSet)
+{
+ return SerializeFileDB("banlist", pathBanlist, banSet);
+}
- // Write and commit header, data
- try {
- fileout << ssPeers;
- }
- catch (const std::exception& e) {
- return error("%s: Serialize or I/O error - %s", __func__, e.what());
- }
- FileCommit(fileout.Get());
- fileout.fclose();
+bool CBanDB::Read(banmap_t& banSet)
+{
+ return DeserializeFileDB(pathBanlist, banSet);
+}
- // replace existing peers.dat, if any, with new peers.dat.XXXX
- if (!RenameOver(pathTmp, pathAddr))
- return error("%s: Rename-into-place failed", __func__);
+CAddrDB::CAddrDB()
+{
+ pathAddr = GetDataDir() / "peers.dat";
+}
- return true;
+bool CAddrDB::Write(const CAddrMan& addr)
+{
+ return SerializeFileDB("peers", pathAddr, addr);
}
bool CAddrDB::Read(CAddrMan& addr)
{
- // open input file, and associate with CAutoFile
- FILE *file = fsbridge::fopen(pathAddr, "rb");
- CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
- if (filein.IsNull())
- return error("%s: Failed to open file %s", __func__, pathAddr.string());
-
- // use file size to size memory buffer
- uint64_t fileSize = fs::file_size(pathAddr);
- uint64_t dataSize = 0;
- // Don't try to resize to a negative number if file is small
- if (fileSize >= sizeof(uint256))
- dataSize = fileSize - sizeof(uint256);
- std::vector<unsigned char> vchData;
- vchData.resize(dataSize);
- uint256 hashIn;
-
- // read data and checksum from file
- try {
- filein.read((char *)&vchData[0], dataSize);
- filein >> hashIn;
- }
- catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
- }
- filein.fclose();
-
- CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
-
- // verify stored checksum matches input data
- uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
- if (hashIn != hashTmp)
- return error("%s: Checksum mismatch, data corrupted", __func__);
-
- return Read(addr, ssPeers);
+ return DeserializeFileDB(pathAddr, addr);
}
bool CAddrDB::Read(CAddrMan& addr, CDataStream& ssPeers)
{
- unsigned char pchMsgTmp[4];
- try {
- // de-serialize file header (network specific magic number) and ..
- ssPeers >> FLATDATA(pchMsgTmp);
-
- // ... verify the network matches ours
- if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
- return error("%s: Invalid network magic number", __func__);
-
- // de-serialize address data into one CAddrMan object
- ssPeers >> addr;
- }
- catch (const std::exception& e) {
- // de-serialization has failed, ensure addrman is left in a clean state
+ bool ret = DeserializeDB(ssPeers, addr, false);
+ if (!ret) {
+ // Ensure addrman is left in a clean state
addr.Clear();
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
-
- return true;
+ return ret;
}
diff --git a/src/addrdb.h b/src/addrdb.h
index c3d509bd3a..6cb36dfac4 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -85,7 +85,7 @@ public:
CAddrDB();
bool Write(const CAddrMan& addr);
bool Read(CAddrMan& addr);
- bool Read(CAddrMan& addr, CDataStream& ssPeers);
+ static bool Read(CAddrMan& addr, CDataStream& ssPeers);
};
/** Access to the banlist database (banlist.dat) */
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index dd34a313b7..b4952af6f4 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -15,6 +15,8 @@
template <unsigned int BITS>
base_uint<BITS>::base_uint(const std::string& str)
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
SetHex(str);
}
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 0f6b3d4fba..c7734035df 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -31,12 +31,16 @@ public:
base_uint()
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
for (int i = 0; i < WIDTH; i++)
pn[i] = 0;
}
base_uint(const base_uint& b)
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
for (int i = 0; i < WIDTH; i++)
pn[i] = b.pn[i];
}
@@ -50,6 +54,8 @@ public:
base_uint(uint64_t b)
{
+ static_assert(BITS/32 > 0 && BITS%32 == 0, "Template parameter BITS must be a positive multiple of 32.");
+
pn[0] = (unsigned int)b;
pn[1] = (unsigned int)(b >> 32);
for (int i = 2; i < WIDTH; i++)
@@ -174,7 +180,7 @@ public:
{
// prefix operator
int i = 0;
- while (++pn[i] == 0 && i < WIDTH-1)
+ while (i < WIDTH && ++pn[i] == 0)
i++;
return *this;
}
@@ -191,7 +197,7 @@ public:
{
// prefix operator
int i = 0;
- while (--pn[i] == (uint32_t)-1 && i < WIDTH-1)
+ while (i < WIDTH && --pn[i] == (uint32_t)-1)
i++;
return *this;
}
diff --git a/src/base58.cpp b/src/base58.cpp
index 36b3523692..efa1beb1e4 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -225,7 +225,7 @@ public:
bool operator()(const CNoDestination& no) const { return false; }
};
-} // anon namespace
+} // namespace
bool CBitcoinAddress::Set(const CKeyID& id)
{
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 61a0b31aed..226861aa7f 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -7,10 +7,12 @@
#include "key.h"
#include "validation.h"
#include "util.h"
+#include "random.h"
int
main(int argc, char** argv)
{
+ RandomInit();
ECC_Start();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 195388839e..7bb1b93668 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -11,7 +11,7 @@
namespace block_bench {
#include "bench/data/block413567.raw.h"
-}
+} // namespace block_bench
// These are the two major time-sinks which happen after we have fully received
// a block off the wire, but before we can relay the block on to peers using
diff --git a/src/chain.cpp b/src/chain.cpp
index a5b369c4fc..8d4c4e7dea 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -126,7 +126,7 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
if (fNegative || fOverflow || bnTarget == 0)
return 0;
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
- // as it's too large for a arith_uint256. However, as 2**256 is at least as large
+ // as it's too large for an arith_uint256. However, as 2**256 is at least as large
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
// or ~bnTarget / (nTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 3b42c5fb23..dc4d2621ee 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -124,12 +124,12 @@ public:
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
// Note that of those with the service bits flag, most only support a subset of possible options
- vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille, only supports x1, x5, x9, and xd
- vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me", true)); // Matt Corallo, only supports x9
- vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
- vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com", true)); // Christian Decker, supports x1 - xf
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli, only supports x1, x5, x9, and xd
- vSeeds.push_back(CDNSSeedData("petertodd.org", "seed.btc.petertodd.org", true)); // Peter Todd, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.bitcoin.sipa.be", true); // Pieter Wuille, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("dnsseed.bluematt.me", true); // Matt Corallo, only supports x9
+ vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org", false); // Luke Dashjr
+ vSeeds.emplace_back("seed.bitcoinstats.com", true); // Christian Decker, supports x1 - xf
+ vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch", true); // Jonas Schnelli, only supports x1, x5, x9, and xd
+ vSeeds.emplace_back("seed.btc.petertodd.org", true); // Peter Todd, only supports x1, x5, x9, and xd
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
@@ -225,10 +225,10 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
// nodes with support for servicebits filtering should be at the top
- vSeeds.push_back(CDNSSeedData("testnetbitcoin.jonasschnelli.ch", "testnet-seed.bitcoin.jonasschnelli.ch", true));
- vSeeds.push_back(CDNSSeedData("petertodd.org", "seed.tbtc.petertodd.org", true));
- vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
- vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
+ vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true);
+ vSeeds.emplace_back("seed.tbtc.petertodd.org", true);
+ vSeeds.emplace_back("testnet-seed.bluematt.me", false);
+ vSeeds.emplace_back("testnet-seed.bitcoin.schildbach.de", false);
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
diff --git a/src/chainparams.h b/src/chainparams.h
index a2f136171b..f55ae4cf7f 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -15,9 +15,9 @@
#include <vector>
struct CDNSSeedData {
- std::string name, host;
+ std::string host;
bool supportsServiceBitsFiltering;
- CDNSSeedData(const std::string &strName, const std::string &strHost, bool supportsServiceBitsFilteringIn = false) : name(strName), host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
+ CDNSSeedData(const std::string &strHost, bool supportsServiceBitsFilteringIn) : host(strHost), supportsServiceBitsFiltering(supportsServiceBitsFilteringIn) {}
};
struct SeedSpec6 {
diff --git a/src/coins.cpp b/src/coins.cpp
index 2dceaf09b6..3113b7755d 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -11,11 +11,15 @@
#include <assert.h>
bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
-bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }
+bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
+{
+ Coin coin;
+ return GetCoin(outpoint, coin);
+}
CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
@@ -55,7 +59,7 @@ bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
CCoinsMap::const_iterator it = FetchCoin(outpoint);
if (it != cacheCoins.end()) {
coin = it->second.coin;
- return true;
+ return !coin.IsSpent();
}
return false;
}
@@ -125,7 +129,7 @@ bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
- return it != cacheCoins.end();
+ return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}
uint256 CCoinsViewCache::GetBestBlock() const {
diff --git a/src/coins.h b/src/coins.h
index 4774c9f6a6..077545a55b 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -145,11 +145,13 @@ private:
class CCoinsView
{
public:
- //! Retrieve the Coin (unspent transaction output) for a given outpoint.
+ /** Retrieve the Coin (unspent transaction output) for a given outpoint.
+ * Returns true only when an unspent coin was found, which is returned in coin.
+ * When false is returned, coin's value is unspecified.
+ */
virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
- //! Just check whether we have data for a given outpoint.
- //! This may (but cannot always) return true for spent outputs.
+ //! Just check whether a given outpoint is unspent.
virtual bool HaveCoin(const COutPoint &outpoint) const;
//! Retrieve the block hash whose state this CCoinsView currently represents
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
index d62d74d462..b4d1c90992 100644
--- a/src/compat/glibc_sanity.cpp
+++ b/src/compat/glibc_sanity.cpp
@@ -56,7 +56,7 @@ bool sanity_test_fdelt()
}
#endif
-} // anon namespace
+} // namespace
bool glibc_sanity_test()
{
diff --git a/src/compat/glibcxx_sanity.cpp b/src/compat/glibcxx_sanity.cpp
index cee8a98c7f..569fb1bbe8 100644
--- a/src/compat/glibcxx_sanity.cpp
+++ b/src/compat/glibcxx_sanity.cpp
@@ -38,7 +38,7 @@ bool sanity_test_list(unsigned int size)
return true;
}
-} // anon namespace
+} // namespace
// trigger: string::at(x) on an empty string to trigger __throw_out_of_range_fmt.
// test: force std::string to throw an out_of_range exception. Verify that
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 351911a3a4..58b2ed4b3e 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -12,7 +12,13 @@
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
static const unsigned int MAX_BLOCK_WEIGHT = 4000000;
-/** The maximum allowed size for a block excluding witness data, in bytes (network rule) */
+/**
+ * The maximum allowed size for a block excluding witness data, in bytes (network rule).
+ * This parameter is largely superfluous because it is directly implied by the above block
+ * weight limit, even when BIP 141 is not active. It continues to exist for use in
+ * various early tests that run before the witness data has been checked.
+ * All tests related to it could be removed without breaking consensus compatibility.
+ */
static const unsigned int MAX_BLOCK_BASE_SIZE = 1000000;
/** The maximum allowed number of signature check operations in a block (network rule) */
static const int64_t MAX_BLOCK_SIGOPS_COST = 80000;
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index 5837549455..fd24d05ee7 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -176,7 +176,7 @@ private:
*/
mutable std::vector<bool> epoch_flags;
- /** epoch_heuristic_counter is used to determine when a epoch might be aged
+ /** epoch_heuristic_counter is used to determine when an epoch might be aged
* & an expensive scan should be done. epoch_heuristic_counter is
* decremented on insert and reset to the new number of inserts which would
* cause the epoch to reach epoch_size when it reaches zero.
@@ -184,7 +184,7 @@ private:
uint32_t epoch_heuristic_counter;
/** epoch_size is set to be the number of elements supposed to be in a
- * epoch. When the number of non-erased elements in a epoch
+ * epoch. When the number of non-erased elements in an epoch
* exceeds epoch_size, a new epoch should be started and all
* current entries demoted. epoch_size is set to be 45% of size because
* we want to keep load around 90%, and we support 3 epochs at once --
@@ -206,6 +206,37 @@ private:
/** compute_hashes is convenience for not having to write out this
* expression everywhere we use the hash values of an Element.
*
+ * We need to map the 32-bit input hash onto a hash bucket in a range [0, size) in a
+ * manner which preserves as much of the hash's uniformity as possible. Ideally
+ * this would be done by bitmasking but the size is usually not a power of two.
+ *
+ * The naive approach would be to use a mod -- which isn't perfectly uniform but so
+ * long as the hash is much larger than size it is not that bad. Unfortunately,
+ * mod/division is fairly slow on ordinary microprocessors (e.g. 90-ish cycles on
+ * haswell, ARM doesn't even have an instruction for it.); when the divisor is a
+ * constant the compiler will do clever tricks to turn it into a multiply+add+shift,
+ * but size is a run-time value so the compiler can't do that here.
+ *
+ * One option would be to implement the same trick the compiler uses and compute the
+ * constants for exact division based on the size, as described in "{N}-bit Unsigned
+ * Division via {N}-bit Multiply-Add" by Arch D. Robison in 2005. But that code is
+ * somewhat complicated and the result is still slower than other options:
+ *
+ * Instead we treat the 32-bit random number as a Q32 fixed-point number in the range
+ * [0,1) and simply multiply it by the size. Then we just shift the result down by
+ * 32-bits to get our bucket number. The results has non-uniformity the same as a
+ * mod, but it is much faster to compute. More about this technique can be found at
+ * http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
+ *
+ * The resulting non-uniformity is also more equally distributed which would be
+ * advantageous for something like linear probing, though it shouldn't matter
+ * one way or the other for a cuckoo table.
+ *
+ * The primary disadvantage of this approach is increased intermediate precision is
+ * required but for a 32-bit random number we only need the high 32 bits of a
+ * 32*32->64 multiply, which means the operation is reasonably fast even on a
+ * typical 32-bit processor.
+ *
* @param e the element whose hashes will be returned
* @returns std::array<uint32_t, 8> of deterministic hashes derived from e
*/
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 4ad8a2c1ac..ba9e21cc1f 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -209,4 +209,4 @@ const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w)
return w.obfuscate_key;
}
-};
+} // namespace dbwrapper_private
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 053702f843..497e565b1e 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -92,35 +92,32 @@ static bool multiUserAuthorized(std::string strUserPass)
std::string strUser = strUserPass.substr(0, strUserPass.find(":"));
std::string strPass = strUserPass.substr(strUserPass.find(":") + 1);
- if (gArgs.IsArgSet("-rpcauth")) {
+ for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) {
//Search for multi-user login/pass "rpcauth" from config
- for (std::string strRPCAuth : gArgs.GetArgs("-rpcauth"))
- {
- std::vector<std::string> vFields;
- boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
- if (vFields.size() != 3) {
- //Incorrect formatting in config file
- continue;
- }
-
- std::string strName = vFields[0];
- if (!TimingResistantEqual(strName, strUser)) {
- continue;
- }
-
- std::string strSalt = vFields[1];
- std::string strHash = vFields[2];
-
- static const unsigned int KEY_SIZE = 32;
- unsigned char out[KEY_SIZE];
-
- CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
- std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
- std::string strHashFromPass = HexStr(hexvec);
-
- if (TimingResistantEqual(strHashFromPass, strHash)) {
- return true;
- }
+ std::vector<std::string> vFields;
+ boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
+ if (vFields.size() != 3) {
+ //Incorrect formatting in config file
+ continue;
+ }
+
+ std::string strName = vFields[0];
+ if (!TimingResistantEqual(strName, strUser)) {
+ continue;
+ }
+
+ std::string strSalt = vFields[1];
+ std::string strHash = vFields[2];
+
+ static const unsigned int KEY_SIZE = 32;
+ unsigned char out[KEY_SIZE];
+
+ CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
+ std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
+ std::string strHashFromPass = HexStr(hexvec);
+
+ if (TimingResistantEqual(strHashFromPass, strHash)) {
+ return true;
}
}
return false;
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 0d1cba3fd2..8841a4e9e7 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -21,13 +21,13 @@
#include <signal.h>
#include <future>
-#include <event2/event.h>
-#include <event2/http.h>
#include <event2/thread.h>
#include <event2/buffer.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>
+#include "support/events.h"
+
#ifdef EVENT__HAVE_NETINET_IN_H
#include <netinet/in.h>
#ifdef _XOPEN_SOURCE_EXTENDED
@@ -196,18 +196,16 @@ static bool InitHTTPAllowList()
LookupHost("::1", localv6, false);
rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet
rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost
- if (gArgs.IsArgSet("-rpcallowip")) {
- for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
- CSubNet subnet;
- LookupSubNet(strAllow.c_str(), subnet);
- if (!subnet.IsValid()) {
- uiInterface.ThreadSafeMessageBox(
- strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
- "", CClientUIInterface::MSG_ERROR);
- return false;
- }
- rpc_allow_subnets.push_back(subnet);
+ for (const std::string& strAllow : gArgs.GetArgs("-rpcallowip")) {
+ CSubNet subnet;
+ LookupSubNet(strAllow.c_str(), subnet);
+ if (!subnet.IsValid()) {
+ uiInterface.ThreadSafeMessageBox(
+ strprintf("Invalid -rpcallowip subnet specification: %s. Valid are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24).", strAllow),
+ "", CClientUIInterface::MSG_ERROR);
+ return false;
}
+ rpc_allow_subnets.push_back(subnet);
}
std::string strAllowed;
for (const CSubNet& subnet : rpc_allow_subnets)
@@ -367,9 +365,6 @@ static void libevent_log_cb(int severity, const char *msg)
bool InitHTTPServer()
{
- struct evhttp* http = 0;
- struct event_base* base = 0;
-
if (!InitHTTPAllowList())
return false;
@@ -395,17 +390,13 @@ bool InitHTTPServer()
evthread_use_pthreads();
#endif
- base = event_base_new(); // XXX RAII
- if (!base) {
- LogPrintf("Couldn't create an event_base: exiting\n");
- return false;
- }
+ raii_event_base base_ctr = obtain_event_base();
/* Create a new evhttp object to handle requests. */
- http = evhttp_new(base); // XXX RAII
+ raii_evhttp http_ctr = obtain_evhttp(base_ctr.get());
+ struct evhttp* http = http_ctr.get();
if (!http) {
LogPrintf("couldn't create evhttp. Exiting.\n");
- event_base_free(base);
return false;
}
@@ -416,8 +407,6 @@ bool InitHTTPServer()
if (!HTTPBindAddresses(http)) {
LogPrintf("Unable to bind any endpoint for RPC server\n");
- evhttp_free(http);
- event_base_free(base);
return false;
}
@@ -426,8 +415,9 @@ bool InitHTTPServer()
LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
- eventBase = base;
- eventHTTP = http;
+ // tranfer ownership to eventBase/HTTP via .release()
+ eventBase = base_ctr.release();
+ eventHTTP = http_ctr.release();
return true;
}
diff --git a/src/httpserver.h b/src/httpserver.h
index 6be9950682..9df56e5fc5 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -86,7 +86,7 @@ public:
/**
* Get the request header specified by hdr, or an empty string.
- * Return an pair (isPresent,string).
+ * Return a pair (isPresent,string).
*/
std::pair<bool, std::string> GetHeader(const std::string& hdr);
@@ -125,7 +125,7 @@ public:
virtual ~HTTPClosure() {}
};
-/** Event class. This can be used either as an cross-thread trigger or as a timer.
+/** Event class. This can be used either as a cross-thread trigger or as a timer.
*/
class HTTPEvent
{
diff --git a/src/init.cpp b/src/init.cpp
index ed7695344d..57232c7df3 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -88,14 +88,6 @@ static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
#define MIN_CORE_FILEDESCRIPTORS 150
#endif
-/** Used to pass flags to the Bind() function */
-enum BindFlags {
- BF_NONE = 0,
- BF_EXPLICIT = (1U << 0),
- BF_REPORT_ERROR = (1U << 1),
- BF_WHITELIST = (1U << 2),
-};
-
static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
//////////////////////////////////////////////////////////////////////////////
@@ -296,17 +288,6 @@ static void registerSignalHandler(int signal, void(*handler)(int))
}
#endif
-bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) {
- if (!(flags & BF_EXPLICIT) && IsLimited(addr))
- return false;
- std::string strError;
- if (!connman.BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
- if (flags & BF_REPORT_ERROR)
- return InitError(strError);
- return false;
- }
- return true;
-}
void OnRPCStarted()
{
uiInterface.NotifyBlockTip.connect(&RPCNotifyBlockChange);
@@ -822,7 +803,7 @@ int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = NODE_NETWORK;
-}
+} // namespace
[[noreturn]] static void new_handler_terminate()
{
@@ -844,8 +825,6 @@ bool AppInitBasicSetup()
// Turn off Microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
-#endif
-#if _MSC_VER >= 1400
// Disable confusing "helpful" text message on abort, Ctrl-C
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
@@ -900,10 +879,14 @@ bool AppInitParameterInteraction()
return InitError(_("Prune mode is incompatible with -txindex."));
}
+ // -bind and -whitebind can't be set when not listening
+ size_t nUserBind = gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size();
+ if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
+ return InitError("Cannot set -bind or -whitebind together with -listen=0");
+ }
+
// Make sure enough file descriptors are available
- int nBind = std::max(
- (gArgs.IsArgSet("-bind") ? gArgs.GetArgs("-bind").size() : 0) +
- (gArgs.IsArgSet("-whitebind") ? gArgs.GetArgs("-whitebind").size() : 0), size_t(1));
+ int nBind = std::max(nUserBind, size_t(1));
nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0);
@@ -935,15 +918,13 @@ bool AppInitParameterInteraction()
}
// Now remove the logging categories which were explicitly excluded
- if (gArgs.IsArgSet("-debugexclude")) {
- for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
- uint32_t flag = 0;
- if (!GetLogCategory(&flag, &cat)) {
- InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
- continue;
- }
- logCategories &= ~flag;
+ for (const std::string& cat : gArgs.GetArgs("-debugexclude")) {
+ uint32_t flag = 0;
+ if (!GetLogCategory(&flag, &cat)) {
+ InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat));
+ continue;
}
+ logCategories &= ~flag;
}
// Check for -debugnet
@@ -1030,14 +1011,7 @@ bool AppInitParameterInteraction()
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
- // Fee-per-kilobyte amount required for mempool acceptance and relay
- // If you are mining, be careful setting this:
- // if you set it to zero then
- // a transaction spammer can cheaply fill blocks using
- // 0-fee transactions. It should be set above the real
- // cost to you of processing a transaction.
- if (IsArgSet("-minrelaytxfee"))
- {
+ if (IsArgSet("-minrelaytxfee")) {
CAmount n = 0;
if (!ParseMoney(GetArg("-minrelaytxfee", ""), n)) {
return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
@@ -1260,13 +1234,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
- if (gArgs.IsArgSet("-uacomment")) {
- for (std::string cmt : gArgs.GetArgs("-uacomment"))
- {
- if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
- return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
- uacomments.push_back(cmt);
- }
+ for (const std::string& cmt : gArgs.GetArgs("-uacomment")) {
+ if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
+ return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt));
+ uacomments.push_back(cmt);
}
strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
@@ -1289,16 +1260,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (gArgs.IsArgSet("-whitelist")) {
- for (const std::string& net : gArgs.GetArgs("-whitelist")) {
- CSubNet subnet;
- LookupSubNet(net.c_str(), subnet);
- if (!subnet.IsValid())
- return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
- connman.AddWhitelistedRange(subnet);
- }
- }
-
// Check for host lookup allowed before parsing any network related parameters
fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
@@ -1349,44 +1310,12 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
fDiscover = GetBoolArg("-discover", true);
fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
- if (fListen) {
- bool fBound = false;
- if (gArgs.IsArgSet("-bind")) {
- for (const std::string& strBind : gArgs.GetArgs("-bind")) {
- CService addrBind;
- if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
- return InitError(ResolveErrMsg("bind", strBind));
- fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
- }
- }
- if (gArgs.IsArgSet("-whitebind")) {
- for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
- CService addrBind;
- if (!Lookup(strBind.c_str(), addrBind, 0, false))
- return InitError(ResolveErrMsg("whitebind", strBind));
- if (addrBind.GetPort() == 0)
- return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
- fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
- }
- }
- if (!gArgs.IsArgSet("-bind") && !gArgs.IsArgSet("-whitebind")) {
- struct in_addr inaddr_any;
- inaddr_any.s_addr = INADDR_ANY;
- fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE);
- fBound |= Bind(connman, CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
- }
- if (!fBound)
- return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
- }
-
- if (gArgs.IsArgSet("-externalip")) {
- for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
- CService addrLocal;
- if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
- AddLocal(addrLocal, LOCAL_MANUAL);
- else
- return InitError(ResolveErrMsg("externalip", strAddr));
- }
+ for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
+ CService addrLocal;
+ if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
+ AddLocal(addrLocal, LOCAL_MANUAL);
+ else
+ return InitError(ResolveErrMsg("externalip", strAddr));
}
#if ENABLE_ZMQ
@@ -1615,10 +1544,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
std::vector<fs::path> vImportFiles;
- if (gArgs.IsArgSet("-loadblock"))
- {
- for (const std::string& strFile : gArgs.GetArgs("-loadblock"))
- vImportFiles.push_back(strFile);
+ for (const std::string& strFile : gArgs.GetArgs("-loadblock")) {
+ vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
@@ -1645,7 +1572,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Map ports with UPnP
MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
- std::string strNodeError;
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
connOptions.nRelevantServices = nRelevantServices;
@@ -1661,12 +1587,39 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
+ for (const std::string& strBind : gArgs.GetArgs("-bind")) {
+ CService addrBind;
+ if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) {
+ return InitError(ResolveErrMsg("bind", strBind));
+ }
+ connOptions.vBinds.push_back(addrBind);
+ }
+ for (const std::string& strBind : gArgs.GetArgs("-whitebind")) {
+ CService addrBind;
+ if (!Lookup(strBind.c_str(), addrBind, 0, false)) {
+ return InitError(ResolveErrMsg("whitebind", strBind));
+ }
+ if (addrBind.GetPort() == 0) {
+ return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
+ }
+ connOptions.vWhiteBinds.push_back(addrBind);
+ }
+
+ for (const auto& net : gArgs.GetArgs("-whitelist")) {
+ CSubNet subnet;
+ LookupSubNet(net.c_str(), subnet);
+ if (!subnet.IsValid())
+ return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
+ connOptions.vWhitelistedRange.push_back(subnet);
+ }
+
if (gArgs.IsArgSet("-seednode")) {
connOptions.vSeedNodes = gArgs.GetArgs("-seednode");
}
- if (!connman.Start(scheduler, strNodeError, connOptions))
- return InitError(strNodeError);
+ if (!connman.Start(scheduler, connOptions)) {
+ return false;
+ }
// ********************************************************* Step 12: finished
diff --git a/src/leveldb/db/version_set.h b/src/leveldb/db/version_set.h
index c4e7ac360b..7935a965a7 100644
--- a/src/leveldb/db/version_set.h
+++ b/src/leveldb/db/version_set.h
@@ -376,7 +376,7 @@ class Compaction {
// Each compaction reads inputs from "level_" and "level_+1"
std::vector<FileMetaData*> inputs_[2]; // The two sets of inputs
- // State used to check for number of of overlapping grandparent files
+ // State used to check for number of overlapping grandparent files
// (parent == level_ + 1, grandparent == level_ + 2)
std::vector<FileMetaData*> grandparents_;
size_t grandparent_index_; // Index in grandparent_starts_
diff --git a/src/net.cpp b/src/net.cpp
index 73f020273b..301cf58b87 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -64,6 +64,14 @@
#endif
#endif
+/** Used to pass flags to the Bind() function */
+enum BindFlags {
+ BF_NONE = 0,
+ BF_EXPLICIT = (1U << 0),
+ BF_REPORT_ERROR = (1U << 1),
+ BF_WHITELIST = (1U << 2),
+};
+
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
@@ -240,7 +248,7 @@ bool RemoveLocal(const CService& addr)
/** Make a particular network entirely off-limits (no automatic connects to it) */
void SetLimited(enum Network net, bool fLimited)
{
- if (net == NET_UNROUTABLE)
+ if (net == NET_UNROUTABLE || net == NET_INTERNAL)
return;
LOCK(cs_mapLocalHost);
vfLimited[net] = fLimited;
@@ -601,7 +609,6 @@ void CConnman::SetBannedSetDirty(bool dirty)
bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
- LOCK(cs_vWhitelistedRange);
for (const CSubNet& subnet : vWhitelistedRange) {
if (subnet.Match(addr))
return true;
@@ -609,12 +616,6 @@ bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
return false;
}
-void CConnman::AddWhitelistedRange(const CSubNet &subnet) {
- LOCK(cs_vWhitelistedRange);
- vWhitelistedRange.push_back(subnet);
-}
-
-
std::string CNode::GetAddrName() const {
LOCK(cs_addrName);
return addrName;
@@ -1604,7 +1605,12 @@ void CConnman::ThreadDNSAddressSeed()
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
ServiceFlags requiredServiceBits = nRelevantServices;
- if (LookupHost(GetDNSHost(seed, &requiredServiceBits).c_str(), vIPs, 0, true))
+ std::string host = GetDNSHost(seed, &requiredServiceBits);
+ CNetAddr resolveSource;
+ if (!resolveSource.SetInternal(host)) {
+ continue;
+ }
+ if (LookupHost(host.c_str(), vIPs, 0, true))
{
for (const CNetAddr& ip : vIPs)
{
@@ -1614,18 +1620,7 @@ void CConnman::ThreadDNSAddressSeed()
vAdd.push_back(addr);
found++;
}
- }
- if (interruptNet) {
- return;
- }
- // TODO: The seed name resolve may fail, yielding an IP of [::], which results in
- // addrman assigning the same source to results from different seeds.
- // This should switch to a hard-coded stable dummy IP for each seed name, so that the
- // resolve is not required at all.
- if (!vIPs.empty()) {
- CService seedSource;
- Lookup(seed.name.c_str(), seedSource, 0, true);
- addrman.Add(vAdd, seedSource);
+ addrman.Add(vAdd, resolveSource);
}
}
}
@@ -1682,7 +1677,7 @@ void CConnman::ProcessOneShot()
void CConnman::ThreadOpenConnections()
{
// Connect to specific addresses
- if (gArgs.IsArgSet("-connect") && gArgs.GetArgs("-connect").size() > 0)
+ if (gArgs.IsArgSet("-connect"))
{
for (int64_t nLoop = 0;; nLoop++)
{
@@ -1724,7 +1719,7 @@ void CConnman::ThreadOpenConnections()
if (!done) {
LogPrintf("Adding fixed seed nodes as DNS doesn't seem to be available.\n");
CNetAddr local;
- LookupHost("127.0.0.1", local, false);
+ local.SetInternal("fixedseeds");
addrman.Add(convertSeed6(Params().FixedSeeds()), local);
done = true;
}
@@ -1908,8 +1903,7 @@ void CConnman::ThreadOpenAddedConnections()
{
{
LOCK(cs_vAddedNodes);
- if (gArgs.IsArgSet("-addnode"))
- vAddedNodes = gArgs.GetArgs("-addnode");
+ vAddedNodes = gArgs.GetArgs("-addnode");
}
while (true)
@@ -2226,7 +2220,38 @@ NodeId CConnman::GetNewNodeId()
return nLastNodeId.fetch_add(1, std::memory_order_relaxed);
}
-bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options connOptions)
+
+bool CConnman::Bind(const CService &addr, unsigned int flags) {
+ if (!(flags & BF_EXPLICIT) && IsLimited(addr))
+ return false;
+ std::string strError;
+ if (!BindListenPort(addr, strError, (flags & BF_WHITELIST) != 0)) {
+ if ((flags & BF_REPORT_ERROR) && clientInterface) {
+ clientInterface->ThreadSafeMessageBox(strError, "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
+ return true;
+}
+
+bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds) {
+ bool fBound = false;
+ for (const auto& addrBind : binds) {
+ fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
+ }
+ for (const auto& addrBind : whiteBinds) {
+ fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
+ }
+ if (binds.empty() && whiteBinds.empty()) {
+ struct in_addr inaddr_any;
+ inaddr_any.s_addr = INADDR_ANY;
+ fBound |= Bind(CService(in6addr_any, GetListenPort()), BF_NONE);
+ fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE);
+ }
+ return fBound;
+}
+
+bool CConnman::Start(CScheduler& scheduler, Options connOptions)
{
nTotalBytesRecv = 0;
nTotalBytesSent = 0;
@@ -2248,11 +2273,23 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c
SetBestHeight(connOptions.nBestHeight);
+ clientInterface = connOptions.uiInterface;
+
+ if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
+ if (clientInterface) {
+ clientInterface->ThreadSafeMessageBox(
+ _("Failed to listen on any port. Use -listen=0 if you want this."),
+ "", CClientUIInterface::MSG_ERROR);
+ }
+ return false;
+ }
+
+ vWhitelistedRange = connOptions.vWhitelistedRange;
+
for (const auto& strDest : connOptions.vSeedNodes) {
AddOneShot(strDest);
}
- clientInterface = connOptions.uiInterface;
if (clientInterface) {
clientInterface->InitMessage(_("Loading P2P addresses..."));
}
diff --git a/src/net.h b/src/net.h
index a6aea189f9..dc25e7a5dd 100644
--- a/src/net.h
+++ b/src/net.h
@@ -144,13 +144,14 @@ public:
uint64_t nMaxOutboundTimeframe = 0;
uint64_t nMaxOutboundLimit = 0;
std::vector<std::string> vSeedNodes;
+ std::vector<CSubNet> vWhitelistedRange;
+ std::vector<CService> vBinds, vWhiteBinds;
};
CConnman(uint64_t seed0, uint64_t seed1);
~CConnman();
- bool Start(CScheduler& scheduler, std::string& strNodeError, Options options);
+ bool Start(CScheduler& scheduler, Options options);
void Stop();
void Interrupt();
- bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
bool GetNetworkActive() const { return fNetworkActive; };
void SetNetworkActive(bool active);
bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);
@@ -244,8 +245,6 @@ public:
unsigned int GetSendBufferSize() const;
- void AddWhitelistedRange(const CSubNet &subnet);
-
ServiceFlags GetLocalServices() const;
//!set the max outbound target in bytes
@@ -289,6 +288,9 @@ private:
ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
};
+ bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
+ bool Bind(const CService &addr, unsigned int flags);
+ bool InitBinds(const std::vector<CService>& binds, const std::vector<CService>& whiteBinds);
void ThreadOpenAddedConnections();
void AddOneShot(const std::string& strDest);
void ProcessOneShot();
@@ -346,7 +348,6 @@ private:
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
std::vector<CSubNet> vWhitelistedRange;
- CCriticalSection cs_vWhitelistedRange;
unsigned int nSendBufferMaxSize;
unsigned int nReceiveFloodSize;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 91681265b1..8fc6f6f95e 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -120,7 +120,7 @@ namespace {
MapRelay mapRelay;
/** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */
std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration;
-} // anon namespace
+} // namespace
//////////////////////////////////////////////////////////////////////////////
//
@@ -559,7 +559,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
}
}
-} // anon namespace
+} // namespace
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main);
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 34a7029862..89f257c642 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -15,6 +15,9 @@
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
+// 0xFD + sha256("bitcoin")[0:5]
+static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
+
void CNetAddr::Init()
{
memset(ip, 0, sizeof(ip));
@@ -42,6 +45,18 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
}
}
+bool CNetAddr::SetInternal(const std::string &name)
+{
+ if (name.empty()) {
+ return false;
+ }
+ unsigned char hash[32] = {};
+ CSHA256().Write((const unsigned char*)name.data(), name.size()).Finalize(hash);
+ memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
+ memcpy(ip + sizeof(g_internal_prefix), hash, sizeof(ip) - sizeof(g_internal_prefix));
+ return true;
+}
+
bool CNetAddr::SetSpecial(const std::string &strName)
{
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
@@ -84,7 +99,7 @@ bool CNetAddr::IsIPv4() const
bool CNetAddr::IsIPv6() const
{
- return (!IsIPv4() && !IsTor());
+ return (!IsIPv4() && !IsTor() && !IsInternal());
}
bool CNetAddr::IsRFC1918() const
@@ -199,6 +214,9 @@ bool CNetAddr::IsValid() const
if (IsRFC3849())
return false;
+ if (IsInternal())
+ return false;
+
if (IsIPv4())
{
// INADDR_NONE
@@ -217,11 +235,19 @@ bool CNetAddr::IsValid() const
bool CNetAddr::IsRoutable() const
{
- return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal());
+ return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
+}
+
+bool CNetAddr::IsInternal() const
+{
+ return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
}
enum Network CNetAddr::GetNetwork() const
{
+ if (IsInternal())
+ return NET_INTERNAL;
+
if (!IsRoutable())
return NET_UNROUTABLE;
@@ -238,6 +264,8 @@ std::string CNetAddr::ToStringIP() const
{
if (IsTor())
return EncodeBase32(&ip[6], 10) + ".onion";
+ if (IsInternal())
+ return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
CService serv(*this, 0);
struct sockaddr_storage sockaddr;
socklen_t socklen = sizeof(sockaddr);
@@ -305,9 +333,15 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nClass = 255;
nBits = 0;
}
-
- // all unroutable addresses belong to the same group
- if (!IsRoutable())
+ // all internal-usage addresses get their own group
+ if (IsInternal())
+ {
+ nClass = NET_INTERNAL;
+ nStartByte = sizeof(g_internal_prefix);
+ nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
+ }
+ // all other unroutable addresses belong to the same group
+ else if (!IsRoutable())
{
nClass = NET_UNROUTABLE;
nBits = 0;
@@ -393,7 +427,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
REACH_PRIVATE
};
- if (!IsRoutable())
+ if (!IsRoutable() || IsInternal())
return REACH_UNREACHABLE;
int ourNet = GetExtNetwork(this);
@@ -552,7 +586,7 @@ std::string CService::ToStringPort() const
std::string CService::ToStringIPPort() const
{
- if (IsIPv4() || IsTor()) {
+ if (IsIPv4() || IsTor() || IsInternal()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
diff --git a/src/netaddress.h b/src/netaddress.h
index fbc4d1a65f..80716600d1 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -22,6 +22,7 @@ enum Network
NET_IPV4,
NET_IPV6,
NET_TOR,
+ NET_INTERNAL,
NET_MAX,
};
@@ -45,6 +46,12 @@ class CNetAddr
*/
void SetRaw(Network network, const uint8_t *data);
+ /**
+ * Transform an arbitrary string into a non-routable ipv6 address.
+ * Useful for mapping resolved addresses back to their source.
+ */
+ bool SetInternal(const std::string& name);
+
bool SetSpecial(const std::string &strName); // for Tor addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
@@ -64,6 +71,7 @@ class CNetAddr
bool IsTor() const;
bool IsLocal() const;
bool IsRoutable() const;
+ bool IsInternal() const;
bool IsValid() const;
enum Network GetNetwork() const;
std::string ToString() const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 32557dd179..a23f92e1ed 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -108,17 +108,22 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
struct addrinfo *aiTrav = aiRes;
while (aiTrav != NULL && (nMaxSolutions == 0 || vIP.size() < nMaxSolutions))
{
+ CNetAddr resolved;
if (aiTrav->ai_family == AF_INET)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in));
- vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
+ resolved = CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr);
}
if (aiTrav->ai_family == AF_INET6)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr;
- vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id));
+ resolved = CNetAddr(s6->sin6_addr, s6->sin6_scope_id);
+ }
+ /* Never allow resolving to an internal address. Consider any such result invalid */
+ if (!resolved.IsInternal()) {
+ vIP.push_back(resolved);
}
aiTrav = aiTrav->ai_next;
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 7125a74f03..2029ce3744 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -48,7 +48,7 @@ class TxConfirmStats;
* in each bucket and the total amount of feerate paid in each bucket. Then we
* calculate how many blocks Y it took each transaction to be mined. We convert
* from a number of blocks to a number of periods Y' each encompassing "scale"
- * blocks. This is is tracked in 3 different data sets each up to a maximum
+ * blocks. This is tracked in 3 different data sets each up to a maximum
* number of periods. Within each data set we have an array of counters in each
* feerate bucket and we increment all the counters from Y' up to max periods
* representing that a tx was successfully confirmed in less than or equal to
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 6cd246ed53..da87e40091 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -39,7 +39,7 @@ const char *SENDCMPCT="sendcmpct";
const char *CMPCTBLOCK="cmpctblock";
const char *GETBLOCKTXN="getblocktxn";
const char *BLOCKTXN="blocktxn";
-};
+} // namespace NetMsgType
/** All known message types. Keep this in the same order as the list of
* messages above and in protocol.h.
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index e57fa238cb..a16457ea4e 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -11,7 +11,7 @@ namespace
{
/* Global secp256k1_context object used for verification. */
secp256k1_context* secp256k1_context_verify = NULL;
-}
+} // namespace
/** This function is taken from the libsecp256k1 distribution and implements
* DER parsing for ECDSA signatures, while supporting an arbitrary subset of
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index de00eacdb9..33f4535ee2 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -26,7 +26,6 @@
class CBlockIndex;
-static const int64_t nClientStartupTime = GetTime();
static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;
@@ -238,7 +237,7 @@ bool ClientModel::isReleaseVersion() const
QString ClientModel::formatClientStartupTime() const
{
- return QDateTime::fromTime_t(nClientStartupTime).toString();
+ return QDateTime::fromTime_t(GetStartupTime()).toString();
}
QString ClientModel::dataDir() const
@@ -303,7 +302,7 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB
}
// if we are in-sync, update the UI regardless of last update time
if (!initialSync || now - nLastUpdateNotification > MODEL_UPDATE_DELAY) {
- //pass a async signal to the UI thread
+ //pass an async signal to the UI thread
QMetaObject::invokeMethod(clientmodel, "numBlocksChanged", Qt::QueuedConnection,
Q_ARG(int, pIndex->nHeight),
Q_ARG(QDateTime, QDateTime::fromTime_t(pIndex->GetBlockTime())),
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index b9da48ee1d..af9a888d94 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -499,7 +499,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
{
// there is some fudging in these numbers related to the actual virtual transaction size calculation that will keep this estimate from being exact.
// usually, the result will be an overestimate within a couple of satoshis so that the confirmation dialog ends up displaying a slightly smaller fee.
- // also, the witness stack size value value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit.
+ // also, the witness stack size value is a variable sized integer. usually, the number of stack items will be well under the single byte var int limit.
nBytes += 2; // account for the serialized marker and flag bytes
nBytes += nQuantity; // account for the witness byte that holds the number of stack items for each input.
}
@@ -524,13 +524,10 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
if (IsDust(txout, ::dustRelayFee))
{
- if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
- nChange = GetDustThreshold(txout, ::dustRelayFee);
- else
- {
- nPayFee += nChange;
- nChange = 0;
- }
+ nPayFee += nChange;
+ nChange = 0;
+ if (CoinControlDialog::fSubtractFeeFromAmount)
+ nBytes -= 34; // we didn't detect lack of change above
}
}
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 0f1b3f4a73..14078b9ee8 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -315,7 +315,7 @@
<bool>false</bool>
</property>
<property name="toolTip">
- <string>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
+ <string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
@@ -338,7 +338,7 @@
<bool>false</bool>
</property>
<property name="toolTip">
- <string>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
+ <string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
@@ -361,7 +361,7 @@
<bool>false</bool>
</property>
<property name="toolTip">
- <string>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
+ <string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index 4779ffa43f..a83f285034 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -126,7 +126,7 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
return;
// estimate the number of headers left based on nPowTargetSpacing
- // and check if the gui is not aware of the the best header (happens rarely)
+ // and check if the gui is not aware of the best header (happens rarely)
int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
bool hasBestHeader = bestHeaderHeight >= count;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index b17693e1ca..ec0580b81c 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -672,7 +672,7 @@ void RPCConsole::setFontSize(int newSize)
{
QSettings settings;
- //don't allow a insane font size
+ //don't allow an insane font size
if (newSize < FONT_RANGE.width() || newSize > FONT_RANGE.height())
return;
@@ -738,7 +738,7 @@ void RPCConsole::clear(bool clearHistory)
tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
tr("Type <b>help</b> for an overview of available commands.")) +
"<br><span class=\"secwarning\">" +
- tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.") +
+ tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
"</span>",
true);
}
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 449eb1ae58..6538a80233 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -339,7 +339,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
transaction_array.append(&(ssTx[0]), ssTx.size());
}
- // Add addresses / update labels that we've sent to to the address book,
+ // Add addresses / update labels that we've sent to the address book,
// and emit coinsSent signal for each recipient
for (const SendCoinsRecipient &rcp : transaction.getRecipients())
{
diff --git a/src/rest.cpp b/src/rest.cpp
index 8fb0c13fa5..33e3fb4529 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -413,7 +413,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
boost::split(uriParts, strUriParams, boost::is_any_of("/"));
}
- // throw exception in case of a empty request
+ // throw exception in case of an empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index c5585a9fba..cb1539dce5 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -76,6 +76,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listunspent", 0, "minconf" },
{ "listunspent", 1, "maxconf" },
{ "listunspent", 2, "addresses" },
+ { "listunspent", 3, "include_unsafe" },
{ "listunspent", 4, "query_options" },
{ "getblock", 1, "verbosity" },
{ "getblockheader", 1, "verbose" },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 3b212dc0e4..8c682592c5 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -722,19 +722,16 @@ protected:
UniValue submitblock(const JSONRPCRequest& request)
{
+ // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored.
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw std::runtime_error(
- "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n"
+ "submitblock \"hexdata\" ( \"dummy\" )\n"
"\nAttempts to submit new block to network.\n"
- "The 'jsonparametersobject' parameter is currently ignored.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
"\nArguments\n"
"1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
- "2. \"parameters\" (string, optional) object of optional parameters\n"
- " {\n"
- " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n"
- " }\n"
+ "2. \"dummy\" (optional) dummy value, for compatibility with BIP22. This value is ignored.\n"
"\nResult:\n"
"\nExamples:\n"
+ HelpExampleCli("submitblock", "\"mydata\"")
@@ -963,7 +960,7 @@ static const CRPCCommand commands[] =
{ "mining", "getmininginfo", &getmininginfo, true, {} },
{ "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","dummy","fee_delta"} },
{ "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
- { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} },
+ { "mining", "submitblock", &submitblock, true, {"hexdata","dummy"} },
{ "generating", "generate", &generate, true, {"nblocks","maxtries"} },
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index d6f9f0059c..5cab0ad5bd 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -75,7 +75,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
- " \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
+ " \"addr\":\"host:port\", (string) The IP address and port of the peer\n"
" \"addrbind\":\"ip:port\", (string) Bind address of the connection to the peer\n"
" \"addrlocal\":\"ip:port\", (string) Local address as reported by the peer\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
@@ -199,7 +199,7 @@ UniValue addnode(const JSONRPCRequest& request)
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
throw std::runtime_error(
"addnode \"node\" \"add|remove|onetry\"\n"
- "\nAttempts add or remove a node from the addnode list.\n"
+ "\nAttempts to add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
"\nArguments:\n"
"1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
@@ -290,7 +290,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request)
"\nResult:\n"
"[\n"
" {\n"
- " \"addednode\" : \"192.168.0.201\", (string) The node ip address or name (as provided to addnode)\n"
+ " \"addednode\" : \"192.168.0.201\", (string) The node IP address or name (as provided to addnode)\n"
" \"connected\" : true|false, (boolean) If connected\n"
" \"addresses\" : [ (list of objects) Only when connected = true\n"
" {\n"
@@ -397,7 +397,7 @@ static UniValue GetNetworksInfo()
for(int n=0; n<NET_MAX; ++n)
{
enum Network network = static_cast<enum Network>(n);
- if(network == NET_UNROUTABLE)
+ if(network == NET_UNROUTABLE || network == NET_INTERNAL)
continue;
proxyType proxy;
UniValue obj(UniValue::VOBJ);
@@ -497,12 +497,12 @@ UniValue setban(const JSONRPCRequest& request)
(strCommand != "add" && strCommand != "remove"))
throw std::runtime_error(
"setban \"subnet\" \"add|remove\" (bantime) (absolute)\n"
- "\nAttempts add or remove a IP/Subnet from the banned list.\n"
+ "\nAttempts to add or remove an IP/Subnet from the banned list.\n"
"\nArguments:\n"
- "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
- "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n"
- "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
- "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
+ "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)\n"
+ "2. \"command\" (string, required) 'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list\n"
+ "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
+ "4. \"absolute\" (boolean, optional) If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
"\nExamples:\n"
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 1a04ce2b47..c320d20453 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -258,6 +258,22 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
return "Bitcoin server stopping";
}
+UniValue uptime(const JSONRPCRequest& jsonRequest)
+{
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
+ throw std::runtime_error(
+ "uptime\n"
+ "\nReturns the total uptime of the server.\n"
+ "\nResult:\n"
+ "ttt (numeric) The number of seconds that the server has been running\n"
+ "\nExamples:\n"
+ + HelpExampleCli("uptime", "")
+ + HelpExampleRpc("uptime", "")
+ );
+
+ return GetTime() - GetStartupTime();
+}
+
/**
* Call Table
*/
@@ -267,6 +283,7 @@ static const CRPCCommand vRPCCommands[] =
/* Overall control/query calls */
{ "control", "help", &help, true, {"command"} },
{ "control", "stop", &stop, true, {} },
+ { "control", "uptime", &uptime, true, {} },
};
CRPCTable::CRPCTable()
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index c4ab441e2c..4b71a42cdf 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -68,7 +68,7 @@ struct ECCryptoClosure
};
ECCryptoClosure instance_of_eccryptoclosure;
-}
+} // namespace
/** Check that all specified flags are part of the libconsensus interface. */
static bool verify_flags(unsigned int flags)
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 222cff59ea..7149c938fc 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -31,7 +31,7 @@ inline bool set_error(ScriptError* ret, const ScriptError serror)
return false;
}
-} // anon namespace
+} // namespace
bool CastToBool(const valtype& vch)
{
@@ -1164,7 +1164,7 @@ uint256 GetOutputsHash(const CTransaction& txTo) {
return ss.GetHash();
}
-} // anon namespace
+} // namespace
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
{
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 7bb8d9941b..befc5f5233 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -66,7 +66,7 @@ public:
* signatureCache could be made local to VerifySignature.
*/
static CSignatureCache signatureCache;
-}
+} // namespace
// To be called once in AppInitMain/BasicTestingSetup to initialize the
// signatureCache.
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index f4a32472b0..4b01a6de94 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -399,7 +399,7 @@ public:
}
};
const DummySignatureChecker dummyChecker;
-}
+} // namespace
const BaseSignatureChecker& DummySignatureCreator::Checker() const
{
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 7efcad7b0f..8e08acf0c6 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -273,7 +273,7 @@ public:
return true;
}
};
-}
+} // namespace
CScript GetScriptForDestination(const CTxDestination& dest)
{
diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage
index ab580c5b23..5198724bea 100644
--- a/src/secp256k1/sage/group_prover.sage
+++ b/src/secp256k1/sage/group_prover.sage
@@ -3,7 +3,7 @@
# to independently set assumptions on input or intermediary variables.
#
# The general approach is:
-# * A constraint is a tuple of two sets of of symbolic expressions:
+# * A constraint is a tuple of two sets of symbolic expressions:
# the first of which are required to evaluate to zero, the second of which
# are required to evaluate to nonzero.
# - A constraint is said to be conflicting if any of its nonzero expressions
diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s
index 5df561f2fc..bd2b629e1c 100644
--- a/src/secp256k1/src/asm/field_10x26_arm.s
+++ b/src/secp256k1/src/asm/field_10x26_arm.s
@@ -11,7 +11,7 @@ Note:
- To avoid unnecessary loads and make use of available registers, two
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
- which will be added to c and d respectively in the the even passes
+ which will be added to c and d respectively in the even passes
*/
diff --git a/src/support/events.h b/src/support/events.h
index 4f2f3cf9ef..90690876ee 100644
--- a/src/support/events.h
+++ b/src/support/events.h
@@ -27,26 +27,26 @@ MAKE_RAII(evhttp);
MAKE_RAII(evhttp_request);
MAKE_RAII(evhttp_connection);
-raii_event_base obtain_event_base() {
+inline raii_event_base obtain_event_base() {
auto result = raii_event_base(event_base_new());
if (!result.get())
throw std::runtime_error("cannot create event_base");
return result;
}
-raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {
+inline raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {
return raii_event(event_new(base, s, events, cb, arg));
}
-raii_evhttp obtain_evhttp(struct event_base* base) {
+inline raii_evhttp obtain_evhttp(struct event_base* base) {
return raii_evhttp(evhttp_new(base));
}
-raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {
+inline raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {
return raii_evhttp_request(evhttp_request_new(cb, arg));
}
-raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {
+inline raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {
auto result = raii_evhttp_connection(evhttp_connection_base_new(base, NULL, host.c_str(), port));
if (!result.get())
throw std::runtime_error("create connection failed");
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 45ae7d4636..2c98fbcfd6 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ -
// Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each
-// element of Aarray and Barray, and then converting the result into a arith_uint256.
+// element of Aarray and Barray, and then converting the result into an arith_uint256.
#define CHECKBITWISEOPERATOR(_A_,_B_,_OP_) \
for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; } \
BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (_A_##L _OP_ _B_##L));
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 33abfabe6b..e24431528a 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -50,12 +50,6 @@ public:
return true;
}
- bool HaveCoin(const COutPoint& outpoint) const override
- {
- Coin coin;
- return GetCoin(outpoint, coin);
- }
-
uint256 GetBestBlock() const override { return hashBestBlock_; }
bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) override
@@ -99,7 +93,7 @@ public:
size_t& usage() { return cachedCoinsUsage; }
};
-}
+} // namespace
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
@@ -147,8 +141,22 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
{
uint256 txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration.
Coin& coin = result[COutPoint(txid, 0)];
+
+ // Determine whether to test HaveCoin before or after Access* (or both). As these functions
+ // can influence each other's behaviour by pulling things into the cache, all combinations
+ // are tested.
+ bool test_havecoin_before = InsecureRandBits(2) == 0;
+ bool test_havecoin_after = InsecureRandBits(2) == 0;
+
+ bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false;
const Coin& entry = (InsecureRandRange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
BOOST_CHECK(coin == entry);
+ BOOST_CHECK(!test_havecoin_before || result_havecoin == !entry.IsSpent());
+
+ if (test_havecoin_after) {
+ bool ret = stack.back()->HaveCoin(COutPoint(txid, 0));
+ BOOST_CHECK(ret == !entry.IsSpent());
+ }
if (InsecureRandRange(5) == 0 || coin.IsSpent()) {
Coin newcoin;
@@ -628,7 +636,7 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
- CheckAccessCoin(PRUNED, ABSENT, PRUNED, NO_ENTRY , FRESH );
+ CheckAccessCoin(PRUNED, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index e35a7ce569..0390d6806d 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -2506,7 +2506,7 @@
],
["CHECKSEQUENCEVERIFY tests"],
-["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"],
+["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on an empty stack"],
["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"],
["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"],
["0", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "UNSATISFIED_LOCKTIME", "CSV fails if stack top bit 1 << 31 is set and the tx version < 2"],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index d70fa54333..e6b382af13 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -174,7 +174,7 @@
[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]],
"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"],
-["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
+["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."],
["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"],
[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"],
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index e4b4b85720..b45a7fcc57 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -25,6 +25,13 @@ static CSubNet ResolveSubNet(const char* subnet)
return ret;
}
+static CNetAddr CreateInternal(const char* host)
+{
+ CNetAddr addr;
+ addr.SetInternal(host);
+ return addr;
+}
+
BOOST_AUTO_TEST_CASE(netbase_networks)
{
BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
@@ -32,6 +39,7 @@ BOOST_AUTO_TEST_CASE(netbase_networks)
BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4);
BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6);
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
+ BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);
}
@@ -58,6 +66,8 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable());
BOOST_CHECK(ResolveIP("2001::1").IsRoutable());
BOOST_CHECK(ResolveIP("127.0.0.1").IsValid());
+ BOOST_CHECK(CreateInternal("FD6B:88C0:8724:edb1:8e4:3588:e546:35ca").IsInternal());
+ BOOST_CHECK(CreateInternal("bar.com").IsInternal());
}
@@ -103,6 +113,11 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
BOOST_CHECK(TestParse(":::", "[::]:0"));
+
+ // verify that an internal address fails to resolve
+ BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0"));
+ // and that a one-off resolves correctly
+ BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]", "[fd6c:88c0:8724:1:2:3:4:5]:65535"));
}
BOOST_AUTO_TEST_CASE(onioncat_test)
@@ -281,6 +296,9 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
BOOST_CHECK(ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 4, 112, 175})); //he.net
BOOST_CHECK(ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == std::vector<unsigned char>({(unsigned char)NET_IPV6, 32, 1, 32, 1})); //IPv6
+ // baz.net sha256 hash: 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
+ std::vector<unsigned char> internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb, 0x46, 0x07, 0xc4, 0xac, 0x07};
+ BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 2ff4f4227e..1bb191c73d 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -468,7 +468,7 @@ std::string JSONPrettyPrint(const UniValue& univalue)
}
return ret;
}
-}
+} // namespace
BOOST_AUTO_TEST_CASE(script_build)
{
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index eb0722cd81..4cd64bf028 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -407,7 +407,7 @@ static bool WriteBinaryFile(const fs::path &filename, const std::string &data)
/****** Bitcoin specific TorController implementation ********/
/** Controller that connects to Tor control socket, authenticate, then create
- * and maintain a ephemeral hidden service.
+ * and maintain an ephemeral hidden service.
*/
class TorController
{
diff --git a/src/txdb.cpp b/src/txdb.cpp
index c8f5090293..97e916fd22 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -210,7 +210,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
return true;
}
-bool CBlockTreeDB::LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
+bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
std::unique_ptr<CDBIterator> pcursor(NewIterator());
@@ -238,12 +238,12 @@ bool CBlockTreeDB::LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)
pindexNew->nStatus = diskindex.nStatus;
pindexNew->nTx = diskindex.nTx;
- if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
- return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());
+ if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
+ return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
pcursor->Next();
} else {
- return error("LoadBlockIndex() : failed to read value");
+ return error("%s: failed to read value", __func__);
}
} else {
break;
diff --git a/src/txdb.h b/src/txdb.h
index 974dd4ebe3..2a3e4eb696 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -122,7 +122,7 @@ public:
bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
- bool LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)> insertBlockIndex);
+ bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex);
};
#endif // BITCOIN_TXDB_H
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 304300239c..dcfc5ffde0 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -122,7 +122,7 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes
// accounted for in the state of their ancestors)
std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end());
- // Iterate in reverse, so that whenever we are looking at at a transaction
+ // Iterate in reverse, so that whenever we are looking at a transaction
// we are sure that all in-mempool descendants have already been processed.
// This maximizes the benefit of the descendant cache and guarantees that
// setMemPoolChildren will be updated, an assumption made in
@@ -769,7 +769,7 @@ public:
return counta < countb;
}
};
-}
+} // namespace
std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::GetSortedDepthAndScore() const
{
@@ -903,11 +903,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
return false;
}
}
- return (base->GetCoin(outpoint, coin) && !coin.IsSpent());
-}
-
-bool CCoinsViewMemPool::HaveCoin(const COutPoint &outpoint) const {
- return mempool.exists(outpoint) || base->HaveCoin(outpoint);
+ return base->GetCoin(outpoint, coin);
}
size_t CTxMemPool::DynamicMemoryUsage() const {
diff --git a/src/txmempool.h b/src/txmempool.h
index 7ca3b18a1e..78ac3c209b 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -684,8 +684,7 @@ protected:
public:
CCoinsViewMemPool(CCoinsView* baseIn, const CTxMemPool& mempoolIn);
- bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
- bool HaveCoin(const COutPoint &outpoint) const;
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
};
/**
diff --git a/src/util.cpp b/src/util.cpp
index 20a8082017..b76c173f90 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -84,6 +84,8 @@
#include <openssl/rand.h>
#include <openssl/conf.h>
+// Application startup time (used for uptime calculation)
+const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
const char * const BITCOIN_PID_FILENAME = "bitcoind.pid";
@@ -420,7 +422,9 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg)
{
LOCK(cs_args);
- return mapMultiArgs.at(strArg);
+ if (IsArgSet(strArg))
+ return mapMultiArgs.at(strArg);
+ return {};
}
bool ArgsManager::IsArgSet(const std::string& strArg)
@@ -889,3 +893,9 @@ std::string CopyrightHolders(const std::string& strPrefix)
}
return strCopyrightHolders;
}
+
+// Obtain the application startup time (used for uptime calculation)
+int64_t GetStartupTime()
+{
+ return nStartupTime;
+}
diff --git a/src/util.h b/src/util.h
index f40db84a10..824ad51ac4 100644
--- a/src/util.h
+++ b/src/util.h
@@ -5,7 +5,7 @@
/**
* Server/client environment: argument handling, config file parsing,
- * logging, thread wrappers
+ * logging, thread wrappers, startup time
*/
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
@@ -29,6 +29,9 @@
#include <boost/signals2/signal.hpp>
+// Application startup time (used for uptime calculation)
+int64_t GetStartupTime();
+
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
@@ -122,6 +125,17 @@ int LogPrintStr(const std::string &str);
/** Get format string from VA_ARGS for error reporting */
template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; }
+static inline void MarkUsed() {}
+template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args)
+{
+ (void)t;
+ MarkUsed(args...);
+}
+
+#ifdef USE_COVERAGE
+#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0)
+#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0)
+#else
#define LogPrintf(...) do { \
std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \
try { \
@@ -138,6 +152,7 @@ template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt,
LogPrintf(__VA_ARGS__); \
} \
} while(0)
+#endif
template<typename... Args>
bool error(const char* fmt, const Args&... args)
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 74bf66fbf6..93abaec04b 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -437,7 +437,7 @@ bool ParseInt32(const std::string& str, int32_t *out)
errno = 0; // strtol will not set errno if valid
long int n = strtol(str.c_str(), &endp, 10);
if(out) *out = (int32_t)n;
- // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
+ // Note that strtol returns a *long int*, so even if strtol doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
// platforms the size of these types may be different.
return endp && *endp == 0 && !errno &&
@@ -453,7 +453,7 @@ bool ParseInt64(const std::string& str, int64_t *out)
errno = 0; // strtoll will not set errno if valid
long long int n = strtoll(str.c_str(), &endp, 10);
if(out) *out = (int64_t)n;
- // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
+ // Note that strtoll returns a *long long int*, so even if strtol doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *int64_t*.
return endp && *endp == 0 && !errno &&
n >= std::numeric_limits<int64_t>::min() &&
@@ -470,7 +470,7 @@ bool ParseUInt32(const std::string& str, uint32_t *out)
errno = 0; // strtoul will not set errno if valid
unsigned long int n = strtoul(str.c_str(), &endp, 10);
if(out) *out = (uint32_t)n;
- // Note that strtoul returns a *unsigned long int*, so even if it doesn't report a over/underflow
+ // Note that strtoul returns a *unsigned long int*, so even if it doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *uint32_t*. On 64-bit
// platforms the size of these types may be different.
return endp && *endp == 0 && !errno &&
@@ -487,7 +487,7 @@ bool ParseUInt64(const std::string& str, uint64_t *out)
errno = 0; // strtoull will not set errno if valid
unsigned long long int n = strtoull(str.c_str(), &endp, 10);
if(out) *out = (uint64_t)n;
- // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report a over/underflow
+ // Note that strtoull returns a *unsigned long long int*, so even if it doesn't report an over/underflow
// we still have to check that the returned value is within the range of an *uint64_t*.
return endp && *endp == 0 && !errno &&
n <= std::numeric_limits<uint64_t>::max();
diff --git a/src/validation.cpp b/src/validation.cpp
index cba3b9e4ad..eb6ea42b63 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1209,7 +1209,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
- // invalid in new blocks, e.g. a invalid P2SH. We DoS ban
+ // invalid in new blocks, e.g. an invalid P2SH. We DoS ban
// such nodes as they are not following the protocol. That
// said during an upgrade careful thought should be taken
// as to the correct behavior - we may want to continue
@@ -1297,7 +1297,7 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
return state.Error(strMessage);
}
-} // anon namespace
+} // namespace
enum DisconnectResult
{
@@ -3325,7 +3325,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
bool static LoadBlockIndexDB(const CChainParams& chainparams)
{
- if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex))
+ if (!pblocktree->LoadBlockIndexGuts(chainparams.GetConsensus(), InsertBlockIndex))
return false;
boost::this_thread::interruption_point();
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index 4bb352f23c..92c90b7efb 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -189,7 +189,7 @@ public:
uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
};
-}
+} // namespace
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
{
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 3c25364648..0fe2412352 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -148,7 +148,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
pwallet->UpdateTimeFirstKey(1);
if (fRescan) {
- pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
}
}
@@ -278,7 +278,7 @@ UniValue importaddress(const JSONRPCRequest& request)
if (fRescan)
{
- pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
pwallet->ReacceptWalletTransactions();
}
@@ -436,7 +436,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (fRescan)
{
- pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */);
pwallet->ReacceptWalletTransactions();
}
@@ -536,11 +536,7 @@ UniValue importwallet(const JSONRPCRequest& request)
file.close();
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
pwallet->UpdateTimeFirstKey(nTimeBegin);
-
- CBlockIndex *pindex = chainActive.FindEarliestAtLeast(nTimeBegin - TIMESTAMP_WINDOW);
-
- LogPrintf("Rescanning last %i blocks\n", pindex ? chainActive.Height() - pindex->nHeight + 1 : 0);
- pwallet->ScanForWalletTransactions(pindex);
+ pwallet->RescanFromTime(nTimeBegin, false /* update */);
pwallet->MarkDirty();
if (!fGood)
@@ -1049,7 +1045,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
" \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
- " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n"
+ " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n"
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
" }\n"
@@ -1126,14 +1122,10 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
if (fRescan && fRunScan && requests.size()) {
- CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis();
- CBlockIndex* scanFailed = nullptr;
- if (pindex) {
- scanFailed = pwallet->ScanForWalletTransactions(pindex, true);
- pwallet->ReacceptWalletTransactions();
- }
+ int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */);
+ pwallet->ReacceptWalletTransactions();
- if (scanFailed) {
+ if (scannedTime > nLowestTimestamp) {
std::vector<UniValue> results = response.getValues();
response.clear();
response.setArray();
@@ -1143,7 +1135,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
// range, or if the import result already has an error set, let
// the result stand unmodified. Otherwise replace the result
// with an error message.
- if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW > scanFailed->GetBlockTimeMax() || results.at(i).exists("error")) {
+ if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
response.push_back(results.at(i));
} else {
UniValue result = UniValue(UniValue::VOBJ);
@@ -1159,7 +1151,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
"caused by pruning or data corruption (see bitcoind log for details) and could "
"be dealt with by downloading and rescanning the relevant blocks (see -reindex "
"and -rescan options).",
- GetImportTimestamp(request, now), scanFailed->GetBlockTimeMax(), TIMESTAMP_WINDOW)));
+ GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
response.push_back(std::move(result));
}
++i;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 58153dfc3c..0d1a86dd24 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -220,6 +220,10 @@ bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigne
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
}
+/**
+ * Update wallet first key creation time. This should be called whenever keys
+ * are added to the wallet, with the oldest key creation time.
+ */
void CWallet::UpdateTimeFirstKey(int64_t nCreateTime)
{
AssertLockHeld(cs_wallet);
@@ -1468,6 +1472,34 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
}
/**
+ * Scan active chain for relevant transactions after importing keys. This should
+ * be called whenever new keys are added to the wallet, with the oldest key
+ * creation time.
+ *
+ * @return Earliest timestamp that could be successfully scanned from. Timestamp
+ * returned will be higher than startTime if relevant blocks could not be read.
+ */
+int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
+{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(cs_wallet);
+
+ // Find starting block. May be null if nCreateTime is greater than the
+ // highest blockchain timestamp, in which case there is nothing that needs
+ // to be scanned.
+ CBlockIndex* const startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
+ LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
+
+ if (startBlock) {
+ const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update);
+ if (failedBlock) {
+ return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
+ }
+ }
+ return startTime;
+}
+
+/**
* Scan the block chain (starting in pindexStart) for transactions
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
@@ -1488,11 +1520,6 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
fAbortRescan = false;
fScanningWallet = true;
- // no need to read and scan block, if block was created before
- // our wallet birthday (as adjusted for block time variability)
- while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - TIMESTAMP_WINDOW)))
- pindex = chainActive.Next(pindex);
-
ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
double dProgressStart = GuessVerificationProgress(chainParams.TxData(), pindex);
double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip());
@@ -2633,28 +2660,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
CTxOut newTxOut(nChange, scriptChange);
- // We do not move dust-change to fees, because the sender would end up paying more than requested.
- // This would be against the purpose of the all-inclusive feature.
- // So instead we raise the change and deduct from the recipient.
- if (nSubtractFeeFromAmount > 0 && IsDust(newTxOut, ::dustRelayFee))
- {
- CAmount nDust = GetDustThreshold(newTxOut, ::dustRelayFee) - newTxOut.nValue;
- newTxOut.nValue += nDust; // raise change until no more dust
- for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
- {
- if (vecSend[i].fSubtractFeeFromAmount)
- {
- txNew.vout[i].nValue -= nDust;
- if (IsDust(txNew.vout[i], ::dustRelayFee))
- {
- strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
- return false;
- }
- break;
- }
- }
- }
-
// Never create dust outputs; if we would, just
// add the dust to the fee.
if (IsDust(newTxOut, ::dustRelayFee))
@@ -3863,11 +3868,11 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
else if (IsArgSet("-usehd")) {
bool useHD = GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET);
if (walletInstance->IsHDEnabled() && !useHD) {
- InitError(strprintf(_("Error loading %s: You can't disable HD on a already existing HD wallet"), walletFile));
+ InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile));
return NULL;
}
if (!walletInstance->IsHDEnabled() && useHD) {
- InitError(strprintf(_("Error loading %s: You can't enable HD on a already existing non-HD wallet"), walletFile));
+ InitError(strprintf(_("Error loading %s: You can't enable HD on an already existing non-HD wallet"), walletFile));
return NULL;
}
}
@@ -3887,7 +3892,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
- //this might happen if a user uses a old wallet within a pruned node
+ //this might happen if a user uses an old wallet within a pruned node
// or if he ran -disablewallet for a longer time, then decided to re-enable
if (fPruneMode)
{
@@ -3903,6 +3908,13 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
+
+ // No need to read and scan block if block was created before
+ // our wallet birthday (as adjusted for block time variability)
+ while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) {
+ pindexRescan = chainActive.Next(pindexRescan);
+ }
+
nStart = GetTimeMillis();
walletInstance->ScanForWalletTransactions(pindexRescan, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index ad606b8535..6ed955cf58 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -68,6 +68,8 @@ static const bool DEFAULT_USE_HD_WALLET = true;
extern const char * DEFAULT_WALLET_DAT;
+static const int64_t TIMESTAMP_MIN = 0;
+
class CBlockIndex;
class CCoinControl;
class COutput;
@@ -919,6 +921,7 @@ public:
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
+ int64_t RescanFromTime(int64_t startTime, bool update);
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
diff --git a/test/README.md b/test/README.md
index 4dd512638d..15f6df790f 100644
--- a/test/README.md
+++ b/test/README.md
@@ -15,84 +15,152 @@ The util tests are run as part of `make check` target. The functional
tests are run by the travis continuous build process whenever a pull
request is opened. Both sets of tests can also be run locally.
-Functional Test dependencies
-============================
+# Running tests locally
+
+Build for your system first. Be sure to enable wallet, utils and daemon when you configure. Tests will not run otherwise.
+
+### Functional tests
+
+#### Dependencies
+
The ZMQ functional test requires a python ZMQ library. To install it:
- on Unix, run `sudo apt-get install python3-zmq`
- on mac OS, run `pip3 install pyzmq`
-Running tests locally
-=====================
+#### Running the tests
-Build for your system first. Be sure to enable wallet, utils and daemon when you configure. Tests will not run otherwise.
+Individual tests can be run by directly calling the test script, eg:
-Functional tests
-----------------
+```
+test/functional/replace-by-fee.py
+```
-You can run any single test by calling
+or can be run through the test_runner harness, eg:
- test/functional/test_runner.py <testname>
+```
+test/functional/test_runner.py replace-by-fee.py
+```
-Or you can run any combination (incl. duplicates) of tests by calling
+You can run any combination (incl. duplicates) of tests by calling:
- test/functional/test_runner.py <testname1> <testname2> <testname3> ...
+```
+test/functional/test_runner.py <testname1> <testname2> <testname3> ...
+```
-Run the regression test suite with
+Run the regression test suite with:
- test/functional/test_runner.py
+```
+test/functional/test_runner.py
+```
Run all possible tests with
- test/functional/test_runner.py --extended
+```
+test/functional/test_runner.py --extended
+```
+
+By default, up to 4 tests will be run in parallel by test_runner. To specify
+how many jobs to run, append `--jobs=n`
-By default, tests will be run in parallel. To specify how many jobs to run,
-append `--jobs=n` (default n=4).
+The individual tests and the test_runner harness have many command-line
+options. Run `test_runner.py -h` to see them all.
-If you want to create a basic coverage report for the RPC test suite, append `--coverage`.
+#### Troubleshooting and debugging test failures
-Possible options, which apply to each individual test run:
+##### Resource contention
+The P2P and RPC ports used by the bitcoind nodes-under-test are chosen to make
+conflicts with other processes unlikely. However, if there is another bitcoind
+process running on the system (perhaps from a previous test which hasn't successfully
+killed all its bitcoind nodes), then there may be a port conflict which will
+cause the test to fail. It is recommended that you run the tests on a system
+where no other bitcoind processes are running.
+
+On linux, the test_framework will warn if there is another
+bitcoind process running when the tests are started.
+
+If there are zombie bitcoind processes after test failure, you can kill them
+by running the following commands. **Note that these commands will kill all
+bitcoind processes running on the system, so should not be used if any non-test
+bitcoind processes are being run.**
+
+```bash
+killall bitcoind
```
- -h, --help show this help message and exit
- --nocleanup Leave bitcoinds and test.* datadir on exit or error
- --noshutdown Don't stop bitcoinds after the test execution
- --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli
- (default: ../../src)
- --tmpdir=TMPDIR Root directory for datadirs
- --tracerpc Print out all RPC calls as they are made
- --coveragedir=COVERAGEDIR
- Write tested RPC commands into this directory
-```
-If you set the environment variable `PYTHON_DEBUG=1` you will get some debug
-output (example: `PYTHON_DEBUG=1 test/functional/test_runner.py wallet`).
+or
+
+```bash
+pkill -9 bitcoind
+```
-A 200-block -regtest blockchain and wallets for four nodes
-is created the first time a regression test is run and
-is stored in the cache/ directory. Each node has 25 mature
-blocks (25*50=1250 BTC) in its wallet.
-After the first run, the cache/ blockchain and wallets are
-copied into a temporary directory and used as the initial
-test state.
+##### Data directory cache
-If you get into a bad state, you should be able
-to recover with:
+A pre-mined blockchain with 200 blocks is generated the first time a
+functional test is run and is stored in test/cache. This speeds up
+test startup times since new blockchains don't need to be generated for
+each test. However, the cache may get into a bad state, in which case
+tests will fail. If this happens, remove the cache directory (and make
+sure bitcoind processes are stopped as above):
```bash
rm -rf cache
killall bitcoind
```
-Util tests
-----------
+##### Test logging
+
+The tests contain logging at different levels (debug, info, warning, etc). By
+default:
+
+- when run through the test_runner harness, *all* logs are written to
+ `test_framework.log` and no logs are output to the console.
+- when run directly, *all* logs are written to `test_framework.log` and INFO
+ level and above are output to the console.
+- when run on Travis, no logs are output to the console. However, if a test
+ fails, the `test_framework.log` and bitcoind `debug.log`s will all be dumped
+ to the console to help troubleshooting.
+
+To change the level of logs output to the console, use the `-l` command line
+argument.
+
+`test_framework.log` and bitcoind `debug.log`s can be combined into a single
+aggregate log by running the `combine_logs.py` script. The output can be plain
+text, colorized text or html. For example:
+
+```
+combine_logs.py -c <test data directory> | less -r
+```
+
+will pipe the colorized logs from the test into less.
+
+Use `--tracerpc` to trace out all the RPC calls and responses to the console. For
+some tests (eg any that use `submitblock` to submit a full block over RPC),
+this can result in a lot of screen output.
+
+By default, the test data directory will be deleted after a successful run.
+Use `--nocleanup` to leave the test data directory intact. The test data
+directory is never deleted after a failed test.
+
+##### Attaching a debugger
+
+A python debugger can be attached to tests at any point. Just add the line:
+
+```py
+import pdb; pdb.set_trace()
+```
+
+anywhere in the test. You will then be able to inspect variables, as well as
+call methods that interact with the bitcoind nodes-under-test.
+
+### Util tests
Util tests can be run locally by running `test/util/bitcoin-util-test.py`.
Use the `-v` option for verbose output.
-Writing functional tests
-========================
+# Writing functional tests
You are encouraged to write functional tests for new or existing features.
Further information about the functional test framework and individual
diff --git a/test/functional/README.md b/test/functional/README.md
index e6c4849702..96fe0becce 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -1,108 +1,154 @@
-Regression tests
-================
+# Functional tests
-### [test_framework/authproxy.py](test_framework/authproxy.py)
-Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc).
+### Writing Functional Tests
-### [test_framework/test_framework.py](test_framework/test_framework.py)
-Base class for new regression tests.
+#### Example test
-### [test_framework/util.py](test_framework/util.py)
-Generally useful functions.
+The [example_test.py](example_test.py) is a heavily commented example of a test case that uses both
+the RPC and P2P interfaces. If you are writing your first test, copy that file
+and modify to fit your needs.
-### [test_framework/mininode.py](test_framework/mininode.py)
-Basic code to support p2p connectivity to a bitcoind.
+#### Coverage
-### [test_framework/comptool.py](test_framework/comptool.py)
-Framework for comparison-tool style, p2p tests.
+Running `test_runner.py` with the `--coverage` argument tracks which RPCs are
+called by the tests and prints a report of uncovered RPCs in the summary. This
+can be used (along with the `--extended` argument) to find out which RPCs we
+don't have test cases for.
-### [test_framework/script.py](test_framework/script.py)
-Utilities for manipulating transaction scripts (originally from python-bitcoinlib)
+#### Style guidelines
-### [test_framework/blockstore.py](test_framework/blockstore.py)
-Implements disk-backed block and tx storage.
+- Where possible, try to adhere to [PEP-8 guidelines]([https://www.python.org/dev/peps/pep-0008/)
+- Use a python linter like flake8 before submitting PRs to catch common style
+ nits (eg trailing whitespace, unused imports, etc)
+- Avoid wildcard imports where possible
+- 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.
-### [test_framework/key.py](test_framework/key.py)
-Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib)
+#### General test-writing advice
-### [test_framework/bignum.py](test_framework/bignum.py)
-Helpers for script.py
+- Set `self.num_nodes` to the minimum number of nodes necessary for the test.
+ Having additional unrequired nodes adds to the execution time of the test as
+ well as memory/CPU/disk requirements (which is important when running tests in
+ parallel or on Travis).
+- 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
+ 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.
+- When calling RPCs with lots of arguments, consider using named keyword
+ arguments instead of positional arguments to make the intent of the call
+ clear to readers.
-### [test_framework/blocktools.py](test_framework/blocktools.py)
-Helper functions for creating blocks and transactions.
+#### RPC and P2P definitions
-P2P test design notes
----------------------
+Test writers may find it helpful to refer to the definitions for the RPC and
+P2P messages. These can be found in the following source files:
-## Mininode
+- `/src/rpc/*` for RPCs
+- `/src/wallet/rpc*` for wallet RPCs
+- `ProcessMessage()` in `/src/net_processing.cpp` for parsing P2P messages
-* ```mininode.py``` contains all the definitions for objects that pass
-over the network (```CBlock```, ```CTransaction```, etc, along with the network-level
-wrappers for them, ```msg_block```, ```msg_tx```, etc).
+#### Using the P2P interface
-* P2P tests have two threads. One thread handles all network communication
+- `mininode.py` contains all the definitions for objects that pass
+over the network (`CBlock`, `CTransaction`, etc, along with the network-level
+wrappers for them, `msg_block`, `msg_tx`, etc).
+
+- P2P tests have two threads. One thread handles all network communication
with the bitcoind(s) being tested (using python's asyncore package); the other
implements the test logic.
-* ```NodeConn``` is the class used to connect to a bitcoind. If you implement
-a callback class that derives from ```NodeConnCB``` and pass that to the
-```NodeConn``` object, your code will receive the appropriate callbacks when
+- `NodeConn` is the class used to connect to a bitcoind. If you implement
+a callback class that derives from `NodeConnCB` and pass that to the
+`NodeConn` object, your code will receive the appropriate callbacks when
events of interest arrive.
-* You can pass the same handler to multiple ```NodeConn```'s if you like, or pass
-different ones to each -- whatever makes the most sense for your test.
-
-* Call ```NetworkThread.start()``` after all ```NodeConn``` objects are created to
+- Call `NetworkThread.start()` after all `NodeConn` objects are created to
start the networking thread. (Continue with the test logic in your existing
thread.)
-* RPC calls are available in p2p tests.
+- Can be used to write tests where specific P2P protocol behavior is tested.
+Examples tests are `p2p-accept-block.py`, `p2p-compactblocks.py`.
-* Can be used to write free-form tests, where specific p2p-protocol behavior
-is tested. Examples: ```p2p-accept-block.py```, ```p2p-compactblocks.py```.
+#### Comptool
-## Comptool
+- Comptool is a Testing framework for writing tests that compare the block/tx acceptance
+behavior of a bitcoind against 1 or more other bitcoind instances. It should not be used
+to write static tests with known outcomes, since that type of test is easier to write and
+maintain using the standard BitcoinTestFramework.
-* Testing framework for writing tests that compare the block/tx acceptance
-behavior of a bitcoind against 1 or more other bitcoind instances, or against
-known outcomes, or both.
-
-* Set the ```num_nodes``` variable (defined in ```ComparisonTestFramework```) to start up
-1 or more nodes. If using 1 node, then ```--testbinary``` can be used as a command line
+- Set the `num_nodes` variable (defined in `ComparisonTestFramework`) to start up
+1 or more nodes. If using 1 node, then `--testbinary` can be used as a command line
option to change the bitcoind binary used by the test. If using 2 or more nodes,
-then ```--refbinary``` can be optionally used to change the bitcoind that will be used
+then `--refbinary` can be optionally used to change the bitcoind that will be used
on nodes 2 and up.
-* Implement a (generator) function called ```get_tests()``` which yields ```TestInstance```s.
-Each ```TestInstance``` consists of:
- - a list of ```[object, outcome, hash]``` entries
- * ```object``` is a ```CBlock```, ```CTransaction```, or
- ```CBlockHeader```. ```CBlock```'s and ```CTransaction```'s are tested for
- acceptance. ```CBlockHeader```s can be used so that the test runner can deliver
+- Implement a (generator) function called `get_tests()` which yields `TestInstance`s.
+Each `TestInstance` consists of:
+ - a list of `[object, outcome, hash]` entries
+ * `object` is a `CBlock`, `CTransaction`, or
+ `CBlockHeader`. `CBlock`'s and `CTransaction`'s are tested for
+ acceptance. `CBlockHeader`s can be used so that the test runner can deliver
complete headers-chains when requested from the bitcoind, to allow writing
tests where blocks can be delivered out of order but still processed by
headers-first bitcoind's.
- * ```outcome``` is ```True```, ```False```, or ```None```. If ```True```
- or ```False```, the tip is compared with the expected tip -- either the
+ * `outcome` is `True`, `False`, or `None`. If `True`
+ or `False`, the tip is compared with the expected tip -- either the
block passed in, or the hash specified as the optional 3rd entry. If
- ```None``` is specified, then the test will compare all the bitcoind's
+ `None` is specified, then the test will compare all the bitcoind's
being tested to see if they all agree on what the best tip is.
- * ```hash``` is the block hash of the tip to compare against. Optional to
+ * `hash` is the block hash of the tip to compare against. Optional to
specify; if left out then the hash of the block passed in will be used as
the expected tip. This allows for specifying an expected tip while testing
the handling of either invalid blocks or blocks delivered out of order,
which complete a longer chain.
- - ```sync_every_block```: ```True/False```. If ```False```, then all blocks
+ - `sync_every_block`: `True/False`. If `False`, then all blocks
are inv'ed together, and the test runner waits until the node receives the
last one, and tests only the last block for tip acceptance using the
- outcome and specified tip. If ```True```, then each block is tested in
+ outcome and specified tip. If `True`, then each block is tested in
sequence and synced (this is slower when processing many blocks).
- - ```sync_every_transaction```: ```True/False```. Analogous to
- ```sync_every_block```, except if the outcome on the last tx is "None",
+ - `sync_every_transaction`: `True/False`. Analogous to
+ `sync_every_block`, except if the outcome on the last tx is "None",
then the contents of the entire mempool are compared across all bitcoind
- connections. If ```True``` or ```False```, then only the last tx's
+ connections. If `True` or `False`, then only the last tx's
acceptance is tested against the given outcome.
-* For examples of tests written in this framework, see
- ```invalidblockrequest.py``` and ```p2p-fullblocktest.py```.
+- For examples of tests written in this framework, see
+ `invalidblockrequest.py` and `p2p-fullblocktest.py`.
+
+### test-framework modules
+
+#### [test_framework/authproxy.py](test_framework/authproxy.py)
+Taken from the [python-bitcoinrpc repository](https://github.com/jgarzik/python-bitcoinrpc).
+
+#### [test_framework/test_framework.py](test_framework/test_framework.py)
+Base class for functional tests.
+#### [test_framework/util.py](test_framework/util.py)
+Generally useful functions.
+
+#### [test_framework/mininode.py](test_framework/mininode.py)
+Basic code to support P2P connectivity to a bitcoind.
+
+#### [test_framework/comptool.py](test_framework/comptool.py)
+Framework for comparison-tool style, P2P tests.
+
+#### [test_framework/script.py](test_framework/script.py)
+Utilities for manipulating transaction scripts (originally from python-bitcoinlib)
+
+#### [test_framework/blockstore.py](test_framework/blockstore.py)
+Implements disk-backed block and tx storage.
+
+#### [test_framework/key.py](test_framework/key.py)
+Wrapper around OpenSSL EC_Key (originally from python-bitcoinlib)
+
+#### [test_framework/bignum.py](test_framework/bignum.py)
+Helpers for script.py
+
+#### [test_framework/blocktools.py](test_framework/blocktools.py)
+Helper functions for creating blocks and transactions.
diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py
index d42bab6cbf..569db7ced5 100755
--- a/test/functional/bumpfee.py
+++ b/test/functional/bumpfee.py
@@ -10,7 +10,7 @@ its preconditions are met, and returns appropriate errors in other cases.
This module consists of around a dozen individual test cases implemented in the
top-level functions named as test_<test_case_description>. The test functions
can be disabled or reordered if needed for debugging. If new test cases are
-added in the the future, they should try to follow the same convention and not
+added in the future, they should try to follow the same convention and not
make assumptions about execution order.
"""
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
new file mode 100755
index 0000000000..1ba5f756cd
--- /dev/null
+++ b/test/functional/example_test.py
@@ -0,0 +1,219 @@
+#!/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.
+"""An example functional test
+
+The module-level docstring should include a high-level description of
+what the test is doing. It's the first thing people see when they open
+the file and should give the reader information about *what* the test
+is testing and *how* it's being tested
+"""
+# Imports should be in PEP8 ordering (std library first, then third party
+# libraries then local imports).
+from collections import defaultdict
+
+# Avoid wildcard * imports if possible
+from test_framework.blocktools import (create_block, create_coinbase)
+from test_framework.mininode import (
+ CInv,
+ NetworkThread,
+ NodeConn,
+ NodeConnCB,
+ 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,
+)
+
+# NodeConnCB is a class containing callbacks to be executed when a P2P
+# message is received from the node-under-test. Subclass NodeConnCB and
+# override the on_*() methods if you need custom behaviour.
+class BaseNode(NodeConnCB):
+ def __init__(self):
+ """Initialize the NodeConnCB
+
+ Used to inialize custom properties for the Node that aren't
+ included by default in the base class. Be aware that the NodeConnCB
+ base class already stores a counter for each P2P message type and the
+ last received message of each type, which should be sufficient for the
+ needs of most tests.
+
+ Call super().__init__() first for standard initialization and then
+ initialize custom properties."""
+ super().__init__()
+ # Stores a dictionary of all blocks received
+ self.block_receive_map = defaultdict(int)
+
+ def on_block(self, conn, message):
+ """Override the standard on_block callback
+
+ Store the hash of a received block in the dictionary."""
+ message.block.calc_sha256()
+ self.block_receive_map[message.block.sha256] += 1
+
+def custom_function():
+ """Do some custom behaviour
+
+ If this function is more generally useful for other tests, consider
+ moving it to a module in test_framework."""
+ # self.log.info("running custom_function") # Oops! Can't run self.log outside the BitcoinTestFramework
+ pass
+
+class ExampleTest(BitcoinTestFramework):
+ # Each functional test is a subclass of the BitcoinTestFramework class.
+
+ # Override the __init__(), add_options(), setup_chain(), setup_network()
+ # and setup_nodes() methods to customize the test setup as required.
+
+ def __init__(self):
+ """Initialize the test
+
+ Call super().__init__() first, and then override any test parameters
+ for your individual test."""
+ super().__init__()
+ 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()
+
+ # 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
+ # to be run in automated environments without command-line options.
+ # def add_options()
+ # pass
+
+ # Use setup_chain() to customize the node data directories. In practice
+ # this is not used very much since the default behaviour is almost always
+ # fine
+ # def setup_chain():
+ # pass
+
+ def setup_network(self):
+ """Setup the test network topology
+
+ Often you won't need to override this, since the standard network topology
+ (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests.
+
+ If you do override this method, remember to start the nodes, assign
+ them to self.nodes, connect them and then sync."""
+
+ self.setup_nodes()
+
+ # In this test, we're not connecting node2 to node0 or node1. Calls to
+ # sync_all() should not include node2, since we're not expecting it to
+ # sync.
+ connect_nodes(self.nodes[0], 1)
+ self.sync_all([self.nodes[0:1]])
+
+ # Use setup_nodes() to customize the node start behaviour (for example if
+ # you don't want to start all nodes at the start of the test).
+ # def setup_nodes():
+ # pass
+
+ def custom_method(self):
+ """Do some custom behaviour for this test
+
+ Define it in a method here because you're going to use it repeatedly.
+ If you think it's useful in general, consider moving it to the base
+ BitcoinTestFramework class so other tests can use it."""
+
+ self.log.info("Running custom_method")
+
+ def run_test(self):
+ """Main test logic"""
+
+ # Create a P2P connection to one of the nodes
+ node0 = BaseNode()
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
+ node0.add_connection(connections[0])
+
+ # Start up network handling in another thread. This needs to be called
+ # after the P2P connections have been created.
+ NetworkThread().start()
+ # wait_for_verack ensures that the P2P connection is fully up.
+ node0.wait_for_verack()
+
+ # Generating a block on one of the nodes will get us out of IBD
+ blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
+ self.sync_all([self.nodes[0:1]])
+
+ # Notice above how we called an RPC by calling a method with the same
+ # name on the node object. Notice also how we used a keyword argument
+ # to specify a named RPC argument. Neither of those are defined on the
+ # node object. Instead there's some __getattr__() magic going on under
+ # the covers to dispatch unrecognised attribute calls to the RPC
+ # interface.
+
+ # Logs are nice. Do plenty of them. They can be used in place of comments for
+ # breaking the test into sub-sections.
+ self.log.info("Starting test!")
+
+ self.log.info("Calling a custom function")
+ custom_function()
+
+ self.log.info("Calling a custom method")
+ self.custom_method()
+
+ self.log.info("Create some blocks")
+ self.tip = int(self.nodes[0].getbestblockhash(), 16)
+ self.block_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
+
+ height = 1
+
+ for i in range(10):
+ # Use the mininode and blocktools functionality to manually build a block
+ # Calling the generate() rpc is easier, but this allows us to exactly
+ # control the blocks and transactions.
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block.solve()
+ block_message = msg_block(block)
+ # Send message is used to send a P2P message to the node over our NodeConn connection
+ node0.send_message(block_message)
+ self.tip = block.sha256
+ blocks.append(self.tip)
+ self.block_time += 1
+ height += 1
+
+ self.log.info("Wait for node1 to reach current tip (height 11) using RPC")
+ self.nodes[1].waitforblockheight(11)
+
+ self.log.info("Connect node2 and node1")
+ connect_nodes(self.nodes[1], 2)
+
+ self.log.info("Add P2P connection to node2")
+ node2 = BaseNode()
+ connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
+ node2.add_connection(connections[1])
+ node2.wait_for_verack()
+
+ self.log.info("Wait for node2 reach current tip. Test that it has propogated all the blocks to us")
+
+ for block in blocks:
+ getdata_request = msg_getdata()
+ getdata_request.inv.append(CInv(2, block))
+ node2.send_message(getdata_request)
+
+ # 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)
+
+ 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
+ # messages. The test thread should acquire the global lock before accessing any NodeConn data to avoid locking
+ # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate.
+ with mininode_lock:
+ for block in node2.block_receive_map.values():
+ assert_equal(block, 1)
+
+if __name__ == '__main__':
+ ExampleTest().main()
diff --git a/test/functional/pruning.py b/test/functional/pruning.py
index 37e9d29738..0af91e0658 100755
--- a/test/functional/pruning.py
+++ b/test/functional/pruning.py
@@ -318,7 +318,7 @@ class PruneTest(BitcoinTestFramework):
self.nodes[2] = self.start_node(2, self.options.tmpdir, ["-prune=550"])
self.log.info("Success")
- # check that wallet loads loads successfully when restarting a pruned node after IBD.
+ # check that wallet loads successfully when restarting a pruned node after IBD.
# this was reported to fail in #7494.
self.log.info("Syncing node 5 to test wallet")
connect_nodes(self.nodes[0], 5)
diff --git a/test/functional/rest.py b/test/functional/rest.py
index fbcceba0fa..a69dbb5013 100755
--- a/test/functional/rest.py
+++ b/test/functional/rest.py
@@ -82,9 +82,9 @@ class RESTTest (BitcoinTestFramework):
n = vout['n']
- ######################################
- # GETUTXOS: query a unspent outpoint #
- ######################################
+ #######################################
+ # GETUTXOS: query an unspent outpoint #
+ #######################################
json_request = '/checkmempool/'+txid+'-'+str(n)
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
@@ -97,9 +97,9 @@ class RESTTest (BitcoinTestFramework):
assert_equal(json_obj['utxos'][0]['value'], 0.1)
- ################################################
- # GETUTXOS: now query a already spent outpoint #
- ################################################
+ #################################################
+ # GETUTXOS: now query an already spent outpoint #
+ #################################################
json_request = '/checkmempool/'+vintx+'-0'
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
@@ -161,24 +161,24 @@ class RESTTest (BitcoinTestFramework):
json_request = '/'+txid+'-'+str(n)
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
- assert_equal(len(json_obj['utxos']), 0) #there should be a outpoint because it has just added to the mempool
+ assert_equal(len(json_obj['utxos']), 0) #there should be an outpoint because it has just added to the mempool
json_request = '/checkmempool/'+txid+'-'+str(n)
json_string = http_get_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json')
json_obj = json.loads(json_string)
- assert_equal(len(json_obj['utxos']), 1) #there should be a outpoint because it has just added to the mempool
+ assert_equal(len(json_obj['utxos']), 1) #there should be an outpoint because it has just added to the mempool
#do some invalid requests
json_request = '{"checkmempool'
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'json', json_request, True)
- assert_equal(response.status, 400) #must be a 400 because we send a invalid json request
+ assert_equal(response.status, 400) #must be a 400 because we send an invalid json request
json_request = '{"checkmempool'
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+self.FORMAT_SEPARATOR+'bin', json_request, True)
- assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send an invalid bin request
response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True)
- assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send an invalid bin request
#test limits
json_request = '/checkmempool/'
diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py
index 482c77863f..bc42a319df 100755
--- a/test/functional/smartfees.py
+++ b/test/functional/smartfees.py
@@ -10,7 +10,7 @@ from test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_E
from test_framework.mininode import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN
# Construct 2 trivial P2SH's and the ScriptSigs that spend them
-# So we can create many many transactions without needing to spend
+# So we can create many transactions without needing to spend
# time signing.
redeem_script_1 = CScript([OP_1, OP_DROP])
redeem_script_2 = CScript([OP_2, OP_DROP])
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index fb3ed1473a..688347a68f 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -61,7 +61,7 @@ mininode_socket_map = dict()
# One lock for synchronizing all data access between the networking thread (see
# NetworkThread below) and the thread running the test logic. For simplicity,
-# NodeConn acquires this lock whenever delivering a message to to a NodeConnCB,
+# NodeConn acquires this lock whenever delivering a message to a NodeConnCB,
# and whenever adding anything to the send buffer (in send_message()). This
# lock should be acquired in the thread running the test logic to synchronize
# access to any data shared with the NodeConnCB or NodeConn.
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index d2a609451d..fa6388bf96 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -322,8 +322,8 @@ def _stop_node(node, i):
except http.client.CannotSendRequest as e:
logger.exception("Unable to stop node")
return_code = bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
- assert_equal(return_code, 0)
del bitcoind_processes[i]
+ assert_equal(return_code, 0)
def _stop_nodes(nodes):
"""Stop multiple bitcoind test nodes
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 0dca318af8..9952835951 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -113,6 +113,7 @@ BASE_SCRIPTS= [
'listsinceblock.py',
'p2p-leaktests.py',
'wallet-encryption.py',
+ 'uptime.py',
]
EXTENDED_SCRIPTS = [
@@ -138,6 +139,7 @@ EXTENDED_SCRIPTS = [
'bip65-cltv-p2p.py',
'bipdersig-p2p.py',
'bipdersig.py',
+ 'example_test.py',
'getblocktemplate_proposals.py',
'txn_doublespend.py',
'txn_clone.py --mineblock',
diff --git a/test/functional/uptime.py b/test/functional/uptime.py
new file mode 100755
index 0000000000..b20d6f5cb6
--- /dev/null
+++ b/test/functional/uptime.py
@@ -0,0 +1,32 @@
+#!/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 the RPC call related to the uptime command.
+
+Test corresponds to code in rpc/server.cpp.
+"""
+
+import time
+
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class UptimeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def run_test(self):
+ self._test_uptime()
+
+ def _test_uptime(self):
+ wait_time = 10
+ self.nodes[0].setmocktime(int(time.time() + wait_time))
+ assert(self.nodes[0].uptime() >= wait_time)
+
+
+if __name__ == '__main__':
+ UptimeTest().main()
diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py
index a8600e82f6..e4d40520ef 100755
--- a/test/functional/zapwallettxes.py
+++ b/test/functional/zapwallettxes.py
@@ -70,7 +70,7 @@ class ZapWalletTXesTest (BitcoinTestFramework):
self.nodes[0] = self.start_node(0,self.options.tmpdir, ["-zapwallettxes=1"])
assert_raises(JSONRPCException, self.nodes[0].gettransaction, [txid3])
- #there must be a expection because the unconfirmed wallettx0 must be gone by now
+ #there must be an exception because the unconfirmed wallettx0 must be gone by now
tx0 = self.nodes[0].gettransaction(txid0)
assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed