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--doc/release-notes/release-notes-0.14.2.md102
-rw-r--r--share/pixmaps/nsis-header.bmpbin25818 -> 25820 bytes
-rw-r--r--share/pixmaps/nsis-wizard.bmpbin154542 -> 154544 bytes
-rw-r--r--src/.clang-format2
-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/bitcoin-tx.cpp1
-rw-r--r--src/chain.cpp2
-rw-r--r--src/chainparams.cpp20
-rw-r--r--src/chainparams.h4
-rw-r--r--src/coins.cpp15
-rw-r--r--src/coins.h19
-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/consensus/tx_verify.cpp8
-rw-r--r--src/cuckoocache.h35
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/httpserver.cpp24
-rw-r--r--src/httpserver.h4
-rw-r--r--src/init.cpp122
-rw-r--r--src/leveldb/db/version_set.h2
-rw-r--r--src/net.cpp86
-rw-r--r--src/net.h11
-rw-r--r--src/net_processing.cpp8
-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/test/rpcnestedtests.cpp2
-rw-r--r--src/qt/walletmodel.cpp2
-rw-r--r--src/random.cpp10
-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.cpp6
-rw-r--r--src/txdb.cpp8
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp14
-rw-r--r--src/txmempool.h3
-rw-r--r--src/util.cpp8
-rw-r--r--src/util.h128
-rw-r--r--src/utilstrencodings.cpp8
-rw-r--r--src/validation.cpp25
-rw-r--r--src/validation.h4
-rw-r--r--src/versionbits.cpp2
-rw-r--r--src/wallet/crypter.cpp1
-rw-r--r--src/wallet/rpcdump.cpp28
-rw-r--r--src/wallet/rpcwallet.cpp1
-rw-r--r--src/wallet/wallet.cpp75
-rw-r--r--src/wallet/wallet.h5
-rw-r--r--src/wallet/walletdb.cpp10
-rwxr-xr-xtest/functional/blockchain.py20
-rwxr-xr-xtest/functional/bumpfee.py2
-rwxr-xr-xtest/functional/multi_rpc.py58
-rwxr-xr-xtest/functional/p2p-segwit.py12
-rwxr-xr-xtest/functional/pruning.py6
-rwxr-xr-xtest/functional/rest.py22
-rwxr-xr-xtest/functional/rpcbind_test.py2
-rwxr-xr-xtest/functional/smartfees.py2
-rwxr-xr-xtest/functional/test_framework/mininode.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py5
-rw-r--r--test/functional/test_framework/util.py50
-rwxr-xr-xtest/functional/test_runner.py8
-rwxr-xr-xtest/functional/uptime.py32
-rwxr-xr-xtest/functional/zapwallettxes.py2
-rwxr-xr-xtest/functional/zmq_test.py65
105 files changed, 1074 insertions, 663 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/doc/release-notes/release-notes-0.14.2.md b/doc/release-notes/release-notes-0.14.2.md
new file mode 100644
index 0000000000..0ad554b773
--- /dev/null
+++ b/doc/release-notes/release-notes-0.14.2.md
@@ -0,0 +1,102 @@
+Bitcoin Core version 0.14.2 is now available from:
+
+ <https://bitcoin.org/bin/bitcoin-core-0.14.2/>
+
+This is a new minor version release, including various bugfixes and
+performance improvements, as well as updated translations.
+
+Please report bugs using the issue tracker at github:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later.
+
+Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support),
+No attempt is made to prevent installing or running the software on Windows XP, you
+can still do so at your own risk but be aware that there are known instabilities and issues.
+Please do not report issues about Windows XP to the issue tracker.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+Notable changes
+===============
+
+miniupnp CVE-2017-8798
+----------------------------
+
+Bundled miniupnpc was updated to 2.0.20170509. This fixes an integer signedness error
+(present in MiniUPnPc v1.4.20101221 through v2.0) that allows remote attackers
+(within the LAN) to cause a denial of service or possibly have unspecified
+other impact.
+
+This only affects users that have explicitly enabled UPnP through the GUI
+setting or through the `-upnp` option, as since the last UPnP vulnerability
+(in Bitcoin Core 0.10.3) it has been disabled by default.
+
+If you use this option, it is recommended to upgrade to this version as soon as
+possible.
+
+Known Bugs
+==========
+
+Since 0.14.0 the approximate transaction fee shown in Bitcoin-Qt when using coin
+control and smart fee estimation does not reflect any change in target from the
+smart fee slider. It will only present an approximate fee calculated using the
+default target. The fee calculated using the correct target is still applied to
+the transaction and shown in the final send confirmation dialog.
+
+0.14.2 Change log
+=================
+
+Detailed release notes follow. This overview includes changes that affect
+behavior, not code moves, refactors and string updates. For convenience in locating
+the code changes and accompanying discussion, both the pull request and
+git merge commit are mentioned.
+
+### RPC and other APIs
+- #10410 `321419b` Fix importwallet edge case rescan bug (ryanofsky)
+
+### P2P protocol and network code
+- #10424 `37a8fc5` Populate services in GetLocalAddress (morcos)
+- #10441 `9e3ad50` Only enforce expected services for half of outgoing connections (theuni)
+
+### Build system
+- #10414 `ffb0c4b` miniupnpc 2.0.20170509 (fanquake)
+- #10228 `ae479bc` Regenerate bitcoin-config.h as necessary (theuni)
+
+### Miscellaneous
+- #10245 `44a17f2` Minor fix in build documentation for FreeBSD 11 (shigeya)
+- #10215 `0aee4a1` Check interruptNet during dnsseed lookups (TheBlueMatt)
+
+### GUI
+- #10231 `1e936d7` Reduce a significant cs_main lock freeze (jonasschnelli)
+
+### Wallet
+- #10294 `1847642` Unset change position when there is no change (instagibbs)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Alex Morcos
+- Cory Fields
+- fanquake
+- Gregory Sanders
+- Jonas Schnelli
+- Matt Corallo
+- Russell Yanofsky
+- Shigeya Suzuki
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
+
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/.clang-format b/src/.clang-format
index fc53509138..5918819d13 100644
--- a/src/.clang-format
+++ b/src/.clang-format
@@ -47,6 +47,6 @@ SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
-Standard: Cpp03
+Standard: Cpp11
TabWidth: 8
UseTab: Never
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/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 714ee555ec..6093f78fb1 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -299,7 +299,6 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
if (!pubkey.IsFullyValid())
throw std::runtime_error("invalid TX output pubkey");
CScript scriptPubKey = GetScriptForRawPubKey(pubkey);
- CBitcoinAddress addr(scriptPubKey);
// Extract and validate FLAGS
bool bSegWit = false;
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 b45fc76338..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;
}
@@ -91,9 +95,9 @@ void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
}
}
-void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
+bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
CCoinsMap::iterator it = FetchCoin(outpoint);
- if (it == cacheCoins.end()) return;
+ if (it == cacheCoins.end()) return false;
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
if (moveout) {
*moveout = std::move(it->second.coin);
@@ -104,6 +108,7 @@ void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
it->second.flags |= CCoinsCacheEntry::DIRTY;
it->second.coin.Clear();
}
+ return true;
}
static const Coin coinEmpty;
@@ -124,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 dc3210b8ac..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
@@ -224,8 +226,13 @@ public:
/**
* Return a reference to Coin in the cache, or a pruned one if not found. This is
- * more efficient than GetCoin. Modifications to other cache entries are
- * allowed while accessing the returned pointer.
+ * more efficient than GetCoin.
+ *
+ * Generally, do not hold the reference returned for more than a short scope.
+ * While the current implementation allows for modifications to the contents
+ * of the cache while holding the reference, this behavior should not be relied
+ * on! To be safe, best to not hold the returned reference through any other
+ * calls to this cache.
*/
const Coin& AccessCoin(const COutPoint &output) const;
@@ -240,7 +247,7 @@ public:
* If no unspent output exists for the passed outpoint, this call
* has no effect.
*/
- void SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
+ bool SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
/**
* Push the modifications applied to this cache to its base.
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/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index bf68f8754b..0671cbc132 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -126,7 +126,9 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
unsigned int nSigOps = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- const CTxOut &prevout = inputs.AccessCoin(tx.vin[i].prevout).out;
+ const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
+ assert(!coin.IsSpent());
+ const CTxOut &prevout = coin.out;
if (prevout.scriptPubKey.IsPayToScriptHash())
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
}
@@ -146,7 +148,9 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
- const CTxOut &prevout = inputs.AccessCoin(tx.vin[i].prevout).out;
+ const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
+ assert(!coin.IsSpent());
+ const CTxOut &prevout = coin.out;
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags);
}
return nSigOps;
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/httpserver.cpp b/src/httpserver.cpp
index 0d1cba3fd2..1557cf98f8 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
@@ -367,9 +367,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 +392,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 +409,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 +417,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..88084cbeec 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,16 @@ bool AppInitParameterInteraction()
return InitError(_("Prune mode is incompatible with -txindex."));
}
+ // -bind and -whitebind can't be set when not listening
+ size_t nUserBind =
+ (gArgs.IsArgSet("-bind") ? gArgs.GetArgs("-bind").size() : 0) +
+ (gArgs.IsArgSet("-whitebind") ? gArgs.GetArgs("-whitebind").size() : 0);
+ 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);
@@ -1030,14 +1015,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", "")));
@@ -1289,16 +1267,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,36 +1317,6 @@ 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;
@@ -1645,7 +1583,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 +1598,45 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
+ 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));
+ }
+ connOptions.vBinds.push_back(addrBind);
+ }
+ }
+ 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));
+ }
+ connOptions.vWhiteBinds.push_back(addrBind);
+ }
+ }
+
+ if (gArgs.IsArgSet("-whitelist")) {
+ 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..91a62626a2 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);
}
}
}
@@ -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;
}
@@ -2226,7 +2221,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 +2274,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 b9357440e9..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
//////////////////////////////////////////////////////////////////////////////
//
@@ -342,7 +342,9 @@ bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const CBlockIndex*
// Short-circuit most stuff in case its from the same node
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end() && itInFlight->second.first == nodeid) {
- *pit = &itInFlight->second.second;
+ if (pit) {
+ *pit = &itInFlight->second.second;
+ }
return false;
}
@@ -557,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/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index dada689731..26dec3c610 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -33,8 +33,6 @@ static const CRPCCommand vRPCCommands[] =
void RPCNestedTests::rpcNestedTests()
{
- UniValue jsonRPCError;
-
// do some test setup
// could be moved to a more generic place when we add more tests on QT level
const CChainParams& chainparams = Params();
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/random.cpp b/src/random.cpp
index 7916643263..67efc7d945 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -72,10 +72,16 @@ static bool rdrand_supported = false;
static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
static void RDRandInit()
{
- //! When calling cpuid function #1, ecx register will have this set if RDRAND is available.
+ uint32_t eax, ecx, edx;
+#if defined(__i386__) && ( defined(__PIC__) || defined(__PIE__))
// Avoid clobbering ebx, as that is used for PIC on x86.
- uint32_t eax, tmp, ecx, edx;
+ uint32_t tmp;
__asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1));
+#else
+ uint32_t ebx;
+ __asm__ ("cpuid": "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
+#endif
+ //! When calling cpuid function #1, ecx register will have this set if RDRAND is available.
if (ecx & CPUID_F1_ECX_RDRAND) {
LogPrintf("Using RdRand as entropy source\n");
rdrand_supported = true;
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 1883005163..4cd64bf028 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -376,8 +376,10 @@ static std::pair<bool,std::string> ReadBinaryFile(const fs::path &filename, size
while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0) {
// Check for reading errors so we don't return any data if we couldn't
// read the entire file (or up to maxsize)
- if (ferror(f))
+ if (ferror(f)) {
+ fclose(f);
return std::make_pair(false,"");
+ }
retval.append(buffer, buffer+n);
if (retval.size() > maxsize)
break;
@@ -405,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 afafc695f4..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 {
@@ -1050,9 +1046,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
for (const CTransaction& tx : txn) {
for (const CTxIn& txin : tx.vin) {
if (exists(txin.prevout.hash)) continue;
- if (!mapNextTx.count(txin.prevout)) {
- pvNoSpendsRemaining->push_back(txin.prevout);
- }
+ pvNoSpendsRemaining->push_back(txin.prevout);
}
}
}
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..0e1464e590 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";
@@ -889,3 +891,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 76f8b32a5e..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)
@@ -187,62 +202,63 @@ public:
void ParseParameters(int argc, const char*const argv[]);
void ReadConfigFile(const std::string& confPath);
std::vector<std::string> GetArgs(const std::string& strArg);
-/**
- * Return true if the given argument has been manually set
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @return true if the argument has been set
- */
-bool IsArgSet(const std::string& strArg);
-
-/**
- * Return string argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param default (e.g. "1")
- * @return command-line argument or default value
- */
-std::string GetArg(const std::string& strArg, const std::string& strDefault);
-
-/**
- * Return integer argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param default (e.g. 1)
- * @return command-line argument (0 if invalid number) or default value
- */
-int64_t GetArg(const std::string& strArg, int64_t nDefault);
-
-/**
- * Return boolean argument or default value
- *
- * @param strArg Argument to get (e.g. "-foo")
- * @param default (true or false)
- * @return command-line argument or default value
- */
-bool GetBoolArg(const std::string& strArg, bool fDefault);
-
-/**
- * Set an argument if it doesn't already have a value
- *
- * @param strArg Argument to set (e.g. "-foo")
- * @param strValue Value (e.g. "1")
- * @return true if argument gets set, false if it already had a value
- */
-bool SoftSetArg(const std::string& strArg, const std::string& strValue);
-
-/**
- * Set a boolean argument if it doesn't already have a value
- *
- * @param strArg Argument to set (e.g. "-foo")
- * @param fValue Value (e.g. false)
- * @return true if argument gets set, false if it already had a value
- */
-bool SoftSetBoolArg(const std::string& strArg, bool fValue);
-// Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
-// been set. Also called directly in testing.
-void ForceSetArg(const std::string& strArg, const std::string& strValue);
+ /**
+ * Return true if the given argument has been manually set
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @return true if the argument has been set
+ */
+ bool IsArgSet(const std::string& strArg);
+
+ /**
+ * Return string argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param default (e.g. "1")
+ * @return command-line argument or default value
+ */
+ std::string GetArg(const std::string& strArg, const std::string& strDefault);
+
+ /**
+ * Return integer argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param default (e.g. 1)
+ * @return command-line argument (0 if invalid number) or default value
+ */
+ int64_t GetArg(const std::string& strArg, int64_t nDefault);
+
+ /**
+ * Return boolean argument or default value
+ *
+ * @param strArg Argument to get (e.g. "-foo")
+ * @param default (true or false)
+ * @return command-line argument or default value
+ */
+ bool GetBoolArg(const std::string& strArg, bool fDefault);
+
+ /**
+ * Set an argument if it doesn't already have a value
+ *
+ * @param strArg Argument to set (e.g. "-foo")
+ * @param strValue Value (e.g. "1")
+ * @return true if argument gets set, false if it already had a value
+ */
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
+
+ /**
+ * Set a boolean argument if it doesn't already have a value
+ *
+ * @param strArg Argument to set (e.g. "-foo")
+ * @param fValue Value (e.g. false)
+ * @return true if argument gets set, false if it already had a value
+ */
+ bool SoftSetBoolArg(const std::string& strArg, bool fValue);
+
+ // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
+ // been set. Also called directly in testing.
+ void ForceSetArg(const std::string& strArg, const std::string& strValue);
};
extern ArgsManager gArgs;
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 bef17337b9..eb6ea42b63 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -430,8 +430,9 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool?
- if (pool.exists(hash))
- return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool");
+ if (pool.exists(hash)) {
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-already-in-mempool");
+ }
// Check for conflicts with in-memory transactions
std::set<uint256> setConflicts;
@@ -469,8 +470,9 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
}
}
- if (fReplacementOptOut)
- return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
+ if (fReplacementOptOut) {
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-mempool-conflict");
+ }
setConflicts.insert(ptxConflicting->GetHash());
}
@@ -497,7 +499,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (!had_coin_in_cache) {
coins_to_uncache.push_back(outpoint);
}
- return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known");
+ return state.Invalid(false, REJECT_DUPLICATE, "txn-already-known");
}
}
@@ -1123,7 +1125,8 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
txundo.vprevout.reserve(tx.vin.size());
for (const CTxIn &txin : tx.vin) {
txundo.vprevout.emplace_back();
- inputs.SpendCoin(txin.prevout, &txundo.vprevout.back());
+ bool is_spent = inputs.SpendCoin(txin.prevout, &txundo.vprevout.back());
+ assert(is_spent);
}
}
// add outputs
@@ -1206,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
@@ -1294,7 +1297,7 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
return state.Error(strMessage);
}
-} // anon namespace
+} // namespace
enum DisconnectResult
{
@@ -1368,8 +1371,8 @@ static DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex*
if (!tx.vout[o].scriptPubKey.IsUnspendable()) {
COutPoint out(hash, o);
Coin coin;
- view.SpendCoin(out, &coin);
- if (tx.vout[o] != coin.out) {
+ bool is_spent = view.SpendCoin(out, &coin);
+ if (!is_spent || tx.vout[o] != coin.out) {
fClean = false; // transaction output mismatch
}
}
@@ -3322,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/validation.h b/src/validation.h
index 15e19bc511..82df4cb170 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -469,10 +469,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para
static const unsigned int REJECT_INTERNAL = 0x100;
/** Too high fee. Can not be triggered by P2P transactions */
static const unsigned int REJECT_HIGHFEE = 0x100;
-/** Transaction is already known (either in mempool or blockchain) */
-static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
-/** Transaction conflicts with a transaction already known */
-static const unsigned int REJECT_CONFLICT = 0x102;
/** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n);
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/crypter.cpp b/src/wallet/crypter.cpp
index 836c15b82c..6fa685628f 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -274,7 +274,6 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
// Check for watch-only pubkeys
return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
}
- return false;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
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/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 2e4105a569..5bbb5088e2 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1064,7 +1064,6 @@ public:
bool operator()(const CNoDestination &dest) const { return false; }
bool operator()(const CKeyID &keyID) {
- CPubKey pubkey;
if (pwallet) {
CScript basescript = GetScriptForDestination(keyID);
isminetype typ;
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 2c5c38eb94..0d1a86dd24 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -205,7 +205,6 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
vchCryptedSecret,
mapKeyMetadata[vchPubKey.GetID()]);
}
- return false;
}
bool CWallet::LoadKeyMetadata(const CTxDestination& keyID, const CKeyMetadata &meta)
@@ -221,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);
@@ -1469,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.
@@ -1489,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());
@@ -2634,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))
@@ -2709,8 +2713,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
nBytes = GetVirtualTransactionSize(txNew);
- CTransaction txNewConst(txNew);
-
// Remove scriptSigs to eliminate the fee calculation dummy signatures
for (auto& vin : txNew.vin) {
vin.scriptSig = CScript();
@@ -3866,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;
}
}
@@ -3890,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)
{
@@ -3906,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 45937ee21f..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;
@@ -77,7 +79,7 @@ class CScheduler;
class CTxMemPool;
class CBlockPolicyEstimator;
class CWalletTx;
-class FeeCalculation;
+struct FeeCalculation;
/** (client) version numbers for particular wallet features */
enum WalletFeature
@@ -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/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index eca6706c06..8321719b56 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -76,8 +76,6 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
const std::vector<unsigned char>& vchCryptedSecret,
const CKeyMetadata &keyMeta)
{
- const bool fEraseUnencryptedKey = true;
-
if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) {
return false;
}
@@ -85,12 +83,8 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) {
return false;
}
- if (fEraseUnencryptedKey)
- {
- EraseIC(std::make_pair(std::string("key"), vchPubKey));
- EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
- }
-
+ EraseIC(std::make_pair(std::string("key"), vchPubKey));
+ EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
return true;
}
diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py
index 6aef6d4489..e205c6400c 100755
--- a/test/functional/blockchain.py
+++ b/test/functional/blockchain.py
@@ -18,13 +18,16 @@ Tests correspond to code in rpc/blockchain.cpp.
"""
from decimal import Decimal
+import subprocess
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
+ assert_raises,
assert_raises_jsonrpc,
assert_is_hex_string,
assert_is_hash_string,
+ bitcoind_processes,
)
@@ -34,6 +37,7 @@ class BlockchainTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = False
self.num_nodes = 1
+ self.extra_args = [['-stopatheight=207']]
def run_test(self):
self._test_getchaintxstats()
@@ -41,7 +45,8 @@ class BlockchainTest(BitcoinTestFramework):
self._test_getblockheader()
self._test_getdifficulty()
self._test_getnetworkhashps()
- self.nodes[0].verifychain(4, 0)
+ self._test_stopatheight()
+ assert self.nodes[0].verifychain(4, 0)
def _test_getchaintxstats(self):
chaintxstats = self.nodes[0].getchaintxstats(1)
@@ -129,5 +134,18 @@ class BlockchainTest(BitcoinTestFramework):
# This should be 2 hashes every 10 minutes or 1/300
assert abs(hashes_per_second * 300 - 1) < 0.0001
+ def _test_stopatheight(self):
+ assert_equal(self.nodes[0].getblockcount(), 200)
+ self.nodes[0].generate(6)
+ assert_equal(self.nodes[0].getblockcount(), 206)
+ self.log.debug('Node should not stop at this height')
+ assert_raises(subprocess.TimeoutExpired, lambda: bitcoind_processes[0].wait(timeout=3))
+ self.nodes[0].generate(1)
+ self.log.debug('Node should stop at this height...')
+ bitcoind_processes[0].wait(timeout=3)
+ self.nodes[0] = self.start_node(0, self.options.tmpdir)
+ assert_equal(self.nodes[0].getblockcount(), 207)
+
+
if __name__ == '__main__':
BlockchainTest().main()
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/multi_rpc.py b/test/functional/multi_rpc.py
index 6ff91a960b..a30e15ace9 100755
--- a/test/functional/multi_rpc.py
+++ b/test/functional/multi_rpc.py
@@ -16,16 +16,21 @@ class HTTPBasicsTest (BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = False
- self.num_nodes = 1
+ self.num_nodes = 2
def setup_chain(self):
super().setup_chain()
#Append rpcauth to bitcoin.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
+ rpcuser = "rpcuser=rpcuser💻"
+ rpcpassword = "rpcpassword=rpcpassword🔑"
with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a', encoding='utf8') as f:
f.write(rpcauth+"\n")
f.write(rpcauth2+"\n")
+ with open(os.path.join(self.options.tmpdir+"/node1", "bitcoin.conf"), 'a', encoding='utf8') as f:
+ f.write(rpcuser+"\n")
+ f.write(rpcpassword+"\n")
def run_test(self):
@@ -50,7 +55,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
- assert_equal(resp.status==401, False)
+ assert_equal(resp.status, 200)
conn.close()
#Use new authpair to confirm both work
@@ -60,7 +65,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
- assert_equal(resp.status==401, False)
+ assert_equal(resp.status, 200)
conn.close()
#Wrong login name with rt's password
@@ -71,7 +76,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
- assert_equal(resp.status==401, True)
+ assert_equal(resp.status, 401)
conn.close()
#Wrong password for rt
@@ -82,7 +87,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
- assert_equal(resp.status==401, True)
+ assert_equal(resp.status, 401)
conn.close()
#Correct for rt2
@@ -93,7 +98,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
- assert_equal(resp.status==401, False)
+ assert_equal(resp.status, 200)
conn.close()
#Wrong password for rt2
@@ -104,7 +109,46 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
- assert_equal(resp.status==401, True)
+ assert_equal(resp.status, 401)
+ conn.close()
+
+ ###############################################################
+ # Check correctness of the rpcuser/rpcpassword config options #
+ ###############################################################
+ url = urllib.parse.urlparse(self.nodes[1].url)
+
+ # rpcuser and rpcpassword authpair
+ rpcuserauthpair = "rpcuser💻:rpcpassword🔑"
+
+ headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)}
+
+ conn = http.client.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status, 200)
+ conn.close()
+
+ #Wrong login name with rpcuser's password
+ rpcuserauthpair = "rpcuserwrong:rpcpassword"
+ headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)}
+
+ conn = http.client.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status, 401)
+ conn.close()
+
+ #Wrong password for rpcuser
+ rpcuserauthpair = "rpcuser:rpcpasswordwrong"
+ headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)}
+
+ conn = http.client.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status, 401)
conn.close()
diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py
index dbc61d21fc..63dfbb8ae6 100755
--- a/test/functional/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -1486,7 +1486,7 @@ class SegWitTest(BitcoinTestFramework):
# nodes would have stored, this requires special handling.
# To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to
# the test.
- def test_upgrade_after_activation(self, node, node_id):
+ def test_upgrade_after_activation(self, node_id):
self.log.info("Testing software upgrade after softfork activation")
assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind
@@ -1502,14 +1502,14 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# Make sure that this peer thinks segwit has activated.
- assert(get_bip9_status(node, 'segwit')['status'] == "active")
+ assert(get_bip9_status(self.nodes[node_id], 'segwit')['status'] == "active")
# Make sure this peers blocks match those of node0.
- height = node.getblockcount()
+ height = self.nodes[node_id].getblockcount()
while height >= 0:
- block_hash = node.getblockhash(height)
+ block_hash = self.nodes[node_id].getblockhash(height)
assert_equal(block_hash, self.nodes[0].getblockhash(height))
- assert_equal(self.nodes[0].getblock(block_hash), node.getblock(block_hash))
+ assert_equal(self.nodes[0].getblock(block_hash), self.nodes[node_id].getblock(block_hash))
height -= 1
@@ -1944,7 +1944,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_signature_version_1()
self.test_non_standard_witness()
sync_blocks(self.nodes)
- self.test_upgrade_after_activation(self.nodes[2], 2)
+ self.test_upgrade_after_activation(node_id=2)
self.test_witness_sigops()
diff --git a/test/functional/pruning.py b/test/functional/pruning.py
index 4c3501ad77..0af91e0658 100755
--- a/test/functional/pruning.py
+++ b/test/functional/pruning.py
@@ -315,17 +315,17 @@ class PruneTest(BitcoinTestFramework):
# check that the pruning node's wallet is still in good shape
self.log.info("Stop and start pruning node to trigger wallet rescan")
self.stop_node(2)
- self.start_node(2, self.options.tmpdir, ["-prune=550"])
+ 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)
nds = [self.nodes[0], self.nodes[5]]
sync_blocks(nds, wait=5, timeout=300)
self.stop_node(5) #stop and start to trigger rescan
- self.start_node(5, self.options.tmpdir, ["-prune=550"])
+ self.nodes[5] = self.start_node(5, self.options.tmpdir, ["-prune=550"])
self.log.info("Success")
def run_test(self):
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/rpcbind_test.py b/test/functional/rpcbind_test.py
index 5336cf2ec8..198599010e 100755
--- a/test/functional/rpcbind_test.py
+++ b/test/functional/rpcbind_test.py
@@ -49,7 +49,7 @@ class RPCBindTest(BitcoinTestFramework):
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
# connect to node through non-loopback interface
- node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0)
+ node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0)
node.getnetworkinfo()
self.stop_nodes()
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/test_framework.py b/test/functional/test_framework/test_framework.py
index 67abf35687..c7fd44b81c 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -28,6 +28,7 @@ from .util import (
get_mocktime,
get_rpc_proxy,
initialize_datadir,
+ get_datadir_path,
log_filename,
p2p_port,
rpc_url,
@@ -300,13 +301,13 @@ class BitcoinTestFramework(object):
args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
bitcoind_processes[i] = subprocess.Popen(args)
self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
- wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i)
+ wait_for_bitcoind_start(bitcoind_processes[i], datadir, i)
self.log.debug("initialize_chain: RPC successfully started")
self.nodes = []
for i in range(MAX_NODES):
try:
- self.nodes.append(get_rpc_proxy(rpc_url(i), i))
+ self.nodes.append(get_rpc_proxy(rpc_url(get_datadir_path(cachedir, i), i), i))
except:
self.log.exception("Error connecting to node %d" % i)
sys.exit(1)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 2b0f32c2b6..fa6388bf96 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -181,21 +181,40 @@ def initialize_datadir(dirname, n):
datadir = os.path.join(dirname, "node"+str(n))
if not os.path.isdir(datadir):
os.makedirs(datadir)
- rpc_u, rpc_p = rpc_auth_pair(n)
with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
f.write("regtest=1\n")
- f.write("rpcuser=" + rpc_u + "\n")
- f.write("rpcpassword=" + rpc_p + "\n")
f.write("port="+str(p2p_port(n))+"\n")
f.write("rpcport="+str(rpc_port(n))+"\n")
f.write("listenonion=0\n")
return datadir
-def rpc_auth_pair(n):
- return 'rpcuser💻' + str(n), 'rpcpass🔑' + str(n)
-
-def rpc_url(i, rpchost=None):
- rpc_u, rpc_p = rpc_auth_pair(i)
+def get_datadir_path(dirname, n):
+ return os.path.join(dirname, "node"+str(n))
+
+def get_auth_cookie(datadir, n):
+ user = None
+ password = None
+ if os.path.isfile(os.path.join(datadir, "bitcoin.conf")):
+ with open(os.path.join(datadir, "bitcoin.conf"), 'r') as f:
+ for line in f:
+ if line.startswith("rpcuser="):
+ assert user is None # Ensure that there is only one rpcuser line
+ user = line.split("=")[1].strip("\n")
+ if line.startswith("rpcpassword="):
+ assert password is None # Ensure that there is only one rpcpassword line
+ password = line.split("=")[1].strip("\n")
+ if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")):
+ with open(os.path.join(datadir, "regtest", ".cookie"), 'r') as f:
+ userpass = f.read()
+ split_userpass = userpass.split(':')
+ user = split_userpass[0]
+ password = split_userpass[1]
+ if user is None or password is None:
+ raise ValueError("No RPC credentials")
+ return user, password
+
+def rpc_url(datadir, i, rpchost=None):
+ rpc_u, rpc_p = get_auth_cookie(datadir, i)
host = '127.0.0.1'
port = rpc_port(i)
if rpchost:
@@ -206,7 +225,7 @@ def rpc_url(i, rpchost=None):
host = rpchost
return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, host, int(port))
-def wait_for_bitcoind_start(process, url, i):
+def wait_for_bitcoind_start(process, datadir, i, rpchost=None):
'''
Wait for bitcoind to start. This means that RPC is accessible and fully initialized.
Raise an exception if bitcoind exits during initialization.
@@ -215,7 +234,8 @@ def wait_for_bitcoind_start(process, url, i):
if process.poll() is not None:
raise Exception('bitcoind exited with status %i during initialization' % process.returncode)
try:
- rpc = get_rpc_proxy(url, i)
+ # Check if .cookie file to be created
+ rpc = get_rpc_proxy(rpc_url(datadir, i, rpchost), i)
blocks = rpc.getblockcount()
break # break out of loop on success
except IOError as e:
@@ -224,6 +244,9 @@ def wait_for_bitcoind_start(process, url, i):
except JSONRPCException as e: # Initialization phase
if e.error['code'] != -28: # RPC in warmup?
raise # unknown JSON RPC exception
+ except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting
+ if "No RPC credentials" not in str(e):
+ raise
time.sleep(0.25)
@@ -239,10 +262,9 @@ def _start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary
if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr)
logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
- url = rpc_url(i, rpchost)
- wait_for_bitcoind_start(bitcoind_processes[i], url, i)
+ wait_for_bitcoind_start(bitcoind_processes[i], datadir, i, rpchost)
logger.debug("initialize_chain: RPC successfully started")
- proxy = get_rpc_proxy(url, i, timeout=timewait)
+ proxy = get_rpc_proxy(rpc_url(datadir, i, rpchost), i, timeout=timewait)
if COVERAGE_DIR:
coverage.write_all_rpc_commands(COVERAGE_DIR, proxy)
@@ -300,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 1cac61d909..9952835951 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -20,6 +20,7 @@ import datetime
import os
import time
import shutil
+import signal
import sys
import subprocess
import tempfile
@@ -78,7 +79,7 @@ BASE_SCRIPTS= [
'rawtransactions.py',
'reindex.py',
# vv Tests less than 30s vv
- "zmq_test.py",
+ 'zmq_test.py',
'mempool_resurrect_test.py',
'txn_doublespend.py --mineblock',
'txn_clone.py',
@@ -112,6 +113,7 @@ BASE_SCRIPTS= [
'listsinceblock.py',
'p2p-leaktests.py',
'wallet-encryption.py',
+ 'uptime.py',
]
EXTENDED_SCRIPTS = [
@@ -391,6 +393,10 @@ class TestHandler:
time.sleep(.5)
for j in self.jobs:
(name, time0, proc, log_out, log_err) = j
+ if os.getenv('TRAVIS') == 'true' and int(time.time() - time0) > 20 * 60:
+ # In travis, timeout individual tests after 20 minutes (to stop tests hanging and not
+ # providing useful output.
+ proc.send_signal(signal.SIGINT)
if proc.poll() is not None:
log_out.seek(0), log_err.seek(0)
[stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)]
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
diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py
index ce39cfefdc..26c946d215 100755
--- a/test/functional/zmq_test.py
+++ b/test/functional/zmq_test.py
@@ -8,15 +8,15 @@ import os
import struct
from test_framework.test_framework import BitcoinTestFramework, SkipTest
-from test_framework.util import *
+from test_framework.util import (assert_equal,
+ bytes_to_hex_str,
+ )
class ZMQTest (BitcoinTestFramework):
def __init__(self):
super().__init__()
- self.num_nodes = 4
-
- port = 28332
+ self.num_nodes = 2
def setup_nodes(self):
# Try to import python3-zmq. Skip this test if the import fails.
@@ -28,7 +28,7 @@ class ZMQTest (BitcoinTestFramework):
# Check that bitcoin has been built with ZMQ enabled
config = configparser.ConfigParser()
if not self.options.configfile:
- self.options.configfile = os.path.dirname(__file__) + "/config.ini"
+ self.options.configfile = os.path.dirname(__file__) + "/../config.ini"
config.read_file(open(self.options.configfile))
if not config["components"].getboolean("ENABLE_ZMQ"):
@@ -36,59 +36,66 @@ class ZMQTest (BitcoinTestFramework):
self.zmqContext = zmq.Context()
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
+ self.zmqSubSocket.set(zmq.RCVTIMEO, 60000)
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
- self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % self.port)
- self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args=[
- ['-zmqpubhashtx=tcp://127.0.0.1:'+str(self.port), '-zmqpubhashblock=tcp://127.0.0.1:'+str(self.port)],
- [],
- [],
- []
- ])
+ ip_address = "tcp://127.0.0.1:28332"
+ self.zmqSubSocket.connect(ip_address)
+ extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []]
+ self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
def run_test(self):
- self.sync_all()
+ try:
+ self._zmq_test()
+ finally:
+ # Destroy the zmq context
+ self.log.debug("Destroying zmq context")
+ self.zmqContext.destroy(linger=None)
+ def _zmq_test(self):
genhashes = self.nodes[0].generate(1)
self.sync_all()
- self.log.info("listen...")
+ self.log.info("Wait for tx")
msg = self.zmqSubSocket.recv_multipart()
topic = msg[0]
assert_equal(topic, b"hashtx")
body = msg[1]
msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, 0) #must be sequence 0 on hashtx
+ assert_equal(msgSequence, 0) # must be sequence 0 on hashtx
+ self.log.info("Wait for block")
msg = self.zmqSubSocket.recv_multipart()
topic = msg[0]
body = msg[1]
msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, 0) #must be sequence 0 on hashblock
+ assert_equal(msgSequence, 0) # must be sequence 0 on hashblock
blkhash = bytes_to_hex_str(body)
- assert_equal(genhashes[0], blkhash) #blockhash from generate must be equal to the hash received over zmq
+ assert_equal(genhashes[0], blkhash) # blockhash from generate must be equal to the hash received over zmq
+ self.log.info("Generate 10 blocks (and 10 coinbase txes)")
n = 10
genhashes = self.nodes[1].generate(n)
self.sync_all()
zmqHashes = []
blockcount = 0
- for x in range(0,n*2):
+ for x in range(n * 2):
msg = self.zmqSubSocket.recv_multipart()
topic = msg[0]
body = msg[1]
if topic == b"hashblock":
zmqHashes.append(bytes_to_hex_str(body))
msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, blockcount+1)
+ assert_equal(msgSequence, blockcount + 1)
blockcount += 1
- for x in range(0,n):
- assert_equal(genhashes[x], zmqHashes[x]) #blockhash from generate must be equal to the hash received over zmq
+ for x in range(n):
+ assert_equal(genhashes[x], zmqHashes[x]) # blockhash from generate must be equal to the hash received over zmq
- #test tx from a second node
+ self.log.info("Wait for tx from second node")
+ # test tx from a second node
hashRPC = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
self.sync_all()
@@ -96,14 +103,12 @@ class ZMQTest (BitcoinTestFramework):
msg = self.zmqSubSocket.recv_multipart()
topic = msg[0]
body = msg[1]
- hashZMQ = ""
- if topic == b"hashtx":
- hashZMQ = bytes_to_hex_str(body)
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, blockcount+1)
-
- assert_equal(hashRPC, hashZMQ) #blockhash from generate must be equal to the hash received over zmq
+ assert_equal(topic, b"hashtx")
+ hashZMQ = bytes_to_hex_str(body)
+ msgSequence = struct.unpack('<I', msg[-1])[-1]
+ assert_equal(msgSequence, blockcount + 1)
+ assert_equal(hashRPC, hashZMQ) # txid from sendtoaddress must be equal to the hash received over zmq
if __name__ == '__main__':
- ZMQTest ().main ()
+ ZMQTest().main()