aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am5
-rw-r--r--build-aux/m4/l_atomic.m440
-rw-r--r--configure.ac21
-rw-r--r--contrib/README.md11
-rw-r--r--contrib/devtools/README.md9
-rwxr-xr-xcontrib/devtools/fix-copyright-headers.py77
-rwxr-xr-xcontrib/devtools/gen-manpages.sh29
-rwxr-xr-xcontrib/devtools/git-subtree-check.sh3
-rwxr-xr-xcontrib/devtools/optimize-pngs.py3
-rwxr-xr-xcontrib/devtools/security-check.py3
-rwxr-xr-xcontrib/devtools/test-security-check.py3
-rwxr-xr-xcontrib/gitian-build.sh392
-rw-r--r--contrib/gitian-keys/btcdrak-key.pgpbin8954 -> 4916 bytes
-rwxr-xr-xcontrib/macdeploy/detached-sig-apply.sh4
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh4
-rwxr-xr-xcontrib/macdeploy/extract-osx-sdk.sh33
-rw-r--r--contrib/qos/tc.sh4
-rwxr-xr-xcontrib/qt_translations.py22
-rwxr-xr-xcontrib/seeds/makeseeds.py3
-rw-r--r--contrib/spendfrom/README.md35
-rw-r--r--contrib/spendfrom/setup.py9
-rwxr-xr-xcontrib/spendfrom/spendfrom.py267
-rw-r--r--contrib/testgen/base58.py3
-rwxr-xr-xcontrib/testgen/gen_base58_test_vectors.py3
-rwxr-xr-xcontrib/tidy_datadir.sh3
-rwxr-xr-xcontrib/verify-commits/gpg.sh4
-rwxr-xr-xcontrib/verify-commits/pre-push-hook.sh4
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh4
-rw-r--r--contrib/verifybinaries/README.md22
-rwxr-xr-xcontrib/verifybinaries/verify.sh22
-rwxr-xr-xcontrib/zmq/zmq_sub.py3
-rw-r--r--depends/packages/expat.mk4
-rw-r--r--depends/packages/fontconfig.mk4
-rw-r--r--depends/packages/native_ccache.mk6
-rw-r--r--depends/packages/qt46.mk66
-rw-r--r--depends/patches/qt46/stlfix.patch10
-rw-r--r--doc/README_osx.md17
-rw-r--r--doc/build-openbsd.md46
-rw-r--r--doc/build-osx.md2
-rw-r--r--doc/build-unix.md5
-rw-r--r--doc/build-windows.md6
-rw-r--r--doc/developer-notes.md7
-rw-r--r--doc/gitian-building.md10
-rw-r--r--doc/man/Makefile.am1
-rw-r--r--doc/man/bitcoin-cli.184
-rw-r--r--doc/man/bitcoin-qt.1513
-rw-r--r--doc/man/bitcoin-tx.1107
-rw-r--r--doc/man/bitcoind.1492
-rw-r--r--doc/reduce-traffic.md3
-rw-r--r--doc/release-notes.md14
-rw-r--r--doc/release-process.md3
-rw-r--r--doc/translation_process.md4
-rw-r--r--qa/README.md4
-rwxr-xr-xqa/pull-tester/rpc-tests.py25
-rwxr-xr-xqa/rpc-tests/create_cache.py10
-rwxr-xr-xqa/rpc-tests/importprunedfunds.py35
-rwxr-xr-xqa/rpc-tests/nulldummy.py148
-rwxr-xr-xqa/rpc-tests/p2p-compactblocks.py58
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py28
-rwxr-xr-xqa/rpc-tests/rest.py10
-rw-r--r--qa/rpc-tests/test_framework/blockstore.py3
-rw-r--r--qa/rpc-tests/test_framework/script.py2
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py5
-rw-r--r--qa/rpc-tests/test_framework/util.py8
-rwxr-xr-xqa/rpc-tests/wallet-hd.py6
-rwxr-xr-xqa/rpc-tests/wallet.py5
-rwxr-xr-xqa/rpc-tests/walletbackup.py7
-rwxr-xr-xshare/qt/extract_strings_qt.py3
-rw-r--r--share/qt/protobuf.pri35
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.qttest.include6
-rw-r--r--src/addrdb.cpp218
-rw-r--r--src/addrdb.h103
-rw-r--r--src/addrman.cpp5
-rw-r--r--src/bitcoin-tx.cpp6
-rw-r--r--src/bitcoind.cpp5
-rw-r--r--src/blockencodings.h8
-rw-r--r--src/chain.h10
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/consensus/validation.h6
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/httprpc.cpp2
-rw-r--r--src/httpserver.cpp18
-rw-r--r--src/init.cpp120
-rw-r--r--src/main.cpp293
-rw-r--r--src/main.h21
-rw-r--r--src/net.cpp822
-rw-r--r--src/net.h570
-rw-r--r--src/netaddress.cpp4
-rw-r--r--src/netbase.cpp6
-rw-r--r--src/netbase.h2
-rw-r--r--src/primitives/transaction.cpp5
-rw-r--r--src/primitives/transaction.h7
-rw-r--r--src/protocol.h3
-rw-r--r--src/qt/addressbookpage.cpp16
-rw-r--r--src/qt/addresstablemodel.cpp12
-rw-r--r--src/qt/askpassphrasedialog.cpp8
-rw-r--r--src/qt/bantablemodel.cpp3
-rw-r--r--src/qt/bitcoingui.cpp50
-rw-r--r--src/qt/clientmodel.cpp30
-rw-r--r--src/qt/coincontroldialog.cpp12
-rw-r--r--src/qt/csvmodelwriter.cpp8
-rw-r--r--src/qt/editaddressdialog.cpp18
-rw-r--r--src/qt/guiutil.cpp15
-rw-r--r--src/qt/guiutil.h2
-rw-r--r--src/qt/intro.cpp4
-rw-r--r--src/qt/networkstyle.cpp6
-rw-r--r--src/qt/notificator.cpp12
-rw-r--r--src/qt/optionsdialog.cpp12
-rw-r--r--src/qt/overviewpage.cpp4
-rw-r--r--src/qt/paymentrequest.proto2
-rw-r--r--src/qt/paymentserver.cpp4
-rw-r--r--src/qt/peertablemodel.cpp21
-rw-r--r--src/qt/peertablemodel.h7
-rw-r--r--src/qt/platformstyle.cpp10
-rw-r--r--src/qt/qvalidatedlineedit.cpp8
-rw-r--r--src/qt/qvaluecombobox.cpp4
-rw-r--r--src/qt/receivecoinsdialog.cpp26
-rw-r--r--src/qt/receiverequestdialog.cpp12
-rwxr-xr-xsrc/qt/res/movies/makespinner.sh4
-rw-r--r--src/qt/rpcconsole.cpp278
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp51
-rw-r--r--src/qt/sendcoinsentry.cpp12
-rw-r--r--src/qt/signverifymessagedialog.cpp8
-rw-r--r--src/qt/test/rpcnestedtests.cpp93
-rw-r--r--src/qt/test/rpcnestedtests.h25
-rw-r--r--src/qt/test/test_main.cpp16
-rw-r--r--src/qt/transactiondesc.cpp1
-rw-r--r--src/qt/transactionfilterproxy.cpp8
-rw-r--r--src/qt/transactionrecord.h12
-rw-r--r--src/qt/transactiontablemodel.cpp18
-rw-r--r--src/qt/transactionview.cpp16
-rw-r--r--src/qt/walletframe.cpp8
-rw-r--r--src/qt/walletmodel.cpp19
-rw-r--r--src/qt/walletmodel.h10
-rw-r--r--src/qt/walletmodeltransaction.cpp4
-rw-r--r--src/qt/walletview.cpp44
-rw-r--r--src/rest.cpp14
-rw-r--r--src/rpc/blockchain.cpp157
-rw-r--r--src/rpc/client.cpp7
-rw-r--r--src/rpc/mining.cpp13
-rw-r--r--src/rpc/misc.cpp53
-rw-r--r--src/rpc/net.cpp123
-rw-r--r--src/rpc/protocol.h55
-rw-r--r--src/rpc/rawtransaction.cpp12
-rw-r--r--src/rpc/register.h12
-rw-r--r--src/rpc/server.h1
-rw-r--r--src/script/bitcoinconsensus.cpp4
-rw-r--r--src/script/interpreter.cpp54
-rw-r--r--src/script/interpreter.h13
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.h2
-rw-r--r--src/sync.h5
-rw-r--r--src/test/DoS_tests.cpp56
-rw-r--r--src/test/arith_uint256_tests.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp1
-rw-r--r--src/test/dbwrapper_tests.cpp6
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/net_tests.cpp6
-rw-r--r--src/test/prevector_tests.cpp62
-rw-r--r--src/test/script_P2SH_tests.cpp6
-rw-r--r--src/test/test_bitcoin.cpp8
-rw-r--r--src/test/test_bitcoin.h2
-rw-r--r--src/test/transaction_tests.cpp87
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp1
-rw-r--r--src/util.cpp22
-rw-r--r--src/util.h2
-rw-r--r--src/validationinterface.cpp4
-rw-r--r--src/validationinterface.h5
-rw-r--r--src/wallet/db.cpp8
-rw-r--r--src/wallet/db.h10
-rw-r--r--src/wallet/rpcdump.cpp9
-rw-r--r--src/wallet/rpcwallet.cpp36
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/test/accounting_tests.cpp24
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/wallet.cpp88
-rw-r--r--src/wallet/wallet.h18
-rw-r--r--src/wallet/walletdb.cpp17
-rw-r--r--src/zmq/zmqpublishnotifier.h2
184 files changed, 4861 insertions, 2187 deletions
diff --git a/.gitignore b/.gitignore
index 892b2a3e08..b9db7cbd39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,10 +103,7 @@ linux-build
win32-build
qa/pull-tester/run-bitcoind-for-test.sh
qa/pull-tester/tests_config.py
-qa/pull-tester/test.*/*
-qa/tmp
qa/cache/*
-share/BitcoindComparisonTool.jar
!src/leveldb*/Makefile
diff --git a/Makefile.am b/Makefile.am
index 37c1e98eca..2e061c3773 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,8 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
SUBDIRS = src
+if ENABLE_MAN
+SUBDIRS += doc/man
+endif
.PHONY: deploy FORCE
GZIP_ENV="-9n"
@@ -213,6 +216,8 @@ DISTCLEANFILES = qa/pull-tester/tests_config.pyc
.INTERMEDIATE: $(COVERAGE_INFO)
+DISTCHECK_CONFIGURE_FLAGS = --enable-man
+
clean-local:
rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP)
rm -rf qa/pull-tester/__pycache__
diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4
new file mode 100644
index 0000000000..906724b640
--- /dev/null
+++ b/build-aux/m4/l_atomic.m4
@@ -0,0 +1,40 @@
+# Some versions of gcc/libstdc++ require linking with -latomic if
+# using the C++ atomic library.
+#
+# Sourced from http://bugs.debian.org/797228
+
+m4_define([_CHECK_ATOMIC_testbody], [[
+ #include <atomic>
+ #include <cstdint>
+
+ int main() {
+ std::atomic<int64_t> a{};
+
+ int64_t v = 5;
+ int64_t r = a.fetch_add(v);
+ return static_cast<int>(r);
+ }
+]])
+
+AC_DEFUN([CHECK_ATOMIC], [
+
+ AC_LANG_PUSH(C++)
+
+ AC_MSG_CHECKING([whether std::atomic can be used without link library])
+
+ AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ LIBS="$LIBS -latomic"
+ AC_MSG_CHECKING([whether std::atomic needs -latomic])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([_CHECK_ATOMIC_testbody])],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_RESULT([no])
+ AC_MSG_FAILURE([cannot figure our how to use std::atomic])
+ ])
+ ])
+
+ AC_LANG_POP
+])
diff --git a/configure.ac b/configure.ac
index d332f4face..25b828f18c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -57,6 +57,9 @@ case $host in
esac
dnl Require C++11 compiler (no GNU extensions)
AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory])
+dnl Check if -latomic is required for <std::atomic>
+CHECK_ATOMIC
+
dnl Libtool init checks.
LT_INIT([pic-only])
@@ -66,7 +69,8 @@ AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AC_PATH_TOOL(GCOV, gcov)
AC_PATH_PROG(LCOV, lcov)
-AC_PATH_PROGS([PYTHON], [python3 python2.7 python2 python])
+dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893)
+AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python])
AC_PATH_PROG(GENHTML, genhtml)
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
@@ -167,6 +171,12 @@ AC_ARG_ENABLE([zmq],
AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], [])
+AC_ARG_ENABLE(man,
+ [AS_HELP_STRING([--disable-man],
+ [do not install man pages (default is to install)])],,
+ enable_man=yes)
+AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no)
+
# Enable debug
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],
@@ -355,8 +365,15 @@ case $host in
TARGET_OS=linux
LEVELDB_TARGET_FLAGS="-DOS_LINUX"
;;
+ *freebsd*)
+ LEVELDB_TARGET_FLAGS="-DOS_FREEBSD"
+ ;;
+ *openbsd*)
+ LEVELDB_TARGET_FLAGS="-DOS_OPENBSD"
+ ;;
*)
OTHER_OS=`echo ${host_os} | awk '{print toupper($0)}'`
+ AC_MSG_WARN([Guessing LevelDB OS as OS_${OTHER_OS}, please check whether this is correct, if not add an entry to configure.ac.])
LEVELDB_TARGET_FLAGS="-DOS_${OTHER_OS}"
;;
esac
@@ -1046,7 +1063,7 @@ AC_SUBST(EVENT_PTHREADS_LIBS)
AC_SUBST(ZMQ_LIBS)
AC_SUBST(PROTOBUF_LIBS)
AC_SUBST(QR_LIBS)
-AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
+AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh])
AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py])
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
diff --git a/contrib/README.md b/contrib/README.md
index a23b197cc6..ab5f57587e 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -1,11 +1,3 @@
-Wallet Tools
----------------------
-
-### [SpendFrom](/contrib/spendfrom) ###
-
-Use the raw transactions API to send coins received on a particular
-address (or addresses).
-
Repository Tools
---------------------
@@ -45,6 +37,9 @@ Scripts and notes for Mac builds.
### [RPM](/contrib/rpm) ###
RPM spec file for building bitcoin-core on RPM based distributions
+### [Gitian-build](/contrib/gitian-build.sh) ###
+Script for running full gitian builds.
+
Test and Verify Tools
---------------------
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index bb8b9246b8..60fe69e7e3 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -40,6 +40,12 @@ would be changed to:
```// Copyright (c) 2009-2015 The Bitcoin Core developers```
+gen-manpages.sh
+===============
+
+A small script to automatically create manpages in ../../doc/man by running the release binaries with the -help option.
+This requires help2man which can be found at: https://www.gnu.org/software/help2man/
+
git-subtree-check.sh
====================
@@ -51,8 +57,9 @@ maintained:
* for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master)
* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork)
* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master)
+* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)
-Usage: `git-subtree-check.sh DIR COMMIT`
+Usage: `git-subtree-check.sh DIR (COMMIT)`
`COMMIT` may be omitted, in which case `HEAD` is used.
diff --git a/contrib/devtools/fix-copyright-headers.py b/contrib/devtools/fix-copyright-headers.py
index b6414a551f..54836bd83f 100755
--- a/contrib/devtools/fix-copyright-headers.py
+++ b/contrib/devtools/fix-copyright-headers.py
@@ -1,5 +1,5 @@
-#!/usr/bin/env python
-'''
+#!/usr/bin/env python3
+"""
Run this script to update all the copyright headers of files
that were changed this year.
@@ -10,37 +10,58 @@ For example:
it will change it to
// Copyright (c) 2009-2015 The Bitcoin Core developers
-'''
-import os
+"""
+import subprocess
import time
import re
-year = time.gmtime()[0]
-CMD_GIT_DATE = 'git log --format=@%%at -1 %s | date +"%%Y" -u -f -'
-CMD_REGEX= "perl -pi -e 's/(20\d\d)(?:-20\d\d)? The Bitcoin/$1-%s The Bitcoin/' %s"
-REGEX_CURRENT= re.compile("%s The Bitcoin" % year)
-CMD_LIST_FILES= "find %s | grep %s"
+CMD_GIT_LIST_FILES = ['git', 'ls-files']
+CMD_GIT_DATE = ['git', 'log', '--format=%ad', '--date=short', '-1']
+CMD_PERL_REGEX = ['perl', '-pi', '-e']
+REGEX_TEMPLATE = 's/(20\\d\\d)(?:-20\\d\\d)? The Bitcoin/$1-%s The Bitcoin/'
-FOLDERS = ["./qa", "./src"]
+FOLDERS = ["qa/", "src/"]
EXTENSIONS = [".cpp",".h", ".py"]
+
def get_git_date(file_path):
- r = os.popen(CMD_GIT_DATE % file_path)
- for l in r:
- # Result is one line, so just return
- return l.replace("\n","")
- return ""
-
-n=1
-for folder in FOLDERS:
- for extension in EXTENSIONS:
- for file_path in os.popen(CMD_LIST_FILES % (folder, extension)):
- file_path = os.getcwd() + file_path[1:-1]
- if file_path.endswith(extension):
- git_date = get_git_date(file_path)
- if str(year) == git_date:
- # Only update if current year is not found
- if REGEX_CURRENT.search(open(file_path, "r").read()) is None:
- print n,"Last git edit", git_date, "-", file_path
- os.popen(CMD_REGEX % (year,file_path))
+ d = subprocess.run(CMD_GIT_DATE + [file_path],
+ stdout=subprocess.PIPE,
+ check=True,
+ universal_newlines=True).stdout
+ # yyyy-mm-dd
+ return d.split('-')[0]
+
+
+def skip_file(file_path):
+ for ext in EXTENSIONS:
+ if file_path.endswith(ext):
+ return False
+ else:
+ return True
+
+if __name__ == "__main__":
+ year = str(time.gmtime()[0])
+ regex_current = re.compile("%s The Bitcoin" % year)
+ n = 1
+ for folder in FOLDERS:
+ for file_path in subprocess.run(
+ CMD_GIT_LIST_FILES + [folder],
+ stdout=subprocess.PIPE,
+ check=True,
+ universal_newlines=True
+ ).stdout.split("\n"):
+ if skip_file(file_path):
+ # print(file_path, "(skip)")
+ continue
+ git_date = get_git_date(file_path)
+ if not year == git_date:
+ # print(file_path, year, "(skip)")
+ continue
+ if regex_current.search(open(file_path, "r").read()) is not None:
+ # already up to date
+ # print(file_path, year, "(skip)")
+ continue
+ print(n, file_path, "(update to %s)" % year)
+ subprocess.run(CMD_PERL_REGEX + [REGEX_TEMPLATE % year, file_path], check=True)
n = n + 1
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
new file mode 100755
index 0000000000..967717e1e0
--- /dev/null
+++ b/contrib/devtools/gen-manpages.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
+SRCDIR=${SRCDIR:-$TOPDIR/src}
+MANDIR=${MANDIR:-$TOPDIR/doc/man}
+
+BITCOIND=${BITCOIND:-$SRCDIR/bitcoind}
+BITCOINCLI=${BITCOINCLI:-$SRCDIR/bitcoin-cli}
+BITCOINTX=${BITCOINTX:-$SRCDIR/bitcoin-tx}
+BITCOINQT=${BITCOINQT:-$SRCDIR/qt/bitcoin-qt}
+
+[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1
+
+# The autodetected version git tag can screw up manpage output a little bit
+BTCVER=($($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }'))
+
+# Create a footer file with copyright content.
+# This gets autodetected fine for bitcoind if --version-string is not set,
+# but has different outcomes for bitcoin-qt and bitcoin-cli.
+echo "[COPYRIGHT]" > footer.h2m
+$BITCOIND --version | sed -n '1!p' >> footer.h2m
+
+for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $BITCOINQT; do
+ cmdname="${cmd##*/}"
+ help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd}
+ sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1
+done
+
+rm -f footer.h2m
diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh
index 1cb82fe682..2384d66cad 100755
--- a/contrib/devtools/git-subtree-check.sh
+++ b/contrib/devtools/git-subtree-check.sh
@@ -1,4 +1,7 @@
#!/bin/sh
+# Copyright (c) 2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
DIR="$1"
COMMIT="$2"
diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py
index 799e0cc7d0..b7b8dc0082 100755
--- a/contrib/devtools/optimize-pngs.py
+++ b/contrib/devtools/optimize-pngs.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text).
#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index c61d652641..b4b4b4603d 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2015-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Perform basic ELF security checks on a series of executables.
Exit status will be 0 if successful, and the program will be silent.
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index 324b7bcd85..c0f120392e 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python2
+# Copyright (c) 2015-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Test script for security-check.py
'''
diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh
new file mode 100755
index 0000000000..53c24e3a87
--- /dev/null
+++ b/contrib/gitian-build.sh
@@ -0,0 +1,392 @@
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# What to do
+sign=false
+verify=false
+build=false
+setupenv=false
+
+# Systems to build
+linux=true
+windows=true
+osx=true
+
+# Other Basic variables
+SIGNER=
+VERSION=
+commit=false
+url=https://github.com/bitcoin/bitcoin
+proc=2
+mem=2000
+lxc=true
+osslTarUrl=http://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz
+osslPatchUrl=https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch
+scriptName=$(basename -- "$0")
+signProg="gpg --detach-sign"
+commitFiles=true
+
+# Help Message
+read -d '' usage <<- EOF
+Usage: $scriptName [-c|u|v|b|s|B|o|h|j|m|] signer version
+
+Run this script from the directory containing the bitcoin, gitian-builder, gitian.sigs, and bitcoin-detached-sigs.
+
+Arguments:
+signer GPG signer to sign each build assert file
+version Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified
+
+Options:
+-c|--commit Indicate that the version argument is for a commit or branch
+-u|--url Specify the URL of the repository. Default is https://github.com/bitcoin/bitcoin
+-v|--verify Verify the gitian build
+-b|--build Do a gitiain build
+-s|--sign Make signed binaries for Windows and Mac OSX
+-B|--buildsign Build both signed and unsigned binaries
+-o|--os Specify which Operating Systems the build is for. Default is lwx. l for linux, w for windows, x for osx
+-j Number of processes to use. Default 2
+-m Memory to allocate in MiB. Default 2000
+--kvm Use KVM instead of LXC
+--setup Setup the gitian building environment. Uses KVM. If you want to use lxc, use the --lxc option. Only works on Debian-based systems (Ubuntu, Debian)
+--detach-sign Create the assert file for detached signing. Will not commit anything.
+--no-commit Do not commit anything to git
+-h|--help Print this help message
+EOF
+
+# Get options and arguments
+while :; do
+ case $1 in
+ # Verify
+ -v|--verify)
+ verify=true
+ ;;
+ # Build
+ -b|--build)
+ build=true
+ ;;
+ # Sign binaries
+ -s|--sign)
+ sign=true
+ ;;
+ # Build then Sign
+ -B|--buildsign)
+ sign=true
+ build=true
+ ;;
+ # PGP Signer
+ -S|--signer)
+ if [ -n "$2" ]
+ then
+ SIGNER=$2
+ shift
+ else
+ echo 'Error: "--signer" requires a non-empty argument.'
+ exit 1
+ fi
+ ;;
+ # Operating Systems
+ -o|--os)
+ if [ -n "$2" ]
+ then
+ linux=false
+ windows=false
+ osx=false
+ if [[ "$2" = *"l"* ]]
+ then
+ linux=true
+ fi
+ if [[ "$2" = *"w"* ]]
+ then
+ windows=true
+ fi
+ if [[ "$2" = *"x"* ]]
+ then
+ osx=true
+ fi
+ shift
+ else
+ echo 'Error: "--os" requires an argument containing an l (for linux), w (for windows), or x (for Mac OSX)\n'
+ exit 1
+ fi
+ ;;
+ # Help message
+ -h|--help)
+ echo "$usage"
+ exit 0
+ ;;
+ # Commit or branch
+ -c|--commit)
+ commit=true
+ ;;
+ # Number of Processes
+ -j)
+ if [ -n "$2" ]
+ then
+ proc=$2
+ shift
+ else
+ echo 'Error: "-j" requires an argument'
+ exit 1
+ fi
+ ;;
+ # Memory to allocate
+ -m)
+ if [ -n "$2" ]
+ then
+ mem=$2
+ shift
+ else
+ echo 'Error: "-m" requires an argument'
+ exit 1
+ fi
+ ;;
+ # URL
+ -u)
+ if [ -n "$2" ]
+ then
+ url=$2
+ shift
+ else
+ echo 'Error: "-u" requires an argument'
+ exit 1
+ fi
+ ;;
+ # kvm
+ --kvm)
+ lxc=false
+ ;;
+ # Detach sign
+ --detach-sign)
+ signProg="true"
+ commitFiles=false
+ ;;
+ # Commit files
+ --no-commit)
+ commitFiles=false
+ ;;
+ # Setup
+ --setup)
+ setup=true
+ ;;
+ *) # Default case: If no more options then break out of the loop.
+ break
+ esac
+ shift
+done
+
+# Set up LXC
+if [[ $lxc = true ]]
+then
+ export USE_LXC=1
+ export LXC_BRIDGE=lxcbr0
+ sudo ifconfig lxcbr0 up 10.0.2.2
+fi
+
+# Check for OSX SDK
+if [[ ! -e "gitian-builder/inputs/MacOSX10.11.sdk.tar.gz" && $osx == true ]]
+then
+ echo "Cannot build for OSX, SDK does not exist. Will build for other OSes"
+ osx=false
+fi
+
+# Get signer
+if [[ -n"$1" ]]
+then
+ SIGNER=$1
+ shift
+fi
+
+# Get version
+if [[ -n "$1" ]]
+then
+ VERSION=$1
+ COMMIT=$VERSION
+ shift
+fi
+
+# Check that a signer is specified
+if [[ $SIGNER == "" ]]
+then
+ echo "$scriptName: Missing signer."
+ echo "Try $scriptName --help for more information"
+ exit 1
+fi
+
+# Check that a version is specified
+if [[ $VERSION == "" ]]
+then
+ echo "$scriptName: Missing version."
+ echo "Try $scriptName --help for more information"
+ exit 1
+fi
+
+# Add a "v" if no -c
+if [[ $commit = false ]]
+then
+ COMMIT="v${VERSION}"
+fi
+echo ${COMMIT}
+
+# Setup build environment
+if [[ $setup = true ]]
+then
+ sudo apt-get install ruby apache2 git apt-cacher-ng python-vm-builder qemu-kvm qemu-utils
+ git clone https://github.com/bitcoin-core/gitian.sigs.git
+ git clone https://github.com/bitcoin-core/bitcoin-detached-sigs.git
+ git clone https://github.com/devrandom/gitian-builder.git
+ pushd ./gitian-builder
+ if [[ -n "$USE_LXC" ]]
+ then
+ sudo apt-get install lxc
+ bin/make-base-vm --suite trusty --arch amd64 --lxc
+ else
+ bin/make-base-vm --suite trusty --arch amd64
+ fi
+ popd
+fi
+
+# Set up build
+pushd ./bitcoin
+git fetch
+git checkout ${COMMIT}
+popd
+
+# Build
+if [[ $build = true ]]
+then
+ # Make output folder
+ mkdir -p ./bitcoin-binaries/${VERSION}
+
+ # Build Dependencies
+ echo ""
+ echo "Building Dependencies"
+ echo ""
+ pushd ./gitian-builder
+ mkdir -p inputs
+ wget -N -P inputs $osslPatchUrl
+ wget -N -P inputs $osslTarUrl
+ make -C ../bitcoin/depends download SOURCES_PATH=`pwd`/cache/common
+
+ # Linux
+ if [[ $linux = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Linux"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-linux --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ mv build/out/bitcoin-*.tar.gz build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/${VERSION}
+ fi
+ # Windows
+ if [[ $windows = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Windows"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz
+ mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/${VERSION}
+ fi
+ # Mac OSX
+ if [[ $osx = true ]]
+ then
+ echo ""
+ echo "Compiling ${VERSION} Mac OSX"
+ echo ""
+ ./bin/gbuild -j ${proc} -m ${mem} --commit bitcoin=${COMMIT} --url bitcoin=${url} ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-unsigned --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz
+ mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/${VERSION}
+ fi
+ popd
+
+ if [[ $commitFiles = true ]]
+ then
+ # Commit to gitian.sigs repo
+ echo ""
+ echo "Committing ${VERSION} Unsigned Sigs"
+ echo ""
+ pushd gitian.sigs
+ git add ${VERSION}-linux/${SIGNER}
+ git add ${VERSION}-win-unsigned/${SIGNER}
+ git add ${VERSION}-osx-unsigned/${SIGNER}
+ git commit -a -m "Add ${VERSION} unsigned sigs for ${SIGNER}"
+ popd
+ fi
+fi
+
+# Verify the build
+if [[ $verify = true ]]
+then
+ # Linux
+ pushd ./gitian-builder
+ echo ""
+ echo "Verifying v${VERSION} Linux"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-linux ../bitcoin/contrib/gitian-descriptors/gitian-linux.yml
+ # Windows
+ echo ""
+ echo "Verifying v${VERSION} Windows"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-win.yml
+ # Mac OSX
+ echo ""
+ echo "Verifying v${VERSION} Mac OSX"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-unsigned ../bitcoin/contrib/gitian-descriptors/gitian-osx.yml
+ # Signed Windows
+ echo ""
+ echo "Verifying v${VERSION} Signed Windows"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ # Signed Mac OSX
+ echo ""
+ echo "Verifying v${VERSION} Signed Mac OSX"
+ echo ""
+ ./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-osx-signed ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ popd
+fi
+
+# Sign binaries
+if [[ $sign = true ]]
+then
+
+ pushd ./gitian-builder
+ # Sign Windows
+ if [[ $windows = true ]]
+ then
+ echo ""
+ echo "Signing ${VERSION} Windows"
+ echo ""
+ ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
+ mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/${VERSION}
+ mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/${VERSION}
+ fi
+ # Sign Mac OSX
+ if [[ $osx = true ]]
+ then
+ echo ""
+ echo "Signing ${VERSION} Mac OSX"
+ echo ""
+ ./bin/gbuild -i --commit signature=${COMMIT} ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ ./bin/gsign -p $signProg --signer $SIGNER --release ${VERSION}-osx-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml
+ mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/${VERSION}/bitcoin-${VERSION}-osx.dmg
+ fi
+ popd
+
+ if [[ $commitFiles = true ]]
+ then
+ # Commit Sigs
+ pushd gitian.sigs
+ echo ""
+ echo "Committing ${VERSION} Signed Sigs"
+ echo ""
+ git add ${VERSION}-win-signed/${SIGNER}
+ git add ${VERSION}-osx-signed/${SIGNER}
+ git commit -a -m "Add ${VERSION} signed binary sigs for ${SIGNER}"
+ popd
+ fi
+fi
diff --git a/contrib/gitian-keys/btcdrak-key.pgp b/contrib/gitian-keys/btcdrak-key.pgp
index 60d76c0ec7..f00dc729d5 100644
--- a/contrib/gitian-keys/btcdrak-key.pgp
+++ b/contrib/gitian-keys/btcdrak-key.pgp
Binary files differ
diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh
index 781fe315ed..91674a92e6 100755
--- a/contrib/macdeploy/detached-sig-apply.sh
+++ b/contrib/macdeploy/detached-sig-apply.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
set -e
UNSIGNED="$1"
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index 89a2da32f7..5022ea88bc 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
set -e
ROOTDIR=dist
diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh
new file mode 100755
index 0000000000..ff9fbd58df
--- /dev/null
+++ b/contrib/macdeploy/extract-osx-sdk.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+set -e
+
+INPUTFILE="Xcode_7.3.1.dmg"
+HFSFILENAME="5.hfs"
+SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk"
+
+7z x "${INPUTFILE}" "${HFSFILENAME}"
+SDKNAME="$(basename "${SDKDIR}")"
+SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}")
+fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} |
+ while read type inode filename; do
+ inode="${inode::-1}"
+ if [ "${filename:0:14}" = "usr/share/man/" ]; then
+ continue
+ fi
+ filename="${SDKNAME}/$filename"
+ echo "Extracting $filename ..."
+ mkdir -p "$(dirname "$filename")"
+ if [ "$type" = "l/l" ]; then
+ ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename"
+ else
+ icat "${HFSFILENAME}" $inode >"$filename"
+ fi
+done
+echo "Building ${SDKNAME}.tar.gz ..."
+MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')"
+find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz"
+echo 'All done!'
diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh
index f620604212..aaf5e1fa11 100644
--- a/contrib/qos/tc.sh
+++ b/contrib/qos/tc.sh
@@ -1,3 +1,7 @@
+# Copyright (c) 2013 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
#network interface on which to limit traffic
IF="eth0"
#limit of the network interface in question
diff --git a/contrib/qt_translations.py b/contrib/qt_translations.py
deleted file mode 100755
index fd8a8b7129..0000000000
--- a/contrib/qt_translations.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-
-# Helpful little script that spits out a comma-separated list of
-# language codes for Qt icons that should be included
-# in binary bitcoin distributions
-
-import glob
-import os
-import re
-import sys
-
-if len(sys.argv) != 3:
- sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0])
-
-d1 = sys.argv[1]
-d2 = sys.argv[2]
-
-l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ])
-l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ])
-
-print ",".join(sorted(l1.intersection(l2)))
-
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 4072405ef5..041f224f40 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2013-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Generate seeds.txt from Pieter's DNS seeder
#
diff --git a/contrib/spendfrom/README.md b/contrib/spendfrom/README.md
deleted file mode 100644
index c0a9c9ccf9..0000000000
--- a/contrib/spendfrom/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-### SpendFrom ###
-
-Use the raw transactions API to send coins received on a particular
-address (or addresses).
-
-### Usage: ###
-Depends on [jsonrpc](http://json-rpc.org/).
-
- spendfrom.py --from=FROMADDRESS1[,FROMADDRESS2] --to=TOADDRESS --amount=amount \
- --fee=fee --datadir=/path/to/.bitcoin --testnet --dry_run
-
-With no arguments, outputs a list of amounts associated with addresses.
-
-With arguments, sends coins received by the `FROMADDRESS` addresses to the `TOADDRESS`.
-
-### Notes ###
-
-- You may explicitly specify how much fee to pay (a fee more than 1% of the amount
-will fail, though, to prevent bitcoin-losing accidents). Spendfrom may fail if
-it thinks the transaction would never be confirmed (if the amount being sent is
-too small, or if the transaction is too many bytes for the fee).
-
-- If a change output needs to be created, the change will be sent to the last
-`FROMADDRESS` (if you specify just one `FROMADDRESS`, change will go back to it).
-
-- If `--datadir` is not specified, the default datadir is used.
-
-- The `--dry_run` option will just create and sign the transaction and print
-the transaction data (as hexadecimal), instead of broadcasting it.
-
-- If the transaction is created and broadcast successfully, a transaction id
-is printed.
-
-- If this was a tool for end-users and not programmers, it would have much friendlier
-error-handling.
diff --git a/contrib/spendfrom/setup.py b/contrib/spendfrom/setup.py
deleted file mode 100644
index 01b9768a5b..0000000000
--- a/contrib/spendfrom/setup.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from distutils.core import setup
-setup(name='btcspendfrom',
- version='1.0',
- description='Command-line utility for bitcoin "coin control"',
- author='Gavin Andresen',
- author_email='gavin@bitcoinfoundation.org',
- requires=['jsonrpc'],
- scripts=['spendfrom.py'],
- )
diff --git a/contrib/spendfrom/spendfrom.py b/contrib/spendfrom/spendfrom.py
deleted file mode 100755
index 72ee0425eb..0000000000
--- a/contrib/spendfrom/spendfrom.py
+++ /dev/null
@@ -1,267 +0,0 @@
-#!/usr/bin/env python
-#
-# Use the raw transactions API to spend bitcoins received on particular addresses,
-# and send any change back to that same address.
-#
-# Example usage:
-# spendfrom.py # Lists available funds
-# spendfrom.py --from=ADDRESS --to=ADDRESS --amount=11.00
-#
-# Assumes it will talk to a bitcoind or Bitcoin-Qt running
-# on localhost.
-#
-# Depends on jsonrpc
-#
-
-from decimal import *
-import getpass
-import math
-import os
-import os.path
-import platform
-import sys
-import time
-from jsonrpc import ServiceProxy, json
-
-BASE_FEE=Decimal("0.001")
-
-def check_json_precision():
- """Make sure json library being used does not lose precision converting BTC values"""
- n = Decimal("20000000.00000003")
- satoshis = int(json.loads(json.dumps(float(n)))*1.0e8)
- if satoshis != 2000000000000003:
- raise RuntimeError("JSON encode/decode loses precision")
-
-def determine_db_dir():
- """Return the default location of the bitcoin data directory"""
- if platform.system() == "Darwin":
- return os.path.expanduser("~/Library/Application Support/Bitcoin/")
- elif platform.system() == "Windows":
- return os.path.join(os.environ['APPDATA'], "Bitcoin")
- return os.path.expanduser("~/.bitcoin")
-
-def read_bitcoin_config(dbdir):
- """Read the bitcoin.conf file from dbdir, returns dictionary of settings"""
- from ConfigParser import SafeConfigParser
-
- class FakeSecHead(object):
- def __init__(self, fp):
- self.fp = fp
- self.sechead = '[all]\n'
- def readline(self):
- if self.sechead:
- try: return self.sechead
- finally: self.sechead = None
- else:
- s = self.fp.readline()
- if s.find('#') != -1:
- s = s[0:s.find('#')].strip() +"\n"
- return s
-
- config_parser = SafeConfigParser()
- config_parser.readfp(FakeSecHead(open(os.path.join(dbdir, "bitcoin.conf"))))
- return dict(config_parser.items("all"))
-
-def connect_JSON(config):
- """Connect to a bitcoin JSON-RPC server"""
- testnet = config.get('testnet', '0')
- testnet = (int(testnet) > 0) # 0/1 in config file, convert to True/False
- if not 'rpcport' in config:
- config['rpcport'] = 18332 if testnet else 8332
- connect = "http://%s:%s@127.0.0.1:%s"%(config['rpcuser'], config['rpcpassword'], config['rpcport'])
- try:
- result = ServiceProxy(connect)
- # ServiceProxy is lazy-connect, so send an RPC command mostly to catch connection errors,
- # but also make sure the bitcoind we're talking to is/isn't testnet:
- if result.getmininginfo()['testnet'] != testnet:
- sys.stderr.write("RPC server at "+connect+" testnet setting mismatch\n")
- sys.exit(1)
- return result
- except:
- sys.stderr.write("Error connecting to RPC server at "+connect+"\n")
- sys.exit(1)
-
-def unlock_wallet(bitcoind):
- info = bitcoind.getinfo()
- if 'unlocked_until' not in info:
- return True # wallet is not encrypted
- t = int(info['unlocked_until'])
- if t <= time.time():
- try:
- passphrase = getpass.getpass("Wallet is locked; enter passphrase: ")
- bitcoind.walletpassphrase(passphrase, 5)
- except:
- sys.stderr.write("Wrong passphrase\n")
-
- info = bitcoind.getinfo()
- return int(info['unlocked_until']) > time.time()
-
-def list_available(bitcoind):
- address_summary = dict()
-
- address_to_account = dict()
- for info in bitcoind.listreceivedbyaddress(0):
- address_to_account[info["address"]] = info["account"]
-
- unspent = bitcoind.listunspent(0)
- for output in unspent:
- # listunspent doesn't give addresses, so:
- rawtx = bitcoind.getrawtransaction(output['txid'], 1)
- vout = rawtx["vout"][output['vout']]
- pk = vout["scriptPubKey"]
-
- # This code only deals with ordinary pay-to-bitcoin-address
- # or pay-to-script-hash outputs right now; anything exotic is ignored.
- if pk["type"] != "pubkeyhash" and pk["type"] != "scripthash":
- continue
-
- address = pk["addresses"][0]
- if address in address_summary:
- address_summary[address]["total"] += vout["value"]
- address_summary[address]["outputs"].append(output)
- else:
- address_summary[address] = {
- "total" : vout["value"],
- "outputs" : [output],
- "account" : address_to_account.get(address, "")
- }
-
- return address_summary
-
-def select_coins(needed, inputs):
- # Feel free to improve this, this is good enough for my simple needs:
- outputs = []
- have = Decimal("0.0")
- n = 0
- while have < needed and n < len(inputs):
- outputs.append({ "txid":inputs[n]["txid"], "vout":inputs[n]["vout"]})
- have += inputs[n]["amount"]
- n += 1
- return (outputs, have-needed)
-
-def create_tx(bitcoind, fromaddresses, toaddress, amount, fee):
- all_coins = list_available(bitcoind)
-
- total_available = Decimal("0.0")
- needed = amount+fee
- potential_inputs = []
- for addr in fromaddresses:
- if addr not in all_coins:
- continue
- potential_inputs.extend(all_coins[addr]["outputs"])
- total_available += all_coins[addr]["total"]
-
- if total_available < needed:
- sys.stderr.write("Error, only %f BTC available, need %f\n"%(total_available, needed));
- sys.exit(1)
-
- #
- # Note:
- # Python's json/jsonrpc modules have inconsistent support for Decimal numbers.
- # Instead of wrestling with getting json.dumps() (used by jsonrpc) to encode
- # Decimals, I'm casting amounts to float before sending them to bitcoind.
- #
- outputs = { toaddress : float(amount) }
- (inputs, change_amount) = select_coins(needed, potential_inputs)
- if change_amount > BASE_FEE: # don't bother with zero or tiny change
- change_address = fromaddresses[-1]
- if change_address in outputs:
- outputs[change_address] += float(change_amount)
- else:
- outputs[change_address] = float(change_amount)
-
- rawtx = bitcoind.createrawtransaction(inputs, outputs)
- signed_rawtx = bitcoind.signrawtransaction(rawtx)
- if not signed_rawtx["complete"]:
- sys.stderr.write("signrawtransaction failed\n")
- sys.exit(1)
- txdata = signed_rawtx["hex"]
-
- return txdata
-
-def compute_amount_in(bitcoind, txinfo):
- result = Decimal("0.0")
- for vin in txinfo['vin']:
- in_info = bitcoind.getrawtransaction(vin['txid'], 1)
- vout = in_info['vout'][vin['vout']]
- result = result + vout['value']
- return result
-
-def compute_amount_out(txinfo):
- result = Decimal("0.0")
- for vout in txinfo['vout']:
- result = result + vout['value']
- return result
-
-def sanity_test_fee(bitcoind, txdata_hex, max_fee):
- class FeeError(RuntimeError):
- pass
- try:
- txinfo = bitcoind.decoderawtransaction(txdata_hex)
- total_in = compute_amount_in(bitcoind, txinfo)
- total_out = compute_amount_out(txinfo)
- if total_in-total_out > max_fee:
- raise FeeError("Rejecting transaction, unreasonable fee of "+str(total_in-total_out))
-
- tx_size = len(txdata_hex)/2
- kb = tx_size/1000 # integer division rounds down
- if kb > 1 and fee < BASE_FEE:
- raise FeeError("Rejecting no-fee transaction, larger than 1000 bytes")
- if total_in < 0.01 and fee < BASE_FEE:
- raise FeeError("Rejecting no-fee, tiny-amount transaction")
- # Exercise for the reader: compute transaction priority, and
- # warn if this is a very-low-priority transaction
-
- except FeeError as err:
- sys.stderr.write((str(err)+"\n"))
- sys.exit(1)
-
-def main():
- import optparse
-
- parser = optparse.OptionParser(usage="%prog [options]")
- parser.add_option("--from", dest="fromaddresses", default=None,
- help="addresses to get bitcoins from")
- parser.add_option("--to", dest="to", default=None,
- help="address to get send bitcoins to")
- parser.add_option("--amount", dest="amount", default=None,
- help="amount to send")
- parser.add_option("--fee", dest="fee", default="0.0",
- help="fee to include")
- parser.add_option("--datadir", dest="datadir", default=determine_db_dir(),
- help="location of bitcoin.conf file with RPC username/password (default: %default)")
- parser.add_option("--testnet", dest="testnet", default=False, action="store_true",
- help="Use the test network")
- parser.add_option("--dry_run", dest="dry_run", default=False, action="store_true",
- help="Don't broadcast the transaction, just create and print the transaction data")
-
- (options, args) = parser.parse_args()
-
- check_json_precision()
- config = read_bitcoin_config(options.datadir)
- if options.testnet: config['testnet'] = True
- bitcoind = connect_JSON(config)
-
- if options.amount is None:
- address_summary = list_available(bitcoind)
- for address,info in address_summary.iteritems():
- n_transactions = len(info['outputs'])
- if n_transactions > 1:
- print("%s %.8f %s (%d transactions)"%(address, info['total'], info['account'], n_transactions))
- else:
- print("%s %.8f %s"%(address, info['total'], info['account']))
- else:
- fee = Decimal(options.fee)
- amount = Decimal(options.amount)
- while unlock_wallet(bitcoind) == False:
- pass # Keep asking for passphrase until they get it right
- txdata = create_tx(bitcoind, options.fromaddresses.split(","), options.to, amount, fee)
- sanity_test_fee(bitcoind, txdata, amount*Decimal("0.01"))
- if options.dry_run:
- print(txdata)
- else:
- txid = bitcoind.sendrawtransaction(txdata)
- print(txid)
-
-if __name__ == '__main__':
- main()
diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py
index b716495145..72b288b2dc 100644
--- a/contrib/testgen/base58.py
+++ b/contrib/testgen/base58.py
@@ -1,3 +1,6 @@
+# Copyright (c) 2012 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Bitcoin base58 encoding and decoding.
diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py
index 1813436953..8518774db3 100755
--- a/contrib/testgen/gen_base58_test_vectors.py
+++ b/contrib/testgen/gen_base58_test_vectors.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2012 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Generate valid and invalid base58 address and private key test vectors.
diff --git a/contrib/tidy_datadir.sh b/contrib/tidy_datadir.sh
index 5d6d826444..8960f8811d 100755
--- a/contrib/tidy_datadir.sh
+++ b/contrib/tidy_datadir.sh
@@ -1,4 +1,7 @@
#!/bin/bash
+# Copyright (c) 2013 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
if [ -d "$1" ]; then
cd "$1"
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
index 375d711725..09ff237544 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2014-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
INPUT=$(cat /dev/stdin)
VALID=false
REVSIG=false
diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh
index c57222818a..c21febb9e9 100755
--- a/contrib/verify-commits/pre-push-hook.sh
+++ b/contrib/verify-commits/pre-push-hook.sh
@@ -1,4 +1,8 @@
#!/bin/bash
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then
exit 0
fi
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
index 5219331e2e..cfe4f11a0b 100755
--- a/contrib/verify-commits/verify-commits.sh
+++ b/contrib/verify-commits/verify-commits.sh
@@ -1,4 +1,8 @@
#!/bin/sh
+# Copyright (c) 2014-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
# Not technically POSIX-compliant due to use of "local", but almost every
# shell anyone uses today supports it, so its probably fine
diff --git a/contrib/verifybinaries/README.md b/contrib/verifybinaries/README.md
index 8970f3daa4..ed3e14fb6c 100644
--- a/contrib/verifybinaries/README.md
+++ b/contrib/verifybinaries/README.md
@@ -1,13 +1,33 @@
### Verify Binaries
+
+#### Preparation:
+
+Make sure you obtain the proper release signing key and verify the fingerprint with several independent sources.
+
+```sh
+$ gpg --fingerprint "Bitcoin Core binary release signing key"
+pub 4096R/36C2E964 2015-06-24 [expires: 2017-02-13]
+ Key fingerprint = 01EA 5486 DE18 A882 D4C2 6845 90C8 019E 36C2 E964
+uid Wladimir J. van der Laan (Bitcoin Core binary release signing key) <laanwj@gmail.com>
+```
+
+#### Usage:
+
This script attempts to download the signature file `SHA256SUMS.asc` from https://bitcoin.org.
It first checks if the signature passes, and then downloads the files specified in the file, and checks if the hashes of these files match those that are specified in the signature file.
The script returns 0 if everything passes the checks. It returns 1 if either the signature check or the hash check doesn't pass. If an error occurs the return value is 2.
-Usage:
```sh
./verify.sh bitcoin-core-0.11.2
./verify.sh bitcoin-core-0.12.0
+./verify.sh bitcoin-core-0.13.0-rc3
+```
+
+If you do not want to keep the downloaded binaries, specify anything as the second parameter.
+
+```sh
+./verify.sh bitcoin-core-0.13.0 delete
```
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index 657c3bd33c..e20770c96a 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -1,4 +1,7 @@
#!/bin/bash
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
### This script attempts to download the signature file SHA256SUMS.asc from bitcoin.org
### It first checks if the signature passes, and then downloads the files specified in
@@ -14,11 +17,11 @@ function clean_up {
done
}
-WORKINGDIR="/tmp/bitcoin"
+WORKINGDIR="/tmp/bitcoin_verify_binaries"
TMPFILE="hashes.tmp"
SIGNATUREFILENAME="SHA256SUMS.asc"
-RCSUBDIR="test/"
+RCSUBDIR="test"
BASEDIR="https://bitcoin.org/bin/"
VERSIONPREFIX="bitcoin-core-"
RCVERSIONSTRING="rc"
@@ -43,7 +46,7 @@ if [ -n "$1" ]; then
# and simultaneously add RCSUBDIR to BASEDIR, where we will look for SIGNATUREFILENAME
if [[ $VERSION == *"$RCVERSIONSTRING"* ]]; then
BASEDIR="$BASEDIR${VERSION/%-$RCVERSIONSTRING*}/"
- BASEDIR="$BASEDIR$RCSUBDIR"
+ BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSIONSTRING${VERSION: -1}/"
else
BASEDIR="$BASEDIR$VERSION/"
fi
@@ -93,7 +96,7 @@ fi
FILES=$(awk '{print $2}' "$TMPFILE")
#and download these one by one
-for file in in $FILES
+for file in $FILES
do
wget --quiet -N "$BASEDIR$file"
done
@@ -108,11 +111,16 @@ if [ $? -eq 1 ]; then
exit 1
elif [ $? -gt 1 ]; then
echo "Error executing 'diff'"
- exit 2
+ exit 2
fi
-#everything matches! clean up the mess
-clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+if [ -n "$2" ]; then
+ echo "Clean up the binaries"
+ clean_up $FILES $SIGNATUREFILENAME $TMPFILE
+else
+ echo "Keep the binaries in $WORKINGDIR"
+ clean_up $TMPFILE
+fi
echo -e "Verified hashes of \n$FILES"
diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py
index 6268123dd8..3dea5e3c14 100755
--- a/contrib/zmq/zmq_sub.py
+++ b/contrib/zmq/zmq_sub.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python2
+# Copyright (c) 2014-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import array
import binascii
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index bd29275638..81a660e83a 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -1,8 +1,8 @@
package=expat
-$(package)_version=2.1.1
+$(package)_version=2.2.0
$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=aff584e5a2f759dcfc6d48671e9529f6afe1e30b0cd6a4cec200cbe3f793de67
+$(package)_sha256_hash=d9e50ff2d19b3538bd2127902a89987474e1a4db8e43a66a4d1a712ab9a504ff
define $(package)_set_vars
$(package)_config_opts=--disable-static
diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk
index 2cf553ed96..fb97e0b9ec 100644
--- a/depends/packages/fontconfig.mk
+++ b/depends/packages/fontconfig.mk
@@ -1,8 +1,8 @@
package=fontconfig
-$(package)_version=2.11.1
+$(package)_version=2.12.1
$(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=dc62447533bca844463a3c3fd4083b57c90f18a70506e7a9f4936b5a1e516a99
+$(package)_sha256_hash=b449a3e10c47e1d1c7a6ec6e2016cca73d3bd68fbbd4f0ae5cc6b573f7d6c7f3
$(package)_dependencies=freetype expat
define $(package)_set_vars
diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk
index 9216e17598..a3a58604e5 100644
--- a/depends/packages/native_ccache.mk
+++ b/depends/packages/native_ccache.mk
@@ -1,8 +1,8 @@
package=native_ccache
-$(package)_version=3.2.5
-$(package)_download_path=http://samba.org/ftp/ccache
+$(package)_version=3.3.1
+$(package)_download_path=https://samba.org/ftp/ccache
$(package)_file_name=ccache-$($(package)_version).tar.bz2
-$(package)_sha256_hash=7a553809e90faf9de3a23ee9c5b5f786cfd4836bf502744bedb824a24bee1097
+$(package)_sha256_hash=cb6e4bafbb19ba0a2ec43386b123a5f92a20e1e3384c071d5d13e0cb3c84bf73
define $(package)_set_vars
$(package)_config_opts=
diff --git a/depends/packages/qt46.mk b/depends/packages/qt46.mk
deleted file mode 100644
index 8fb30a5c44..0000000000
--- a/depends/packages/qt46.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-PACKAGE=qt46
-$(package)_version=4.6.4
-$(package)_download_path=http://download.qt-project.org/archive/qt/4.6/
-$(package)_file_name=qt-everywhere-opensource-src-$($(package)_version).tar.gz
-$(package)_sha256_hash=9ad4d46c721b53a429ed5a2eecfd3c239a9ab566562f183f99d3125f1a234250
-$(package)_dependencies=openssl freetype dbus libX11 xproto libXext libICE libSM
-$(package)_patches=stlfix.patch
-
-define $(package)_set_vars
-$(package)_config_opts = -prefix $(host_prefix) -headerdir $(host_prefix)/include/qt4 -bindir $(build_prefix)/bin
-$(package)_config_opts += -release -no-separate-debug-info -opensource -confirm-license
-$(package)_config_opts += -stl -qt-zlib
-
-$(package)_config_opts += -nomake examples -nomake tests -nomake tools -nomake translations -nomake demos -nomake docs
-$(package)_config_opts += -no-audio-backend -no-glib -no-nis -no-cups -no-iconv -no-gif -no-pch
-$(package)_config_opts += -no-xkb -no-xrender -no-xrandr -no-xfixes -no-xcursor -no-xinerama -no-xsync -no-xinput -no-mitshm -no-xshape
-$(package)_config_opts += -no-libtiff -no-fontconfig -openssl-linked
-$(package)_config_opts += -no-sql-db2 -no-sql-ibase -no-sql-oci -no-sql-tds -no-sql-mysql
-$(package)_config_opts += -no-sql-odbc -no-sql-psql -no-sql-sqlite -no-sql-sqlite2
-$(package)_config_opts += -no-xmlpatterns -no-multimedia -no-phonon -no-scripttools -no-declarative
-$(package)_config_opts += -no-phonon-backend -no-webkit -no-javascript-jit -no-script
-$(package)_config_opts += -no-svg -no-libjpeg -no-libtiff -no-libpng -no-libmng -no-qt3support -no-opengl
-
-$(package)_config_opts_x86_64_linux += -platform linux-g++-64
-$(package)_config_opts_i686_linux = -platform linux-g++-32
-$(package)_build_env = QT_RCC_TEST=1
-endef
-
-define $(package)_preprocess_cmds
- sed -i.old "s|/include /usr/include||" config.tests/unix/freetype/freetype.pri && \
- sed -i.old "s|src_plugins.depends = src_gui src_sql src_svg|src_plugins.depends = src_gui src_sql|" src/src.pro && \
- sed -i.old "s|\.lower(|\.toLower(|g" src/network/ssl/qsslsocket_openssl.cpp && \
- sed -i.old "s|Key_BackSpace|Key_Backspace|" src/gui/itemviews/qabstractitemview.cpp && \
- sed -i.old "s|/usr/X11R6/lib64|$(host_prefix)/lib|" mkspecs/*/*.conf && \
- sed -i.old "s|/usr/X11R6/lib|$(host_prefix)/lib|" mkspecs/*/*.conf && \
- sed -i.old "s|/usr/X11R6/include|$(host_prefix)/include|" mkspecs/*/*.conf && \
- sed -i.old "s|QMAKE_LFLAGS_SHLIB\t+= -shared|QMAKE_LFLAGS_SHLIB\t+= -shared -Wl,--exclude-libs,ALL|" mkspecs/common/g++.conf && \
- sed -i.old "/SSLv2_client_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \
- sed -i.old "/SSLv2_server_method/d" src/network/ssl/qsslsocket_openssl.cpp src/network/ssl/qsslsocket_openssl_symbols.cpp && \
- patch -p1 < $($(package)_patch_dir)/stlfix.patch
-endef
-
-define $(package)_config_cmds
- export PKG_CONFIG_SYSROOT_DIR=/ && \
- export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
- export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
- export CPATH=$(host_prefix)/include && \
- OPENSSL_LIBS='-L$(host_prefix)/lib -lssl -lcrypto' ./configure $($(package)_config_opts) && \
- cd tools/linguist/lrelease; ../../../bin/qmake -o Makefile lrelease.pro
-endef
-
-define $(package)_build_cmds
- export CPATH=$(host_prefix)/include && \
- $(MAKE) -C src && \
- $(MAKE) -C tools/linguist/lrelease
-endef
-
-define $(package)_stage_cmds
- $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) install && \
- $(MAKE) -C tools/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install
-endef
-
-define $(package)_postprocess_cmds
- rm -rf mkspecs/ lib/cmake/ lib/*.prl lib/*.la && \
- find native/bin -type f -exec mv {} {}-qt4 \;
-endef
diff --git a/depends/patches/qt46/stlfix.patch b/depends/patches/qt46/stlfix.patch
deleted file mode 100644
index f8f6fb04b0..0000000000
--- a/depends/patches/qt46/stlfix.patch
+++ /dev/null
@@ -1,10 +0,0 @@
---- old/config.tests/unix/stl/stltest.cpp 2011-06-23 03:45:23.000000000 -0400
-+++ new/config.tests/unix/stl/stltest.cpp 2014-08-28 00:54:04.154837604 -0400
-@@ -49,6 +49,7 @@
- #include <vector>
- #include <algorithm>
- #include <iostream>
-+#include <cstddef>
-
- // something mean to see if the compiler and C++ standard lib are good enough
- template<class K, class T>
diff --git a/doc/README_osx.md b/doc/README_osx.md
index 6a5c672277..2a4460478c 100644
--- a/doc/README_osx.md
+++ b/doc/README_osx.md
@@ -36,11 +36,26 @@ Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.1
```
Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
-To create a tarball suitable for Gitian input, mount the dmg in OS X, then create it with:
+To create a tarball suitable for Gitian input, there are two options:
+
+Using Mac OS X, you can mount the dmg, and then create it with:
```
+ $ hdiutil attach Xcode_7.3.1.dmg
$ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
```
+Alternatively, you can use 7zip and SleuthKit to extract the files one by one.
+The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure
+the dmg file is in the current directory, and then run the script. You may wish
+to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when
+you've confirmed the extraction succeeded.
+
+```bash
+apt-get install p7zip-full sleuthkit
+contrib/macdeploy/extract-osx-sdk.sh
+rm -rf 5.hfs MacOSX10.11.sdk
+```
+
The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
which are created using these tools. The build process has been designed to
avoid including the SDK's files in Gitian's outputs. All interim tarballs are
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index d923301467..55283d6dce 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,6 +1,6 @@
OpenBSD build guide
======================
-(updated for OpenBSD 5.7)
+(updated for OpenBSD 5.9)
This guide describes how to build bitcoind and command-line utilities on OpenBSD.
@@ -15,11 +15,10 @@ Run the following as root to install the base dependencies for building:
pkg_add gmake libtool libevent
pkg_add autoconf # (select highest version, e.g. 2.69)
pkg_add automake # (select highest version, e.g. 1.15)
-pkg_add python # (select version 2.7.x, not 3.x)
-ln -sf /usr/local/bin/python2.7 /usr/local/bin/python2
+pkg_add python # (select highest version, e.g. 3.5)
```
-The default C++ compiler that comes with OpenBSD 5.7 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core. It is possible to patch it up to compile, but with the planned transition to C++11 this is a losing battle. So here we will be installing a newer compiler.
+The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler.
GCC
-------
@@ -27,7 +26,7 @@ GCC
You can install a newer version of gcc with:
```bash
-pkg_add g++ # (select newest 4.x version, e.g. 4.9.2)
+pkg_add g++ # (select newest 4.x version, e.g. 4.9.3)
```
This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`.
@@ -49,18 +48,15 @@ BOOST_PREFIX="${BITCOIN_ROOT}/boost"
mkdir -p $BOOST_PREFIX
# Fetch the source and verify that it is not tampered with
-wget http://heanet.dl.sourceforge.net/project/boost/boost/1.59.0/boost_1_59_0.tar.bz2
-echo '727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca boost_1_59_0.tar.bz2' | sha256 -c
-# MUST output: (SHA256) boost_1_59_0.tar.bz2: OK
-tar -xjf boost_1_59_0.tar.bz2
+curl -o boost_1_61_0.tar.bz2 http://heanet.dl.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.bz2
+echo 'a547bd06c2fd9a71ba1d169d9cf0339da7ebf4753849a8f7d6fdb8feee99b640 boost_1_61_0.tar.bz2' | sha256 -c
+# MUST output: (SHA256) boost_1_61_0.tar.bz2: OK
+tar -xjf boost_1_61_0.tar.bz2
-# Boost 1.59 needs two small patches for OpenBSD
-cd boost_1_59_0
+# Boost 1.61 needs one small patch for OpenBSD
+cd boost_1_61_0
# Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch
patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp
-# https://github.com/boostorg/filesystem/commit/90517e459681790a091566dce27ca3acabf9a70c
-sed 's/__OPEN_BSD__/__OpenBSD__/g' < libs/filesystem/src/path.cpp > libs/filesystem/src/path.cpp.tmp
-mv libs/filesystem/src/path.cpp.tmp libs/filesystem/src/path.cpp
# Build w/ minimum configuration necessary for bitcoin
echo 'using gcc : : eg++ : <cxxflags>"-fvisibility=hidden -fPIC" <linkflags>"" <archiver>"ar" <striper>"strip" <ranlib>"ranlib" <rc>"" : ;' > user-config.jam
@@ -84,7 +80,7 @@ BDB_PREFIX="${BITCOIN_ROOT}/db4"
mkdir -p $BDB_PREFIX
# Fetch the source and verify that it is not tampered with
-wget 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
+curl -o db-4.8.30.NC.tar.gz 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
echo '12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef db-4.8.30.NC.tar.gz' | sha256 -c
# MUST output: (SHA256) db-4.8.30.NC.tar.gz: OK
tar -xzf db-4.8.30.NC.tar.gz
@@ -93,9 +89,25 @@ tar -xzf db-4.8.30.NC.tar.gz
cd db-4.8.30.NC/build_unix/
# Note: Do a static build so that it can be embedded into the executable, instead of having to find a .so at runtime
../dist/configure --enable-cxx --disable-shared --with-pic --prefix=$BDB_PREFIX CC=egcc CXX=eg++ CPP=ecpp
-make install
+make install # do NOT use -jX, this is broken
```
+### Resource limits
+
+The standard ulimit restrictions in OpenBSD are very strict:
+
+ data(kbytes) 1572864
+
+This is, unfortunately, no longer enough to compile some `.cpp` files in the project,
+at least with gcc 4.9.3 (see issue https://github.com/bitcoin/bitcoin/issues/6658).
+If your user is in the `staff` group the limit can be raised with:
+
+ ulimit -d 3000000
+
+The change will only affect the current shell and processes spawned by it. To
+make the change system-wide, change `datasize-cur` and `datasize-max` in
+`/etc/login.conf`, and reboot.
+
### Building Bitcoin Core
**Important**: use `gmake`, not `make`. The non-GNU `make` will exit with a horrible error.
@@ -123,7 +135,7 @@ To configure without wallet:
Build and run the tests:
```bash
-gmake
+gmake # can use -jX here for parallelism
gmake check
```
diff --git a/doc/build-osx.md b/doc/build-osx.md
index c9eb4225ab..bc90a30562 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -16,7 +16,7 @@ Then install [Homebrew](http://brew.sh).
Dependencies
----------------------
- brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config protobuf --c++11 qt5 libevent
+ brew install automake berkeley-db4 libtool boost --c++11 miniupnpc openssl pkg-config homebrew/versions/protobuf260 --c++11 qt5 libevent
NOTE: Building with Qt4 is still supported, however, could result in a broken UI. Building with Qt5 is recommended.
diff --git a/doc/build-unix.md b/doc/build-unix.md
index bd89978cc2..62e3e793e9 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -293,9 +293,10 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
-First install the toolchain:
+Make sure you install the build requirements mentioned above.
+Then, install the toolchain and curl:
- sudo apt-get install g++-arm-linux-gnueabihf
+ sudo apt-get install g++-arm-linux-gnueabihf curl
To build executables for ARM:
diff --git a/doc/build-windows.md b/doc/build-windows.md
index 2b9233d1e1..129774491b 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -16,9 +16,11 @@ These steps can be performed on, for example, an Ubuntu VM. The depends system
will also work on other Linux distributions, however the commands for
installing the toolchain will be different.
-First install the toolchains:
+Make sure you install the build requirements mentioned in
+[build-unix.md](/doc/build-unix.md).
+Then, install the toolchains and curl:
- sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
+ sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev g++-mingw-w64-x86-64 mingw-w64-x86-64-dev curl
To build executables for Windows 32-bit:
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 95c46b05fe..70c0690ba3 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -14,6 +14,7 @@ gradually.
- No indentation for public/protected/private or for namespaces.
- No extra spaces inside parenthesis; don't do ( this )
- No space after function names; one space after if, for and while.
+ - `++i` is preferred over `i++`.
Block style example:
```c++
@@ -24,7 +25,7 @@ class Class
bool Function(char* psz, int n)
{
// Comment summarising what this section of code does
- for (int i = 0; i < n; i++) {
+ for (int i = 0; i < n; ++i) {
// When something fails, return early
if (!Something())
return false;
@@ -231,9 +232,9 @@ General Bitcoin Core
- *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing
on the master branch. Otherwise all new pull requests will start failing the tests, resulting in
confusion and mayhem
-
+
- *Explanation*: If the test suite is to be updated for a change, this has to
- be done first
+ be done first
Wallet
-------
diff --git a/doc/gitian-building.md b/doc/gitian-building.md
index 938f92ff12..4914d90df4 100644
--- a/doc/gitian-building.md
+++ b/doc/gitian-building.md
@@ -95,14 +95,14 @@ After creating the VM, we need to configure it.
- Click `Ok` twice to save.
-Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
-This DVD image can be validated using a SHA256 hashing tool, for example on
+Get the [Debian 8.x net installer](http://cdimage.debian.org/mirror/cdimage/archive/8.5.0/amd64/iso-cd/debian-8.5.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)).
+This DVD image can be [validated](https://www.debian.org/CD/verify) using a SHA256 hashing tool, for example on
Unixy OSes by entering the following in a terminal:
echo "ad4e8c27c561ad8248d5ebc1d36eb172f884057bfeb2c22ead823f59fa8c3dff debian-8.5.0-amd64-netinst.iso" | sha256sum -c
# (must return OK)
-Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso.
+Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded ISO.
![](gitian-building/select_startup_disk.png)
@@ -336,8 +336,8 @@ There will be a lot of warnings printed during the build of the image. These can
Getting and building the inputs
--------------------------------
-Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-build-inputs-first-time-or-when-dependency-versions-change)
-in the bitcoin repository under 'Fetch and build inputs' to install sources which require
+Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-create-inputs-first-time-or-when-dependency-versions-change)
+in the bitcoin repository under 'Fetch and create inputs' to install sources which require
manual intervention. Also optionally follow the next step: 'Seed the Gitian sources cache
and offline git repositories' which will fetch the remaining files required for building
offline.
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
new file mode 100644
index 0000000000..5252ef4a19
--- /dev/null
+++ b/doc/man/Makefile.am
@@ -0,0 +1 @@
+dist_man1_MANS=bitcoind.1 bitcoin-qt.1 bitcoin-cli.1 bitcoin-tx.1
diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1
new file mode 100644
index 0000000000..11b690cf85
--- /dev/null
+++ b/doc/man/bitcoin-cli.1
@@ -0,0 +1,84 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
+.TH BITCOIN-CLI "1" "September 2016" "bitcoin-cli v0.13.0.0" "User Commands"
+.SH NAME
+bitcoin-cli \- manual page for bitcoin-cli v0.13.0.0
+.SH DESCRIPTION
+Bitcoin Core RPC client version v0.13.0.0
+.SS "Usage:"
+.TP
+bitcoin\-cli [options] <command> [params]
+Send command to Bitcoin Core
+.TP
+bitcoin\-cli [options] help
+List commands
+.TP
+bitcoin\-cli [options] help <command>
+Get help for a command
+.SH OPTIONS
+.HP
+\-?
+.IP
+This help message
+.HP
+\fB\-conf=\fR<file>
+.IP
+Specify configuration file (default: bitcoin.conf)
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.HP
+\fB\-regtest\fR
+.IP
+Enter regression test mode, which uses a special chain in which blocks
+can be solved instantly. This is intended for regression testing
+tools and app development.
+.HP
+\fB\-rpcconnect=\fR<ip>
+.IP
+Send commands to node running on <ip> (default: 127.0.0.1)
+.HP
+\fB\-rpcport=\fR<port>
+.IP
+Connect to JSON\-RPC on <port> (default: 8332 or testnet: 18332)
+.HP
+\fB\-rpcwait\fR
+.IP
+Wait for RPC server to start
+.HP
+\fB\-rpcuser=\fR<user>
+.IP
+Username for JSON\-RPC connections
+.HP
+\fB\-rpcpassword=\fR<pw>
+.IP
+Password for JSON\-RPC connections
+.HP
+\fB\-rpcclienttimeout=\fR<n>
+.IP
+Timeout during HTTP requests (default: 900)
+.HP
+\fB\-stdin\fR
+.IP
+Read extra arguments from standard input, one per line until EOF/Ctrl\-D
+(recommended for sensitive information such as passphrases)
+.SH COPYRIGHT
+Copyright (C) 2009-2016 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <http://www.opensource.org/licenses/mit-license.php>.
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
+by Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
new file mode 100644
index 0000000000..24b529dac1
--- /dev/null
+++ b/doc/man/bitcoin-qt.1
@@ -0,0 +1,513 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
+.TH BITCOIN-QT "1" "September 2016" "bitcoin-qt v0.13.0.0" "User Commands"
+.SH NAME
+bitcoin-qt \- manual page for bitcoin-qt v0.13.0.0
+.SH DESCRIPTION
+Bitcoin Core version v0.13.0.0 (64\-bit)
+Usage:
+.IP
+bitcoin\-qt [command\-line options]
+.SH OPTIONS
+.HP
+\-?
+.IP
+Print this help message and exit
+.HP
+\fB\-version\fR
+.IP
+Print version and exit
+.HP
+\fB\-alertnotify=\fR<cmd>
+.IP
+Execute command when a relevant alert is received or we see a really
+long fork (%s in cmd is replaced by message)
+.HP
+\fB\-blocknotify=\fR<cmd>
+.IP
+Execute command when the best block changes (%s in cmd is replaced by
+block hash)
+.HP
+\fB\-checkblocks=\fR<n>
+.IP
+How many blocks to check at startup (default: 288, 0 = all)
+.HP
+\fB\-checklevel=\fR<n>
+.IP
+How thorough the block verification of \fB\-checkblocks\fR is (0\-4, default: 3)
+.HP
+\fB\-conf=\fR<file>
+.IP
+Specify configuration file (default: bitcoin.conf)
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.HP
+\fB\-dbcache=\fR<n>
+.IP
+Set database cache size in megabytes (4 to 16384, default: 300)
+.HP
+\fB\-loadblock=\fR<file>
+.IP
+Imports blocks from external blk000??.dat file on startup
+.HP
+\fB\-maxorphantx=\fR<n>
+.IP
+Keep at most <n> unconnectable transactions in memory (default: 100)
+.HP
+\fB\-maxmempool=\fR<n>
+.IP
+Keep the transaction memory pool below <n> megabytes (default: 300)
+.HP
+\fB\-mempoolexpiry=\fR<n>
+.IP
+Do not keep transactions in the mempool longer than <n> hours (default:
+72)
+.HP
+\fB\-par=\fR<n>
+.IP
+Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 =
+leave that many cores free, default: 0)
+.HP
+\fB\-pid=\fR<file>
+.IP
+Specify pid file (default: bitcoind.pid)
+.HP
+\fB\-prune=\fR<n>
+.IP
+Reduce storage requirements by pruning (deleting) old blocks. This mode
+is incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting
+this setting requires re\-downloading the entire blockchain.
+(default: 0 = disable pruning blocks, >550 = target size in MiB
+to use for block files)
+.HP
+\fB\-reindex\-chainstate\fR
+.IP
+Rebuild chain state from the currently indexed blocks
+.HP
+\fB\-reindex\fR
+.IP
+Rebuild chain state and block index from the blk*.dat files on disk
+.HP
+\fB\-sysperms\fR
+.IP
+Create new files with system default permissions, instead of umask 077
+(only effective with disabled wallet functionality)
+.HP
+\fB\-txindex\fR
+.IP
+Maintain a full transaction index, used by the getrawtransaction rpc
+call (default: 0)
+.PP
+Connection options:
+.HP
+\fB\-addnode=\fR<ip>
+.IP
+Add a node to connect to and attempt to keep the connection open
+.HP
+\fB\-banscore=\fR<n>
+.IP
+Threshold for disconnecting misbehaving peers (default: 100)
+.HP
+\fB\-bantime=\fR<n>
+.IP
+Number of seconds to keep misbehaving peers from reconnecting (default:
+86400)
+.HP
+\fB\-bind=\fR<addr>
+.IP
+Bind to given address and always listen on it. Use [host]:port notation
+for IPv6
+.HP
+\fB\-connect=\fR<ip>
+.IP
+Connect only to the specified node(s)
+.HP
+\fB\-discover\fR
+.IP
+Discover own IP addresses (default: 1 when listening and no \fB\-externalip\fR
+or \fB\-proxy\fR)
+.HP
+\fB\-dns\fR
+.IP
+Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1)
+.HP
+\fB\-dnsseed\fR
+.IP
+Query for peer addresses via DNS lookup, if low on addresses (default: 1
+unless \fB\-connect\fR)
+.HP
+\fB\-externalip=\fR<ip>
+.IP
+Specify your own public address
+.HP
+\fB\-forcednsseed\fR
+.IP
+Always query for peer addresses via DNS lookup (default: 0)
+.HP
+\fB\-listen\fR
+.IP
+Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR)
+.HP
+\fB\-listenonion\fR
+.IP
+Automatically create Tor hidden service (default: 1)
+.HP
+\fB\-maxconnections=\fR<n>
+.IP
+Maintain at most <n> connections to peers (default: 125)
+.HP
+\fB\-maxreceivebuffer=\fR<n>
+.IP
+Maximum per\-connection receive buffer, <n>*1000 bytes (default: 5000)
+.HP
+\fB\-maxsendbuffer=\fR<n>
+.IP
+Maximum per\-connection send buffer, <n>*1000 bytes (default: 1000)
+.HP
+\fB\-maxtimeadjustment\fR
+.IP
+Maximum allowed median peer time offset adjustment. Local perspective of
+time may be influenced by peers forward or backward by this
+amount. (default: 4200 seconds)
+.HP
+\fB\-onion=\fR<ip:port>
+.IP
+Use separate SOCKS5 proxy to reach peers via Tor hidden services
+(default: \fB\-proxy\fR)
+.HP
+\fB\-onlynet=\fR<net>
+.IP
+Only connect to nodes in network <net> (ipv4, ipv6 or onion)
+.HP
+\fB\-permitbaremultisig\fR
+.IP
+Relay non\-P2SH multisig (default: 1)
+.HP
+\fB\-peerbloomfilters\fR
+.IP
+Support filtering of blocks and transaction with bloom filters (default:
+1)
+.HP
+\fB\-port=\fR<port>
+.IP
+Listen for connections on <port> (default: 8333 or testnet: 18333)
+.HP
+\fB\-proxy=\fR<ip:port>
+.IP
+Connect through SOCKS5 proxy
+.HP
+\fB\-proxyrandomize\fR
+.IP
+Randomize credentials for every proxy connection. This enables Tor
+stream isolation (default: 1)
+.HP
+\fB\-seednode=\fR<ip>
+.IP
+Connect to a node to retrieve peer addresses, and disconnect
+.HP
+\fB\-timeout=\fR<n>
+.IP
+Specify connection timeout in milliseconds (minimum: 1, default: 5000)
+.HP
+\fB\-torcontrol=\fR<ip>:<port>
+.IP
+Tor control port to use if onion listening enabled (default:
+127.0.0.1:9051)
+.HP
+\fB\-torpassword=\fR<pass>
+.IP
+Tor control port password (default: empty)
+.HP
+\fB\-whitebind=\fR<addr>
+.IP
+Bind to given address and whitelist peers connecting to it. Use
+[host]:port notation for IPv6
+.HP
+\fB\-whitelist=\fR<netmask>
+.IP
+Whitelist peers connecting from the given netmask or IP address. Can be
+specified multiple times. Whitelisted peers cannot be DoS banned
+and their transactions are always relayed, even if they are
+already in the mempool, useful e.g. for a gateway
+.HP
+\fB\-whitelistrelay\fR
+.IP
+Accept relayed transactions received from whitelisted peers even when
+not relaying transactions (default: 1)
+.HP
+\fB\-whitelistforcerelay\fR
+.IP
+Force relay of transactions from whitelisted peers even they violate
+local relay policy (default: 1)
+.HP
+\fB\-maxuploadtarget=\fR<n>
+.IP
+Tries to keep outbound traffic under the given target (in MiB per 24h),
+0 = no limit (default: 0)
+.PP
+Wallet options:
+.HP
+\fB\-disablewallet\fR
+.IP
+Do not load the wallet and disable wallet RPC calls
+.HP
+\fB\-keypool=\fR<n>
+.IP
+Set key pool size to <n> (default: 100)
+.HP
+\fB\-fallbackfee=\fR<amt>
+.IP
+A fee rate (in BTC/kB) that will be used when fee estimation has
+insufficient data (default: 0.0002)
+.HP
+\fB\-mintxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for
+transaction creation (default: 0.00001)
+.HP
+\fB\-paytxfee=\fR<amt>
+.IP
+Fee (in BTC/kB) to add to transactions you send (default: 0.00)
+.HP
+\fB\-rescan\fR
+.IP
+Rescan the block chain for missing wallet transactions on startup
+.HP
+\fB\-salvagewallet\fR
+.IP
+Attempt to recover private keys from a corrupt wallet on startup
+.HP
+\fB\-spendzeroconfchange\fR
+.IP
+Spend unconfirmed change when sending transactions (default: 1)
+.HP
+\fB\-txconfirmtarget=\fR<n>
+.IP
+If paytxfee is not set, include enough fee so transactions begin
+confirmation on average within n blocks (default: 2)
+.HP
+\fB\-usehd\fR
+.IP
+Use hierarchical deterministic key generation (HD) after BIP32. Only has
+effect during wallet creation/first start (default: 1)
+.HP
+\fB\-upgradewallet\fR
+.IP
+Upgrade wallet to latest format on startup
+.HP
+\fB\-wallet=\fR<file>
+.IP
+Specify wallet file (within data directory) (default: wallet.dat)
+.HP
+\fB\-walletbroadcast\fR
+.IP
+Make the wallet broadcast transactions (default: 1)
+.HP
+\fB\-walletnotify=\fR<cmd>
+.IP
+Execute command when a wallet transaction changes (%s in cmd is replaced
+by TxID)
+.HP
+\fB\-zapwallettxes=\fR<mode>
+.IP
+Delete all wallet transactions and only recover those parts of the
+blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
+account owner and payment request information, 2 = drop tx meta
+data)
+.PP
+ZeroMQ notification options:
+.HP
+\fB\-zmqpubhashblock=\fR<address>
+.IP
+Enable publish hash block in <address>
+.HP
+\fB\-zmqpubhashtx=\fR<address>
+.IP
+Enable publish hash transaction in <address>
+.HP
+\fB\-zmqpubrawblock=\fR<address>
+.IP
+Enable publish raw block in <address>
+.HP
+\fB\-zmqpubrawtx=\fR<address>
+.IP
+Enable publish raw transaction in <address>
+.PP
+Debugging/Testing options:
+.HP
+\fB\-uacomment=\fR<cmt>
+.IP
+Append comment to the user agent string
+.HP
+\fB\-debug=\fR<category>
+.IP
+Output debugging information (default: 0, supplying <category> is
+optional). If <category> is not supplied or if <category> = 1,
+output all debugging information.<category> can be: addrman,
+alert, bench, coindb, db, http, libevent, lock, mempool,
+mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins,
+tor, zmq, qt.
+.HP
+\fB\-help\-debug\fR
+.IP
+Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
+.HP
+\fB\-logips\fR
+.IP
+Include IP addresses in debug output (default: 0)
+.HP
+\fB\-logtimestamps\fR
+.IP
+Prepend debug output with timestamp (default: 1)
+.HP
+\fB\-minrelaytxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for relaying,
+mining and transaction creation (default: 0.00001)
+.HP
+\fB\-maxtxfee=\fR<amt>
+.IP
+Maximum total fees (in BTC) to use in a single wallet transaction or raw
+transaction; setting this too low may abort large transactions
+(default: 0.10)
+.HP
+\fB\-printtoconsole\fR
+.IP
+Send trace/debug info to console instead of debug.log file
+.HP
+\fB\-shrinkdebugfile\fR
+.IP
+Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR)
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.PP
+Node relay options:
+.HP
+\fB\-bytespersigop\fR
+.IP
+Equivalent bytes per sigop in transactions for relay and mining
+(default: 20)
+.HP
+\fB\-datacarrier\fR
+.IP
+Relay and mine data carrier transactions (default: 1)
+.HP
+\fB\-datacarriersize\fR
+.IP
+Maximum size of data in data carrier transactions we relay and mine
+(default: 83)
+.HP
+\fB\-mempoolreplacement\fR
+.IP
+Enable transaction replacement in the memory pool (default: 1)
+.PP
+Block creation options:
+.HP
+\fB\-blockmaxweight=\fR<n>
+.IP
+Set maximum BIP141 block weight (default: 3000000)
+.HP
+\fB\-blockmaxsize=\fR<n>
+.IP
+Set maximum block size in bytes (default: 750000)
+.HP
+\fB\-blockprioritysize=\fR<n>
+.IP
+Set maximum size of high\-priority/low\-fee transactions in bytes
+(default: 0)
+.PP
+RPC server options:
+.HP
+\fB\-server\fR
+.IP
+Accept command line and JSON\-RPC commands
+.HP
+\fB\-rest\fR
+.IP
+Accept public REST requests (default: 0)
+.HP
+\fB\-rpcbind=\fR<addr>
+.IP
+Bind to given address to listen for JSON\-RPC connections. Use
+[host]:port notation for IPv6. This option can be specified
+multiple times (default: bind to all interfaces)
+.HP
+\fB\-rpccookiefile=\fR<loc>
+.IP
+Location of the auth cookie (default: data dir)
+.HP
+\fB\-rpcuser=\fR<user>
+.IP
+Username for JSON\-RPC connections
+.HP
+\fB\-rpcpassword=\fR<pw>
+.IP
+Password for JSON\-RPC connections
+.HP
+\fB\-rpcauth=\fR<userpw>
+.IP
+Username and hashed password for JSON\-RPC connections. The field
+<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
+canonical python script is included in share/rpcuser. This option
+can be specified multiple times
+.HP
+\fB\-rpcport=\fR<port>
+.IP
+Listen for JSON\-RPC connections on <port> (default: 8332 or testnet:
+18332)
+.HP
+\fB\-rpcallowip=\fR<ip>
+.IP
+Allow JSON\-RPC connections from specified source. Valid for <ip> are a
+single IP (e.g. 1.2.3.4), a network/netmask (e.g.
+1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This
+option can be specified multiple times
+.HP
+\fB\-rpcthreads=\fR<n>
+.IP
+Set the number of threads to service RPC calls (default: 4)
+.PP
+UI Options:
+.HP
+\fB\-choosedatadir\fR
+.IP
+Choose data directory on startup (default: 0)
+.HP
+\fB\-lang=\fR<lang>
+.IP
+Set language, for example "de_DE" (default: system locale)
+.HP
+\fB\-min\fR
+.IP
+Start minimized
+.HP
+\fB\-rootcertificates=\fR<file>
+.IP
+Set SSL root certificates for payment request (default: \fB\-system\-\fR)
+.HP
+\fB\-splash\fR
+.IP
+Show splash screen on startup (default: 1)
+.HP
+\fB\-resetguisettings\fR
+.IP
+Reset all settings changed in the GUI
+.SH COPYRIGHT
+Copyright (C) 2009-2016 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <http://www.opensource.org/licenses/mit-license.php>.
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
+by Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1
new file mode 100644
index 0000000000..5c4e31e7f7
--- /dev/null
+++ b/doc/man/bitcoin-tx.1
@@ -0,0 +1,107 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
+.TH BITCOIN-TX "1" "September 2016" "bitcoin-tx v0.13.0.0" "User Commands"
+.SH NAME
+bitcoin-tx \- manual page for bitcoin-tx v0.13.0.0
+.SH DESCRIPTION
+Bitcoin Core bitcoin\-tx utility version v0.13.0.0
+.SS "Usage:"
+.TP
+bitcoin\-tx [options] <hex\-tx> [commands]
+Update hex\-encoded bitcoin transaction
+.TP
+bitcoin\-tx [options] \fB\-create\fR [commands]
+Create hex\-encoded bitcoin transaction
+.SH OPTIONS
+.HP
+\-?
+.IP
+This help message
+.HP
+\fB\-create\fR
+.IP
+Create new, empty TX.
+.HP
+\fB\-json\fR
+.IP
+Select JSON output
+.HP
+\fB\-txid\fR
+.IP
+Output only the hex\-encoded transaction id of the resultant transaction.
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.HP
+\fB\-regtest\fR
+.IP
+Enter regression test mode, which uses a special chain in which blocks
+can be solved instantly. This is intended for regression testing
+tools and app development.
+.PP
+Commands:
+.IP
+delin=N
+.IP
+Delete input N from TX
+.IP
+delout=N
+.IP
+Delete output N from TX
+.IP
+in=TXID:VOUT(:SEQUENCE_NUMBER)
+.IP
+Add input to TX
+.IP
+locktime=N
+.IP
+Set TX lock time to N
+.IP
+nversion=N
+.IP
+Set TX version to N
+.IP
+outaddr=VALUE:ADDRESS
+.IP
+Add address\-based output to TX
+.IP
+outdata=[VALUE:]DATA
+.IP
+Add data\-based output to TX
+.IP
+outscript=VALUE:SCRIPT
+.IP
+Add raw script output to TX
+.IP
+sign=SIGHASH\-FLAGS
+.IP
+Add zero or more signatures to transaction. This command requires JSON
+registers:prevtxs=JSON object, privatekeys=JSON object. See
+signrawtransaction docs for format of sighash flags, JSON
+objects.
+.PP
+Register Commands:
+.IP
+load=NAME:FILENAME
+.IP
+Load JSON file FILENAME into register NAME
+.IP
+set=NAME:JSON\-STRING
+.IP
+Set register NAME to given JSON\-STRING
+.SH COPYRIGHT
+Copyright (C) 2009-2016 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <http://www.opensource.org/licenses/mit-license.php>.
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
+by Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
new file mode 100644
index 0000000000..b99657a5fa
--- /dev/null
+++ b/doc/man/bitcoind.1
@@ -0,0 +1,492 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.5.
+.TH BITCOIND "1" "September 2016" "bitcoind v0.13.0.0" "User Commands"
+.SH NAME
+bitcoind \- manual page for bitcoind v0.13.0.0
+.SH DESCRIPTION
+Bitcoin Core Daemon version v0.13.0.0
+.SS "Usage:"
+.TP
+bitcoind [options]
+Start Bitcoin Core Daemon
+.SH OPTIONS
+.HP
+\-?
+.IP
+Print this help message and exit
+.HP
+\fB\-version\fR
+.IP
+Print version and exit
+.HP
+\fB\-alertnotify=\fR<cmd>
+.IP
+Execute command when a relevant alert is received or we see a really
+long fork (%s in cmd is replaced by message)
+.HP
+\fB\-blocknotify=\fR<cmd>
+.IP
+Execute command when the best block changes (%s in cmd is replaced by
+block hash)
+.HP
+\fB\-checkblocks=\fR<n>
+.IP
+How many blocks to check at startup (default: 288, 0 = all)
+.HP
+\fB\-checklevel=\fR<n>
+.IP
+How thorough the block verification of \fB\-checkblocks\fR is (0\-4, default: 3)
+.HP
+\fB\-conf=\fR<file>
+.IP
+Specify configuration file (default: bitcoin.conf)
+.HP
+\fB\-daemon\fR
+.IP
+Run in the background as a daemon and accept commands
+.HP
+\fB\-datadir=\fR<dir>
+.IP
+Specify data directory
+.HP
+\fB\-dbcache=\fR<n>
+.IP
+Set database cache size in megabytes (4 to 16384, default: 300)
+.HP
+\fB\-loadblock=\fR<file>
+.IP
+Imports blocks from external blk000??.dat file on startup
+.HP
+\fB\-maxorphantx=\fR<n>
+.IP
+Keep at most <n> unconnectable transactions in memory (default: 100)
+.HP
+\fB\-maxmempool=\fR<n>
+.IP
+Keep the transaction memory pool below <n> megabytes (default: 300)
+.HP
+\fB\-mempoolexpiry=\fR<n>
+.IP
+Do not keep transactions in the mempool longer than <n> hours (default:
+72)
+.HP
+\fB\-par=\fR<n>
+.IP
+Set the number of script verification threads (\fB\-4\fR to 16, 0 = auto, <0 =
+leave that many cores free, default: 0)
+.HP
+\fB\-pid=\fR<file>
+.IP
+Specify pid file (default: bitcoind.pid)
+.HP
+\fB\-prune=\fR<n>
+.IP
+Reduce storage requirements by pruning (deleting) old blocks. This mode
+is incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting
+this setting requires re\-downloading the entire blockchain.
+(default: 0 = disable pruning blocks, >550 = target size in MiB
+to use for block files)
+.HP
+\fB\-reindex\-chainstate\fR
+.IP
+Rebuild chain state from the currently indexed blocks
+.HP
+\fB\-reindex\fR
+.IP
+Rebuild chain state and block index from the blk*.dat files on disk
+.HP
+\fB\-sysperms\fR
+.IP
+Create new files with system default permissions, instead of umask 077
+(only effective with disabled wallet functionality)
+.HP
+\fB\-txindex\fR
+.IP
+Maintain a full transaction index, used by the getrawtransaction rpc
+call (default: 0)
+.PP
+Connection options:
+.HP
+\fB\-addnode=\fR<ip>
+.IP
+Add a node to connect to and attempt to keep the connection open
+.HP
+\fB\-banscore=\fR<n>
+.IP
+Threshold for disconnecting misbehaving peers (default: 100)
+.HP
+\fB\-bantime=\fR<n>
+.IP
+Number of seconds to keep misbehaving peers from reconnecting (default:
+86400)
+.HP
+\fB\-bind=\fR<addr>
+.IP
+Bind to given address and always listen on it. Use [host]:port notation
+for IPv6
+.HP
+\fB\-connect=\fR<ip>
+.IP
+Connect only to the specified node(s)
+.HP
+\fB\-discover\fR
+.IP
+Discover own IP addresses (default: 1 when listening and no \fB\-externalip\fR
+or \fB\-proxy\fR)
+.HP
+\fB\-dns\fR
+.IP
+Allow DNS lookups for \fB\-addnode\fR, \fB\-seednode\fR and \fB\-connect\fR (default: 1)
+.HP
+\fB\-dnsseed\fR
+.IP
+Query for peer addresses via DNS lookup, if low on addresses (default: 1
+unless \fB\-connect\fR)
+.HP
+\fB\-externalip=\fR<ip>
+.IP
+Specify your own public address
+.HP
+\fB\-forcednsseed\fR
+.IP
+Always query for peer addresses via DNS lookup (default: 0)
+.HP
+\fB\-listen\fR
+.IP
+Accept connections from outside (default: 1 if no \fB\-proxy\fR or \fB\-connect\fR)
+.HP
+\fB\-listenonion\fR
+.IP
+Automatically create Tor hidden service (default: 1)
+.HP
+\fB\-maxconnections=\fR<n>
+.IP
+Maintain at most <n> connections to peers (default: 125)
+.HP
+\fB\-maxreceivebuffer=\fR<n>
+.IP
+Maximum per\-connection receive buffer, <n>*1000 bytes (default: 5000)
+.HP
+\fB\-maxsendbuffer=\fR<n>
+.IP
+Maximum per\-connection send buffer, <n>*1000 bytes (default: 1000)
+.HP
+\fB\-maxtimeadjustment\fR
+.IP
+Maximum allowed median peer time offset adjustment. Local perspective of
+time may be influenced by peers forward or backward by this
+amount. (default: 4200 seconds)
+.HP
+\fB\-onion=\fR<ip:port>
+.IP
+Use separate SOCKS5 proxy to reach peers via Tor hidden services
+(default: \fB\-proxy\fR)
+.HP
+\fB\-onlynet=\fR<net>
+.IP
+Only connect to nodes in network <net> (ipv4, ipv6 or onion)
+.HP
+\fB\-permitbaremultisig\fR
+.IP
+Relay non\-P2SH multisig (default: 1)
+.HP
+\fB\-peerbloomfilters\fR
+.IP
+Support filtering of blocks and transaction with bloom filters (default:
+1)
+.HP
+\fB\-port=\fR<port>
+.IP
+Listen for connections on <port> (default: 8333 or testnet: 18333)
+.HP
+\fB\-proxy=\fR<ip:port>
+.IP
+Connect through SOCKS5 proxy
+.HP
+\fB\-proxyrandomize\fR
+.IP
+Randomize credentials for every proxy connection. This enables Tor
+stream isolation (default: 1)
+.HP
+\fB\-seednode=\fR<ip>
+.IP
+Connect to a node to retrieve peer addresses, and disconnect
+.HP
+\fB\-timeout=\fR<n>
+.IP
+Specify connection timeout in milliseconds (minimum: 1, default: 5000)
+.HP
+\fB\-torcontrol=\fR<ip>:<port>
+.IP
+Tor control port to use if onion listening enabled (default:
+127.0.0.1:9051)
+.HP
+\fB\-torpassword=\fR<pass>
+.IP
+Tor control port password (default: empty)
+.HP
+\fB\-whitebind=\fR<addr>
+.IP
+Bind to given address and whitelist peers connecting to it. Use
+[host]:port notation for IPv6
+.HP
+\fB\-whitelist=\fR<netmask>
+.IP
+Whitelist peers connecting from the given netmask or IP address. Can be
+specified multiple times. Whitelisted peers cannot be DoS banned
+and their transactions are always relayed, even if they are
+already in the mempool, useful e.g. for a gateway
+.HP
+\fB\-whitelistrelay\fR
+.IP
+Accept relayed transactions received from whitelisted peers even when
+not relaying transactions (default: 1)
+.HP
+\fB\-whitelistforcerelay\fR
+.IP
+Force relay of transactions from whitelisted peers even they violate
+local relay policy (default: 1)
+.HP
+\fB\-maxuploadtarget=\fR<n>
+.IP
+Tries to keep outbound traffic under the given target (in MiB per 24h),
+0 = no limit (default: 0)
+.PP
+Wallet options:
+.HP
+\fB\-disablewallet\fR
+.IP
+Do not load the wallet and disable wallet RPC calls
+.HP
+\fB\-keypool=\fR<n>
+.IP
+Set key pool size to <n> (default: 100)
+.HP
+\fB\-fallbackfee=\fR<amt>
+.IP
+A fee rate (in BTC/kB) that will be used when fee estimation has
+insufficient data (default: 0.0002)
+.HP
+\fB\-mintxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for
+transaction creation (default: 0.00001)
+.HP
+\fB\-paytxfee=\fR<amt>
+.IP
+Fee (in BTC/kB) to add to transactions you send (default: 0.00)
+.HP
+\fB\-rescan\fR
+.IP
+Rescan the block chain for missing wallet transactions on startup
+.HP
+\fB\-salvagewallet\fR
+.IP
+Attempt to recover private keys from a corrupt wallet on startup
+.HP
+\fB\-spendzeroconfchange\fR
+.IP
+Spend unconfirmed change when sending transactions (default: 1)
+.HP
+\fB\-txconfirmtarget=\fR<n>
+.IP
+If paytxfee is not set, include enough fee so transactions begin
+confirmation on average within n blocks (default: 2)
+.HP
+\fB\-usehd\fR
+.IP
+Use hierarchical deterministic key generation (HD) after BIP32. Only has
+effect during wallet creation/first start (default: 1)
+.HP
+\fB\-upgradewallet\fR
+.IP
+Upgrade wallet to latest format on startup
+.HP
+\fB\-wallet=\fR<file>
+.IP
+Specify wallet file (within data directory) (default: wallet.dat)
+.HP
+\fB\-walletbroadcast\fR
+.IP
+Make the wallet broadcast transactions (default: 1)
+.HP
+\fB\-walletnotify=\fR<cmd>
+.IP
+Execute command when a wallet transaction changes (%s in cmd is replaced
+by TxID)
+.HP
+\fB\-zapwallettxes=\fR<mode>
+.IP
+Delete all wallet transactions and only recover those parts of the
+blockchain through \fB\-rescan\fR on startup (1 = keep tx meta data e.g.
+account owner and payment request information, 2 = drop tx meta
+data)
+.PP
+ZeroMQ notification options:
+.HP
+\fB\-zmqpubhashblock=\fR<address>
+.IP
+Enable publish hash block in <address>
+.HP
+\fB\-zmqpubhashtx=\fR<address>
+.IP
+Enable publish hash transaction in <address>
+.HP
+\fB\-zmqpubrawblock=\fR<address>
+.IP
+Enable publish raw block in <address>
+.HP
+\fB\-zmqpubrawtx=\fR<address>
+.IP
+Enable publish raw transaction in <address>
+.PP
+Debugging/Testing options:
+.HP
+\fB\-uacomment=\fR<cmt>
+.IP
+Append comment to the user agent string
+.HP
+\fB\-debug=\fR<category>
+.IP
+Output debugging information (default: 0, supplying <category> is
+optional). If <category> is not supplied or if <category> = 1,
+output all debugging information.<category> can be: addrman,
+alert, bench, coindb, db, http, libevent, lock, mempool,
+mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins,
+tor, zmq.
+.HP
+\fB\-help\-debug\fR
+.IP
+Show all debugging options (usage: \fB\-\-help\fR \fB\-help\-debug\fR)
+.HP
+\fB\-logips\fR
+.IP
+Include IP addresses in debug output (default: 0)
+.HP
+\fB\-logtimestamps\fR
+.IP
+Prepend debug output with timestamp (default: 1)
+.HP
+\fB\-minrelaytxfee=\fR<amt>
+.IP
+Fees (in BTC/kB) smaller than this are considered zero fee for relaying,
+mining and transaction creation (default: 0.00001)
+.HP
+\fB\-maxtxfee=\fR<amt>
+.IP
+Maximum total fees (in BTC) to use in a single wallet transaction or raw
+transaction; setting this too low may abort large transactions
+(default: 0.10)
+.HP
+\fB\-printtoconsole\fR
+.IP
+Send trace/debug info to console instead of debug.log file
+.HP
+\fB\-shrinkdebugfile\fR
+.IP
+Shrink debug.log file on client startup (default: 1 when no \fB\-debug\fR)
+.PP
+Chain selection options:
+.HP
+\fB\-testnet\fR
+.IP
+Use the test chain
+.PP
+Node relay options:
+.HP
+\fB\-bytespersigop\fR
+.IP
+Equivalent bytes per sigop in transactions for relay and mining
+(default: 20)
+.HP
+\fB\-datacarrier\fR
+.IP
+Relay and mine data carrier transactions (default: 1)
+.HP
+\fB\-datacarriersize\fR
+.IP
+Maximum size of data in data carrier transactions we relay and mine
+(default: 83)
+.HP
+\fB\-mempoolreplacement\fR
+.IP
+Enable transaction replacement in the memory pool (default: 1)
+.PP
+Block creation options:
+.HP
+\fB\-blockmaxweight=\fR<n>
+.IP
+Set maximum BIP141 block weight (default: 3000000)
+.HP
+\fB\-blockmaxsize=\fR<n>
+.IP
+Set maximum block size in bytes (default: 750000)
+.HP
+\fB\-blockprioritysize=\fR<n>
+.IP
+Set maximum size of high\-priority/low\-fee transactions in bytes
+(default: 0)
+.PP
+RPC server options:
+.HP
+\fB\-server\fR
+.IP
+Accept command line and JSON\-RPC commands
+.HP
+\fB\-rest\fR
+.IP
+Accept public REST requests (default: 0)
+.HP
+\fB\-rpcbind=\fR<addr>
+.IP
+Bind to given address to listen for JSON\-RPC connections. Use
+[host]:port notation for IPv6. This option can be specified
+multiple times (default: bind to all interfaces)
+.HP
+\fB\-rpccookiefile=\fR<loc>
+.IP
+Location of the auth cookie (default: data dir)
+.HP
+\fB\-rpcuser=\fR<user>
+.IP
+Username for JSON\-RPC connections
+.HP
+\fB\-rpcpassword=\fR<pw>
+.IP
+Password for JSON\-RPC connections
+.HP
+\fB\-rpcauth=\fR<userpw>
+.IP
+Username and hashed password for JSON\-RPC connections. The field
+<userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A
+canonical python script is included in share/rpcuser. This option
+can be specified multiple times
+.HP
+\fB\-rpcport=\fR<port>
+.IP
+Listen for JSON\-RPC connections on <port> (default: 8332 or testnet:
+18332)
+.HP
+\fB\-rpcallowip=\fR<ip>
+.IP
+Allow JSON\-RPC connections from specified source. Valid for <ip> are a
+single IP (e.g. 1.2.3.4), a network/netmask (e.g.
+1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This
+option can be specified multiple times
+.HP
+\fB\-rpcthreads=\fR<n>
+.IP
+Set the number of threads to service RPC calls (default: 4)
+.SH COPYRIGHT
+Copyright (C) 2009-2016 The Bitcoin Core developers
+
+Please contribute if you find Bitcoin Core useful. Visit
+<https://bitcoincore.org> for further information about the software.
+The source code is available from <https://github.com/bitcoin/bitcoin>.
+
+This is experimental software.
+Distributed under the MIT software license, see the accompanying file COPYING
+or <http://www.opensource.org/licenses/mit-license.php>.
+
+This product includes software developed by the OpenSSL Project for use in the
+OpenSSL Toolkit <https://www.openssl.org/> and cryptographic software written
+by Eric Young and UPnP software written by Thomas Bernard.
diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md
index 2d86588eb2..697099beab 100644
--- a/doc/reduce-traffic.md
+++ b/doc/reduce-traffic.md
@@ -19,8 +19,7 @@ This is *not* a hard limit; only a threshold to minimize the outbound
traffic. When the limit is about to be reached, the uploaded data is cut by no
longer serving historic blocks (blocks older than one week).
Keep in mind that new nodes require other nodes that are willing to serve
-historic blocks. **The recommended minimum is 144 blocks per day (max. 144MB
-per day)**
+historic blocks.
Whitelisted peers will never be disconnected, although their traffic counts for
calculating the target.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index b99192ae97..58994a6839 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -41,6 +41,14 @@ report issues about Windows XP to the issue tracker.
Notable changes
===============
+Low-level RPC changes
+----------------------
+
+- `importprunedfunds` only accepts two required arguments. Some versions accept
+ an optional third arg, which was always ignored. Make sure to never pass more
+ than two arguments.
+
+
0.14.0 Change log
=================
@@ -51,6 +59,12 @@ git merge commit are mentioned.
### RPC and REST
+UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n>/.../<txid>-<n>.<bin|hex|json>`) responses
+were changed to return status code HTTP_BAD_REQUEST (400) instead of HTTP_INTERNAL_SERVER_ERROR (500) when requests
+contain invalid parameters.
+
+The first boolean argument to `getaddednodeinfo` has been removed. This is an incompatible change.
+
### Configuration and command-line options
### Block and transaction handling
diff --git a/doc/release-process.md b/doc/release-process.md
index 41c1ac8556..394b159b31 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -137,9 +137,10 @@ Build output expected:
### Verify other gitian builders signatures to your own. (Optional)
-Add other gitian builders keys to your gpg keyring
+Add other gitian builders keys to your gpg keyring, and/or refresh keys.
gpg --import bitcoin/contrib/gitian-keys/*.pgp
+ gpg --refresh-keys
Verify the signatures
diff --git a/doc/translation_process.md b/doc/translation_process.md
index d8a85292e8..9e9ced2457 100644
--- a/doc/translation_process.md
+++ b/doc/translation_process.md
@@ -6,7 +6,7 @@ The Bitcoin-Core project has been designed to support multiple localisations. Th
### Helping to translate (using Transifex)
Transifex is setup to monitor the Github repo for updates, and when code containing new translations is found, Transifex will process any changes. It may take several hours after a pull-request has been merged, to appear in the Transifex web interface.
-Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-boarder money transfers, any help making that easier is greatly appreciated.
+Multiple language support is critical in assisting Bitcoin’s global adoption, and growth. One of Bitcoin’s greatest strengths is cross-border money transfers, any help making that easier is greatly appreciated.
See the [Transifex Bitcoin project](https://www.transifex.com/projects/p/bitcoin/) to assist in translations. You should also join the translation mailing list for announcements - see details below.
@@ -94,7 +94,7 @@ When new plurals are added to the source file, it's important to do the followin
7. Save the source file
### Translating a new language
-To create a new language template, you will need to edit the languages manifest file `src/qt/bitcoin.qrc` and add a new entry. Below is an example of the English language entry.
+To create a new language template, you will need to edit the languages manifest file `src/qt/bitcoin_locale.qrc` and add a new entry. Below is an example of the English language entry.
```xml
<qresource prefix="/translations">
diff --git a/qa/README.md b/qa/README.md
index 723660c6c8..225207cc1c 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -41,8 +41,8 @@ Run all possible tests with
qa/pull-tester/rpc-tests.py -extended
-By default, tests will be run in parallel if you want to specify how many
-tests should be run in parallel, append `-parallel=n` (default n=4).
+By default, tests will be run in parallel. To specify how many jobs to run,
+append `-parallel=n` (default n=4).
If you want to create a basic coverage report for the rpc test suite, append `--coverage`.
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 92cce6aadd..df86861d36 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -92,12 +92,12 @@ if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
if ENABLE_ZMQ:
try:
import zmq
- except ImportError as e:
- print("WARNING: \"import zmq\" failed. Set ENABLE_ZMQ=0 or " \
- "to run zmq tests, see dependency info in /qa/README.md.")
- ENABLE_ZMQ=0
+ except ImportError:
+ print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or "
+ "to run zmq tests, see dependency info in /qa/README.md.")
+ # ENABLE_ZMQ=0
+ raise
-#Tests
testScripts = [
# longest test should go first, to favor running tests in parallel
'p2p-fullblocktest.py',
@@ -143,6 +143,7 @@ testScripts = [
'importprunedfunds.py',
'signmessages.py',
'p2p-compactblocks.py',
+ 'nulldummy.py',
]
if ENABLE_ZMQ:
testScripts.append('zmq_test.py')
@@ -251,21 +252,27 @@ class RPCTestHandler:
self.num_running += 1
t = self.test_list.pop(0)
port_seed = ["--portseed=%s" % len(self.test_list)]
+ log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16)
+ log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
self.jobs.append((t,
time.time(),
subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed,
universal_newlines=True,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)))
+ stdout=log_stdout,
+ stderr=log_stderr),
+ log_stdout,
+ log_stderr))
if not self.jobs:
raise IndexError('pop from empty list')
while True:
# Return first proc that finishes
time.sleep(.5)
for j in self.jobs:
- (name, time0, proc) = j
+ (name, time0, proc, log_out, log_err) = j
if proc.poll() is not None:
- (stdout, stderr) = proc.communicate(timeout=3)
+ log_out.seek(0), log_err.seek(0)
+ [stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)]
+ log_out.close(), log_err.close()
passed = stderr == "" and proc.returncode == 0
self.num_running -= 1
self.jobs.remove(j)
diff --git a/qa/rpc-tests/create_cache.py b/qa/rpc-tests/create_cache.py
index b6161e0917..1ace6310d0 100755
--- a/qa/rpc-tests/create_cache.py
+++ b/qa/rpc-tests/create_cache.py
@@ -12,9 +12,15 @@ from test_framework.test_framework import BitcoinTestFramework
class CreateCache(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+
+ # Test network and test nodes are not required:
+ self.num_nodes = 0
+ self.nodes = []
+
def setup_network(self):
- # Don't setup any test nodes
- self.options.noshutdown = True
+ pass
def run_test(self):
pass
diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py
index eb3c11b4d8..0dee8ad4ec 100755
--- a/qa/rpc-tests/importprunedfunds.py
+++ b/qa/rpc-tests/importprunedfunds.py
@@ -20,14 +20,10 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
self.is_network_split=False
self.sync_all()
- def run_test (self):
- import time
- begintime = int(time.time())
-
+ def run_test(self):
print("Mining blocks...")
self.nodes[0].generate(101)
- # sync
self.sync_all()
# address
@@ -72,7 +68,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
rawtxn2 = self.nodes[0].gettransaction(txnid2)['hex']
proof2 = self.nodes[0].gettxoutproof([txnid2])
-
txnid3 = self.nodes[0].sendtoaddress(address3, 0.025)
self.nodes[0].generate(1)
rawtxn3 = self.nodes[0].gettransaction(txnid3)['hex']
@@ -82,28 +77,27 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
#Import with no affiliated address
try:
- result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "")
+ self.nodes[1].importprunedfunds(rawtxn1, proof1)
except JSONRPCException as e:
assert('No addresses' in e.error['message'])
else:
assert(False)
-
balance1 = self.nodes[1].getbalance("", 0, True)
assert_equal(balance1, Decimal(0))
#Import with affiliated address with no rescan
- self.nodes[1].importaddress(address2, "", False)
- result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2, "")
- balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ self.nodes[1].importaddress(address2, "add2", False)
+ result2 = self.nodes[1].importprunedfunds(rawtxn2, proof2)
+ balance2 = self.nodes[1].getbalance("add2", 0, True)
assert_equal(balance2, Decimal('0.05'))
#Import with private key with no rescan
- self.nodes[1].importprivkey(address3_privkey, "", False)
- result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3, "")
- balance3 = Decimal(self.nodes[1].getbalance("", 0, False))
+ self.nodes[1].importprivkey(address3_privkey, "add3", False)
+ result3 = self.nodes[1].importprunedfunds(rawtxn3, proof3)
+ balance3 = self.nodes[1].getbalance("add3", 0, False)
assert_equal(balance3, Decimal('0.025'))
- balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance3 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance3, Decimal('0.075'))
#Addresses Test - after import
@@ -118,7 +112,6 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
assert_equal(address_info['ismine'], True)
#Remove transactions
-
try:
self.nodes[1].removeprunedfunds(txnid1)
except JSONRPCException as e:
@@ -126,18 +119,16 @@ class ImportPrunedFundsTest(BitcoinTestFramework):
else:
assert(False)
-
- balance1 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance1 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance1, Decimal('0.075'))
-
self.nodes[1].removeprunedfunds(txnid2)
- balance2 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance2 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance2, Decimal('0.025'))
self.nodes[1].removeprunedfunds(txnid3)
- balance3 = Decimal(self.nodes[1].getbalance("", 0, True))
+ balance3 = self.nodes[1].getbalance("*", 0, True)
assert_equal(balance3, Decimal('0.0'))
if __name__ == '__main__':
- ImportPrunedFundsTest ().main ()
+ ImportPrunedFundsTest().main()
diff --git a/qa/rpc-tests/nulldummy.py b/qa/rpc-tests/nulldummy.py
new file mode 100755
index 0000000000..eaed7a8c78
--- /dev/null
+++ b/qa/rpc-tests/nulldummy.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+from test_framework.test_framework import ComparisonTestFramework
+from test_framework.util import *
+from test_framework.mininode import CTransaction, NetworkThread
+from test_framework.blocktools import create_coinbase, create_block, add_witness_commitment
+from test_framework.comptool import TestManager
+from test_framework.script import CScript
+from io import BytesIO
+import time
+
+NULLDUMMY_ERROR = "64: non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero)"
+
+def trueDummy(tx):
+ scriptSig = CScript(tx.vin[0].scriptSig)
+ newscript = []
+ for i in scriptSig:
+ if (len(newscript) == 0):
+ assert(len(i) == 0)
+ newscript.append(b'\x51')
+ else:
+ newscript.append(i)
+ tx.vin[0].scriptSig = CScript(newscript)
+ tx.rehash()
+
+'''
+This test is meant to exercise NULLDUMMY softfork.
+Connect to a single node.
+Generate 2 blocks (save the coinbases for later).
+Generate 427 more blocks.
+[Policy/Consensus] Check that NULLDUMMY compliant transactions are accepted in the 430th block.
+[Policy] Check that non-NULLDUMMY transactions are rejected before activation.
+[Consensus] Check that the new NULLDUMMY rules are not enforced on the 431st block.
+[Policy/Consensus] Check that the new NULLDUMMY rules are enforced on the 432nd block.
+'''
+
+class NULLDUMMYTest(ComparisonTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 1
+
+ def setup_network(self):
+ # Must set the blockversion for this test
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
+ extra_args=[['-debug', '-whitelist=127.0.0.1', '-walletprematurewitness']])
+
+ def run_test(self):
+ self.address = self.nodes[0].getnewaddress()
+ self.ms_address = self.nodes[0].addmultisigaddress(1,[self.address])
+ self.wit_address = self.nodes[0].addwitnessaddress(self.address)
+ self.wit_ms_address = self.nodes[0].addwitnessaddress(self.ms_address)
+
+ test = TestManager(self, self.options.tmpdir)
+ test.add_all_connections(self.nodes)
+ NetworkThread().start() # Start up network handling in another thread
+ self.coinbase_blocks = self.nodes[0].generate(2) # Block 2
+ coinbase_txid = []
+ for i in self.coinbase_blocks:
+ coinbase_txid.append(self.nodes[0].getblock(i)['tx'][0])
+ self.nodes[0].generate(427) # Block 429
+ self.lastblockhash = self.nodes[0].getbestblockhash()
+ self.tip = int("0x" + self.lastblockhash, 0)
+ self.lastblockheight = 429
+ self.lastblocktime = int(time.time()) + 429
+
+ print ("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]")
+ test1txs = [self.create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, 49)]
+ txid1 = self.tx_submit(self.nodes[0], test1txs[0])
+ test1txs.append(self.create_transaction(self.nodes[0], txid1, self.ms_address, 48))
+ txid2 = self.tx_submit(self.nodes[0], test1txs[1])
+ test1txs.append(self.create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, 49))
+ txid3 = self.tx_submit(self.nodes[0], test1txs[2])
+ self.block_submit(self.nodes[0], test1txs, False, True)
+
+ print ("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
+ test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 48)
+ trueDummy(test2tx)
+ txid4 = self.tx_submit(self.nodes[0], test2tx, NULLDUMMY_ERROR)
+
+ print ("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]")
+ self.block_submit(self.nodes[0], [test2tx], False, True)
+
+ print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
+ test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 47)
+ test6txs=[CTransaction(test4tx)]
+ trueDummy(test4tx)
+ self.tx_submit(self.nodes[0], test4tx, NULLDUMMY_ERROR)
+ self.block_submit(self.nodes[0], [test4tx])
+
+ print ("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation")
+ test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48)
+ test6txs.append(CTransaction(test5tx))
+ test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01'
+ self.tx_submit(self.nodes[0], test5tx, NULLDUMMY_ERROR)
+ self.block_submit(self.nodes[0], [test5tx], True)
+
+ print ("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]")
+ for i in test6txs:
+ self.tx_submit(self.nodes[0], i)
+ self.block_submit(self.nodes[0], test6txs, True, True)
+
+
+ def create_transaction(self, node, txid, to_address, amount):
+ inputs = [{ "txid" : txid, "vout" : 0}]
+ outputs = { to_address : amount }
+ rawtx = node.createrawtransaction(inputs, outputs)
+ signresult = node.signrawtransaction(rawtx)
+ tx = CTransaction()
+ f = BytesIO(hex_str_to_bytes(signresult['hex']))
+ tx.deserialize(f)
+ return tx
+
+
+ def tx_submit(self, node, tx, msg = ""):
+ tx.rehash()
+ try:
+ node.sendrawtransaction(bytes_to_hex_str(tx.serialize_with_witness()), True)
+ except JSONRPCException as exp:
+ assert_equal(exp.error["message"], msg)
+ return tx.hash
+
+
+ def block_submit(self, node, txs, witness = False, accept = False):
+ block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)
+ block.nVersion = 4
+ for tx in txs:
+ tx.rehash()
+ block.vtx.append(tx)
+ block.hashMerkleRoot = block.calc_merkle_root()
+ witness and add_witness_commitment(block)
+ block.rehash()
+ block.solve()
+ node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ if (accept):
+ assert_equal(node.getbestblockhash(), block.hash)
+ self.tip = block.sha256
+ self.lastblockhash = block.hash
+ self.lastblocktime += 1
+ self.lastblockheight += 1
+ else:
+ assert_equal(node.getbestblockhash(), self.lastblockhash)
+
+if __name__ == '__main__':
+ NULLDUMMYTest().main() \ No newline at end of file
diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py
index 7fe7ecc16c..bf4fb43add 100755
--- a/qa/rpc-tests/p2p-compactblocks.py
+++ b/qa/rpc-tests/p2p-compactblocks.py
@@ -78,6 +78,13 @@ class TestNode(SingleNodeConnCB):
headers_message.headers = [CBlockHeader(b) for b in new_blocks]
self.send_message(headers_message)
+ def request_headers_and_sync(self, locator, hashstop=0):
+ self.clear_block_announcement()
+ self.get_headers(locator, hashstop)
+ assert(wait_until(self.received_block_announcement, timeout=30))
+ assert(self.received_block_announcement())
+ self.clear_block_announcement()
+
class CompactBlocksTest(BitcoinTestFramework):
def __init__(self):
@@ -130,7 +137,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Test "sendcmpct":
# - No compact block announcements or getdata(MSG_CMPCT_BLOCK) unless
# sendcmpct is sent.
- # - If sendcmpct is sent with version > 0, the message is ignored.
+ # - If sendcmpct is sent with version > 1, the message is ignored.
# - If sendcmpct is sent with boolean 0, then block announcements are not
# made with compact blocks.
# - If sendcmpct is then sent with boolean 1, then new block announcements
@@ -142,57 +149,66 @@ class CompactBlocksTest(BitcoinTestFramework):
def received_sendcmpct():
return (self.test_node.last_sendcmpct is not None)
got_message = wait_until(received_sendcmpct, timeout=30)
+ assert(received_sendcmpct())
assert(got_message)
assert_equal(self.test_node.last_sendcmpct.version, 1)
tip = int(self.nodes[0].getbestblockhash(), 16)
def check_announcement_of_new_block(node, peer, predicate):
- self.test_node.clear_block_announcement()
+ peer.clear_block_announcement()
node.generate(1)
- got_message = wait_until(peer.received_block_announcement, timeout=30)
+ got_message = wait_until(lambda: peer.block_announced, timeout=30)
+ assert(peer.block_announced)
assert(got_message)
with mininode_lock:
- assert(predicate)
+ assert(predicate(peer))
# We shouldn't get any block announcements via cmpctblock yet.
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None)
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None)
# Try one more time, this time after requesting headers.
- self.test_node.clear_block_announcement()
- self.test_node.get_headers(locator=[tip], hashstop=0)
- wait_until(self.test_node.received_block_announcement, timeout=30)
- self.test_node.clear_block_announcement()
+ self.test_node.request_headers_and_sync(locator=[tip])
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None and p.last_inv is not None)
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None and self.test_node.last_inv is not None)
+ # Test a few ways of using sendcmpct that should NOT
+ # result in compact block announcements.
+ # Before each test, sync the headers chain.
+ self.test_node.request_headers_and_sync(locator=[tip])
# Now try a SENDCMPCT message with too-high version
sendcmpct = msg_sendcmpct()
sendcmpct.version = 2
- self.test_node.send_message(sendcmpct)
+ self.test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None)
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None)
+ # Headers sync before next test.
+ self.test_node.request_headers_and_sync(locator=[tip])
# Now try a SENDCMPCT message with valid version, but announce=False
- self.test_node.send_message(msg_sendcmpct())
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None)
+ self.test_node.send_and_ping(msg_sendcmpct())
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None)
+
+ # Headers sync before next test.
+ self.test_node.request_headers_and_sync(locator=[tip])
# Finally, try a SENDCMPCT message with announce=True
sendcmpct.version = 1
sendcmpct.announce = True
- self.test_node.send_message(sendcmpct)
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None)
+ self.test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None)
- # Try one more time
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None)
+ # Try one more time (no headers sync should be needed!)
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None)
# Try one more time, after turning on sendheaders
- self.test_node.send_message(msg_sendheaders())
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is not None)
+ self.test_node.send_and_ping(msg_sendheaders())
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is not None)
# Now turn off announcements
sendcmpct.announce = False
- check_announcement_of_new_block(self.nodes[0], self.test_node, lambda: self.test_node.last_cmpctblock is None and self.test_node.last_headers is not None)
+ self.test_node.send_and_ping(sendcmpct)
+ check_announcement_of_new_block(self.nodes[0], self.test_node, lambda p: p.last_cmpctblock is None and p.last_headers is not None)
# This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
def test_invalid_cmpctblock_message(self):
diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py
index eb857ed983..22ec0ad8c8 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/qa/rpc-tests/p2p-segwit.py
@@ -305,13 +305,18 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# We'll add an unnecessary witness to this transaction that would cause
- # it to be too large according to IsStandard.
+ # it to be non-standard, to test that violating policy with a witness before
+ # segwit activation doesn't blind a node to a transaction. Transactions
+ # rejected for having a witness before segwit activation shouldn't be added
+ # to the rejection cache.
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), CScript([p2sh_program])))
tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, scriptPubKey))
tx3.wit.vtxinwit.append(CTxInWitness())
tx3.wit.vtxinwit[0].scriptWitness.stack = [b'a'*400000]
tx3.rehash()
+ # Note that this should be rejected for the premature witness reason,
+ # rather than a policy check, since segwit hasn't activated yet.
self.std_node.test_transaction_acceptance(tx3, True, False, b'no-witness-yet')
# If we send without witness, it should be accepted.
@@ -949,8 +954,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.test_transaction_acceptance(tx, with_witness=True, accepted=False)
# Verify that removing the witness succeeds.
- # Re-announcing won't result in a getdata for ~2.5 minutes, so just
- # deliver the modified transaction.
+ self.test_node.announce_tx_and_wait_for_getdata(tx)
self.test_node.test_transaction_acceptance(tx, with_witness=False, accepted=True)
# Now try to add extra witness data to a valid witness tx.
@@ -964,8 +968,24 @@ class SegWitTest(BitcoinTestFramework):
tx3 = CTransaction()
tx3.vin.append(CTxIn(COutPoint(tx2.sha256, 0), b""))
- tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_TRUE])))
tx3.wit.vtxinwit.append(CTxInWitness())
+
+ # Add too-large for IsStandard witness and check that it does not enter reject filter
+ p2sh_program = CScript([OP_TRUE])
+ p2sh_pubkey = hash160(p2sh_program)
+ witness_program2 = CScript([b'a'*400000])
+ tx3.vout.append(CTxOut(tx2.vout[0].nValue-1000, CScript([OP_HASH160, p2sh_pubkey, OP_EQUAL])))
+ tx3.wit.vtxinwit[0].scriptWitness.stack = [witness_program2]
+ tx3.rehash()
+
+ # Node will not be blinded to the transaction
+ self.std_node.announce_tx_and_wait_for_getdata(tx3)
+ self.std_node.test_transaction_acceptance(tx3, True, False, b'tx-size')
+ self.std_node.announce_tx_and_wait_for_getdata(tx3)
+ self.std_node.test_transaction_acceptance(tx3, True, False, b'tx-size')
+
+ # Remove witness stuffing, instead add extra witness push on stack
+ tx3.vout[0] = CTxOut(tx2.vout[0].nValue-1000, CScript([OP_TRUE]))
tx3.wit.vtxinwit[0].scriptWitness.stack = [CScript([CScriptNum(1)]), witness_program ]
tx3.rehash()
diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py
index c9c2eaf7f3..b769cd71f2 100755
--- a/qa/rpc-tests/rest.py
+++ b/qa/rpc-tests/rest.py
@@ -179,14 +179,14 @@ class RESTTest (BitcoinTestFramework):
#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, 500) #must be a 500 because we send a invalid json request
+ assert_equal(response.status, 400) #must be a 400 because we send a 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, 500) #must be a 500 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
response = http_post_call(url.hostname, url.port, '/rest/getutxos/checkmempool'+self.FORMAT_SEPARATOR+'bin', '', True)
- assert_equal(response.status, 500) #must be a 500 because we send a invalid bin request
+ assert_equal(response.status, 400) #must be a 400 because we send a invalid bin request
#test limits
json_request = '/checkmempool/'
@@ -194,14 +194,14 @@ class RESTTest (BitcoinTestFramework):
json_request += txid+'-'+str(n)+'/'
json_request = json_request.rstrip("/")
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
- assert_equal(response.status, 500) #must be a 500 because we exceeding the limits
+ assert_equal(response.status, 400) #must be a 400 because we exceeding the limits
json_request = '/checkmempool/'
for x in range(0, 15):
json_request += txid+'-'+str(n)+'/'
json_request = json_request.rstrip("/")
response = http_post_call(url.hostname, url.port, '/rest/getutxos'+json_request+self.FORMAT_SEPARATOR+'json', '', True)
- assert_equal(response.status, 200) #must be a 500 because we exceeding the limits
+ assert_equal(response.status, 200) #must be a 200 because we are within the limits
self.nodes[0].generate(1) #generate block to not affect upcoming tests
self.sync_all()
diff --git a/qa/rpc-tests/test_framework/blockstore.py b/qa/rpc-tests/test_framework/blockstore.py
index 6120dd574b..1e2bbb277a 100644
--- a/qa/rpc-tests/test_framework/blockstore.py
+++ b/qa/rpc-tests/test_framework/blockstore.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python3
+# Copyright (c) 2015-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# BlockStore: a helper class that keeps a map of blocks and implements
# helper functions for responding to getheaders and getdata,
# and for constructing a getheaders message
diff --git a/qa/rpc-tests/test_framework/script.py b/qa/rpc-tests/test_framework/script.py
index b46c643ccb..83bbf20479 100644
--- a/qa/rpc-tests/test_framework/script.py
+++ b/qa/rpc-tests/test_framework/script.py
@@ -882,7 +882,7 @@ def SignatureHash(script, txTo, inIdx, hashtype):
tmp = txtmp.vout[outIdx]
txtmp.vout = []
for i in range(outIdx):
- txtmp.vout.append(CTxOut())
+ txtmp.vout.append(CTxOut(-1))
txtmp.vout.append(tmp)
for i in range(len(txtmp.vin)):
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index a1383729fa..186cf866cf 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -125,7 +125,8 @@ class BitcoinTestFramework(object):
self.add_options(parser)
(self.options, self.args) = parser.parse_args()
- self.options.tmpdir += '/' + str(self.options.port_seed)
+ # backup dir variable for removal at cleanup
+ self.options.root, self.options.tmpdir = self.options.tmpdir, self.options.tmpdir + '/' + str(self.options.port_seed)
if self.options.trace_rpc:
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
@@ -176,6 +177,8 @@ class BitcoinTestFramework(object):
if not self.options.nocleanup and not self.options.noshutdown and success:
print("Cleaning up")
shutil.rmtree(self.options.tmpdir)
+ if not os.listdir(self.options.root):
+ os.rmdir(self.options.root)
else:
print("Not cleaning up dir %s" % self.options.tmpdir)
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 190fa7f661..eee77f1a10 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -125,12 +125,16 @@ def sync_blocks(rpc_connections, wait=1, timeout=60):
"""
Wait until everybody has the same tip
"""
+ maxheight = 0
while timeout > 0:
- tips = [ x.getbestblockhash() for x in rpc_connections ]
+ tips = [ x.waitforblockheight(maxheight, int(wait * 1000)) for x in rpc_connections ]
+ heights = [ x["height"] for x in tips ]
if tips == [ tips[0] ]*len(tips):
return True
- time.sleep(wait)
+ if heights == [ heights[0] ]*len(heights): #heights are the same but hashes are not
+ raise AssertionError("Block sync failed")
timeout -= wait
+ maxheight = max(heights)
raise AssertionError("Block sync failed")
def sync_mempools(rpc_connections, wait=1, timeout=60):
diff --git a/qa/rpc-tests/wallet-hd.py b/qa/rpc-tests/wallet-hd.py
index c11da1e9a9..a49d91f6f4 100755
--- a/qa/rpc-tests/wallet-hd.py
+++ b/qa/rpc-tests/wallet-hd.py
@@ -39,8 +39,8 @@ class WalletHDTest(BitcoinTestFramework):
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
# This should be enough to keep the master key and the non-HD key
- self.nodes[1].backupwallet(tmpdir + "hd.bak")
- #self.nodes[1].dumpwallet(tmpdir + "hd.dump")
+ self.nodes[1].backupwallet(tmpdir + "/hd.bak")
+ #self.nodes[1].dumpwallet(tmpdir + "/hd.dump")
# Derive some HD addresses and remember the last
# Also send funds to each add
@@ -63,7 +63,7 @@ class WalletHDTest(BitcoinTestFramework):
print("Restore backup ...")
self.stop_node(1)
os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
- shutil.copyfile(tmpdir + "hd.bak", tmpdir + "/node1/regtest/wallet.dat")
+ shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1])
#connect_nodes_bi(self.nodes, 0, 1)
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 5d96e7a6e5..3420be1a2e 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -18,9 +18,10 @@ class WalletTest (BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
+ self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)]
def setup_network(self, split=False):
- self.nodes = start_nodes(3, self.options.tmpdir)
+ self.nodes = start_nodes(3, self.options.tmpdir, self.extra_args[:3])
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,0,2)
@@ -154,7 +155,7 @@ class WalletTest (BitcoinTestFramework):
txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
sync_mempools(self.nodes)
- self.nodes.append(start_node(3, self.options.tmpdir))
+ self.nodes.append(start_node(3, self.options.tmpdir, self.extra_args[3]))
connect_nodes_bi(self.nodes, 0, 3)
sync_blocks(self.nodes)
diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py
index b991d5c761..e12cb10a50 100755
--- a/qa/rpc-tests/walletbackup.py
+++ b/qa/rpc-tests/walletbackup.py
@@ -45,12 +45,12 @@ class WalletBackupTest(BitcoinTestFramework):
super().__init__()
self.setup_clean_chain = True
self.num_nodes = 4
+ # nodes 1, 2,3 are spenders, let's give them a keypool=100
+ self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
# This mirrors how the network was setup in the bash test
def setup_network(self, split=False):
- # nodes 1, 2,3 are spenders, let's give them a keypool=100
- extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []]
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[1], 3)
connect_nodes(self.nodes[2], 3)
@@ -79,6 +79,7 @@ class WalletBackupTest(BitcoinTestFramework):
# Must sync mempools before mining.
sync_mempools(self.nodes)
self.nodes[3].generate(1)
+ sync_blocks(self.nodes)
# As above, this mirrors the original bash test.
def start_three(self):
diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py
index 9624abf1fc..92e0df259e 100755
--- a/share/qt/extract_strings_qt.py
+++ b/share/qt/extract_strings_qt.py
@@ -1,4 +1,7 @@
#!/usr/bin/env python
+# Copyright (c) 2012-2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Extract _("...") strings for translation and convert to Qt stringdefs so that
they can be picked up by Qt linguist.
diff --git a/share/qt/protobuf.pri b/share/qt/protobuf.pri
deleted file mode 100644
index 865fe86555..0000000000
--- a/share/qt/protobuf.pri
+++ /dev/null
@@ -1,35 +0,0 @@
-# Based on: http://code.google.com/p/ostinato/source/browse/protobuf.pri
-#
-# Qt qmake integration with Google Protocol Buffers compiler protoc
-#
-# To compile protocol buffers with qt qmake, specify PROTOS variable and
-# include this file
-#
-# Example:
-# PROTOS = a.proto b.proto
-# include(protobuf.pri)
-#
-# Set PROTO_PATH if you need to set the protoc --proto_path search path
-# Set PROTOC to the path to the protoc compiler if it is not in your $PATH
-#
-
-isEmpty(PROTO_DIR):PROTO_DIR = .
-isEmpty(PROTOC):PROTOC = protoc
-
-PROTOPATHS =
-for(p, PROTO_PATH):PROTOPATHS += --proto_path=$${p}
-
-protobuf_decl.name = protobuf header
-protobuf_decl.input = PROTOS
-protobuf_decl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h
-protobuf_decl.commands = $${PROTOC} --cpp_out="$${PROTO_DIR}" $${PROTOPATHS} --proto_path=${QMAKE_FILE_IN_PATH} ${QMAKE_FILE_NAME}
-protobuf_decl.variable_out = GENERATED_FILES
-QMAKE_EXTRA_COMPILERS += protobuf_decl
-
-protobuf_impl.name = protobuf implementation
-protobuf_impl.input = PROTOS
-protobuf_impl.output = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.cc
-protobuf_impl.depends = $${PROTO_DIR}/${QMAKE_FILE_BASE}.pb.h
-protobuf_impl.commands = $$escape_expand(\\n)
-protobuf_impl.variable_out = GENERATED_SOURCES
-QMAKE_EXTRA_COMPILERS += protobuf_impl
diff --git a/src/Makefile.am b/src/Makefile.am
index 03fac5bf97..ebdddc87f5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -71,6 +71,7 @@ endif
.PHONY: FORCE check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
+ addrdb.h \
addrman.h \
base58.h \
bloom.h \
@@ -164,6 +165,7 @@ libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CP
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
+ addrdb.cpp \
bloom.cpp \
blockencodings.cpp \
chain.cpp \
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 813a343ffa..0a7efb5d5b 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -1,13 +1,16 @@
bin_PROGRAMS += qt/test/test_bitcoin-qt
TESTS += qt/test/test_bitcoin-qt
-TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp
+TEST_QT_MOC_CPP = \
+ qt/test/moc_rpcnestedtests.cpp \
+ qt/test/moc_uritests.cpp
if ENABLE_WALLET
TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp
endif
TEST_QT_H = \
+ qt/test/rpcnestedtests.h \
qt/test/uritests.h \
qt/test/paymentrequestdata.h \
qt/test/paymentservertests.h
@@ -16,6 +19,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
qt_test_test_bitcoin_qt_SOURCES = \
+ qt/test/rpcnestedtests.cpp \
qt/test/test_main.cpp \
qt/test/uritests.cpp \
$(TEST_QT_H)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
new file mode 100644
index 0000000000..ddf41f92de
--- /dev/null
+++ b/src/addrdb.cpp
@@ -0,0 +1,218 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "addrdb.h"
+
+#include "addrman.h"
+#include "chainparams.h"
+#include "clientversion.h"
+#include "hash.h"
+#include "random.h"
+#include "streams.h"
+#include "tinyformat.h"
+#include "util.h"
+
+#include <boost/filesystem.hpp>
+
+CBanDB::CBanDB()
+{
+ pathBanlist = GetDataDir() / "banlist.dat";
+}
+
+bool CBanDB::Write(const banmap_t& banSet)
+{
+ // 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;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
+ 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());
+ }
+ FileCommit(fileout.Get());
+ fileout.fclose();
+
+ // replace existing banlist.dat, if any, with new banlist.dat.XXXX
+ if (!RenameOver(pathTmp, pathBanlist))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
+bool CBanDB::Read(banmap_t& banSet)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathBanlist.string().c_str(), "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 = boost::filesystem::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 {
+ // de-serialize file header (network specific magic number) and ..
+ ssBanlist >> 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
+ ssBanlist >> banSet;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
+
+CAddrDB::CAddrDB()
+{
+ pathAddr = GetDataDir() / "peers.dat";
+}
+
+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;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
+ if (fileout.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathTmp.string());
+
+ // 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();
+
+ // replace existing peers.dat, if any, with new peers.dat.XXXX
+ if (!RenameOver(pathTmp, pathAddr))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
+bool CAddrDB::Read(CAddrMan& addr)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathAddr.string().c_str(), "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 = boost::filesystem::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);
+}
+
+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
+ addr.Clear();
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
diff --git a/src/addrdb.h b/src/addrdb.h
new file mode 100644
index 0000000000..d8c66d872b
--- /dev/null
+++ b/src/addrdb.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_ADDRDB_H
+#define BITCOIN_ADDRDB_H
+
+#include "serialize.h"
+
+#include <string>
+#include <map>
+#include <boost/filesystem/path.hpp>
+
+class CSubNet;
+class CAddrMan;
+class CDataStream;
+
+typedef enum BanReason
+{
+ BanReasonUnknown = 0,
+ BanReasonNodeMisbehaving = 1,
+ BanReasonManuallyAdded = 2
+} BanReason;
+
+class CBanEntry
+{
+public:
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+ int64_t nCreateTime;
+ int64_t nBanUntil;
+ uint8_t banReason;
+
+ CBanEntry()
+ {
+ SetNull();
+ }
+
+ CBanEntry(int64_t nCreateTimeIn)
+ {
+ SetNull();
+ nCreateTime = nCreateTimeIn;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(nCreateTime);
+ READWRITE(nBanUntil);
+ READWRITE(banReason);
+ }
+
+ void SetNull()
+ {
+ nVersion = CBanEntry::CURRENT_VERSION;
+ nCreateTime = 0;
+ nBanUntil = 0;
+ banReason = BanReasonUnknown;
+ }
+
+ std::string banReasonToString()
+ {
+ switch (banReason) {
+ case BanReasonNodeMisbehaving:
+ return "node misbehaving";
+ case BanReasonManuallyAdded:
+ return "manually added";
+ default:
+ return "unknown";
+ }
+ }
+};
+
+typedef std::map<CSubNet, CBanEntry> banmap_t;
+
+/** Access to the (IP) address database (peers.dat) */
+class CAddrDB
+{
+private:
+ boost::filesystem::path pathAddr;
+public:
+ CAddrDB();
+ bool Write(const CAddrMan& addr);
+ bool Read(CAddrMan& addr);
+ bool Read(CAddrMan& addr, CDataStream& ssPeers);
+};
+
+/** Access to the banlist database (banlist.dat) */
+class CBanDB
+{
+private:
+ boost::filesystem::path pathBanlist;
+public:
+ CBanDB();
+ bool Write(const banmap_t& banSet);
+ bool Read(banmap_t& banSet);
+};
+
+#endif // BITCOIN_ADDRDB_H
diff --git a/src/addrman.cpp b/src/addrman.cpp
index cebb1c8e5e..bfb8e94575 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -255,6 +255,11 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
int nId;
CAddrInfo* pinfo = Find(addr, &nId);
+ // Do not set a penality for a source's self-announcement
+ if (addr == source) {
+ nTimePenalty = 0;
+ }
+
if (pinfo) {
// periodically update nTime
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 8e8ac47455..cb863bda19 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -395,10 +395,8 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
if (!registers.count("privatekeys"))
throw runtime_error("privatekeys register variable must be set.");
- bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
- fGivenKeys = true;
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
@@ -454,7 +452,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
- if (fGivenKeys && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
+ if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
@@ -517,7 +515,7 @@ public:
static void MutateTx(CMutableTransaction& tx, const string& command,
const string& commandVal)
{
- boost::scoped_ptr<Secp256k1Init> ecc;
+ std::unique_ptr<Secp256k1Init> ecc;
if (command == "nversion")
MutateTxVersion(tx, commandVal);
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 28bc374acc..322298d1b3 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -40,8 +40,6 @@
* Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code.
*/
-static bool fDaemon;
-
void WaitForShutdown(boost::thread_group* threadGroup)
{
bool fShutdown = ShutdownRequested();
@@ -130,8 +128,7 @@ bool AppInit(int argc, char* argv[])
exit(1);
}
#ifndef WIN32
- fDaemon = GetBoolArg("-daemon", false);
- if (fDaemon)
+ if (GetBoolArg("-daemon", false))
{
fprintf(stdout, "Bitcoin server starting\n");
diff --git a/src/blockencodings.h b/src/blockencodings.h
index b980e9e286..349fcbd50f 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -53,11 +53,11 @@ public:
}
uint16_t offset = 0;
- for (size_t i = 0; i < indexes.size(); i++) {
- if (uint64_t(indexes[i]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
+ for (size_t j = 0; j < indexes.size(); j++) {
+ if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max())
throw std::ios_base::failure("indexes overflowed 16 bits");
- indexes[i] = indexes[i] + offset;
- offset = indexes[i] + 1;
+ indexes[j] = indexes[j] + offset;
+ offset = indexes[j] + 1;
}
} else {
for (size_t i = 0; i < indexes.size(); i++) {
diff --git a/src/chain.h b/src/chain.h
index 76a774c123..6588e8f57d 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -137,15 +137,15 @@ enum BlockStatus: uint32_t {
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
- BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat
- BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat
+ BLOCK_HAVE_DATA = 8, //!< full block available in blk*.dat
+ BLOCK_HAVE_UNDO = 16, //!< undo data available in rev*.dat
BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO,
- BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed
- BLOCK_FAILED_CHILD = 64, //! descends from failed block
+ BLOCK_FAILED_VALID = 32, //!< stage after last reached validness failed
+ BLOCK_FAILED_CHILD = 64, //!< descends from failed block
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
- BLOCK_OPT_WITNESS = 128, //! block data in blk*.data was received with a witness-enforcing client
+ BLOCK_OPT_WITNESS = 128, //!< block data in blk*.data was received with a witness-enforcing client
};
/** The block chain is a tree shaped structure starting with the
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index ea6e3aada2..e6be1b5d5b 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -118,7 +118,7 @@ public:
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Christian Decker
vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch")); // Jonas Schnelli
+ vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 000b197270..3e24294a64 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -22,9 +22,9 @@ static const unsigned char REJECT_CHECKPOINT = 0x43;
class CValidationState {
private:
enum mode_state {
- MODE_VALID, //! everything ok
- MODE_INVALID, //! network rule violation (DoS value may be set)
- MODE_ERROR, //! run-time error
+ MODE_VALID, //!< everything ok
+ MODE_INVALID, //!< network rule violation (DoS value may be set)
+ MODE_ERROR, //!< run-time error
} mode;
int nDoS;
std::string strRejectReason;
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 09c68fbe55..4fa06135d2 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -117,7 +117,7 @@ std::vector<unsigned char> CDBWrapper::CreateObfuscateKey() const
bool CDBWrapper::IsEmpty()
{
- boost::scoped_ptr<CDBIterator> it(NewIterator());
+ std::unique_ptr<CDBIterator> it(NewIterator());
it->SeekToFirst();
return !(it->Valid());
}
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 04d3386e9a..6a6c5276cc 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -45,7 +45,7 @@ private:
class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
- HTTPRPCTimerInterface(struct event_base* base) : base(base)
+ HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
{
}
const char* Name()
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index f921305fcc..b296b28503 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -42,8 +42,8 @@ static const size_t MAX_HEADERS_SIZE = 8192;
class HTTPWorkItem : public HTTPClosure
{
public:
- HTTPWorkItem(std::unique_ptr<HTTPRequest> req, const std::string &path, const HTTPRequestHandler& func):
- req(std::move(req)), path(path), func(func)
+ HTTPWorkItem(std::unique_ptr<HTTPRequest> _req, const std::string &_path, const HTTPRequestHandler& _func):
+ req(std::move(_req)), path(_path), func(_func)
{
}
void operator()()
@@ -92,8 +92,8 @@ private:
};
public:
- WorkQueue(size_t maxDepth) : running(true),
- maxDepth(maxDepth),
+ WorkQueue(size_t _maxDepth) : running(true),
+ maxDepth(_maxDepth),
numThreads(0)
{
}
@@ -158,8 +158,8 @@ public:
struct HTTPPathHandler
{
HTTPPathHandler() {}
- HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
- prefix(prefix), exactMatch(exactMatch), handler(handler)
+ HTTPPathHandler(std::string _prefix, bool _exactMatch, HTTPRequestHandler _handler):
+ prefix(_prefix), exactMatch(_exactMatch), handler(_handler)
{
}
std::string prefix;
@@ -522,8 +522,8 @@ static void httpevent_callback_fn(evutil_socket_t, short, void* data)
delete self;
}
-HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const std::function<void(void)>& handler):
- deleteWhenTriggered(deleteWhenTriggered), handler(handler)
+HTTPEvent::HTTPEvent(struct event_base* base, bool _deleteWhenTriggered, const std::function<void(void)>& _handler):
+ deleteWhenTriggered(_deleteWhenTriggered), handler(_handler)
{
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
@@ -539,7 +539,7 @@ void HTTPEvent::trigger(struct timeval* tv)
else
evtimer_add(ev, tv); // trigger after timeval passed
}
-HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
+HTTPRequest::HTTPRequest(struct evhttp_request* _req) : req(_req),
replySent(false)
{
}
diff --git a/src/init.cpp b/src/init.cpp
index 13c68e512a..75182345ee 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -42,6 +42,7 @@
#endif
#include <stdint.h>
#include <stdio.h>
+#include <memory>
#ifndef WIN32
#include <signal.h>
@@ -70,6 +71,7 @@ static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_DISABLE_SAFEMODE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
+std::unique_ptr<CConnman> g_connman;
#if ENABLE_ZMQ
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
@@ -162,7 +164,7 @@ public:
static CCoinsViewDB *pcoinsdbview = NULL;
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
-static boost::scoped_ptr<ECCVerifyHandle> globalVerifyHandle;
+static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
{
@@ -197,7 +199,9 @@ void Shutdown()
if (pwalletMain)
pwalletMain->Flush(false);
#endif
- StopNode();
+ MapPort(false);
+ g_connman.reset();
+
StopTorControl();
UnregisterNodeSignals(GetNodeSignals());
@@ -269,20 +273,26 @@ void HandleSIGHUP(int)
fReopenDebugLog = true;
}
-bool static Bind(const CService &addr, unsigned int flags) {
+bool static Bind(CConnman& connman, 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 (!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);
+}
void OnRPCStopped()
{
+ uiInterface.NotifyBlockTip.disconnect(&RPCNotifyBlockChange);
+ RPCNotifyBlockChange(false, nullptr);
cvBlockChange.notify_all();
LogPrint("rpc", "RPC stopped.\n");
}
@@ -380,7 +390,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY));
- strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
+ strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY));
strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET));
#ifdef ENABLE_WALLET
@@ -666,6 +676,7 @@ bool InitSanityCheck(void)
bool AppInitServers(boost::thread_group& threadGroup)
{
+ RPCServer::OnStarted(&OnRPCStarted);
RPCServer::OnStopped(&OnRPCStopped);
RPCServer::OnPreCommand(&OnRPCPreCommand);
if (!InitHTTPServer())
@@ -748,10 +759,7 @@ void InitParameterInteraction()
if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
if (SoftSetBoolArg("-whitelistrelay", false))
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__);
-#ifdef ENABLE_WALLET
- if (SoftSetBoolArg("-walletbroadcast", false))
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
-#endif
+ // walletbroadcast is disabled in CWallet::ParameterInteraction()
}
// Forcing relay from whitelisted hosts implies we will accept relays from them in the first place.
@@ -810,12 +818,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError("Initializing networking failed");
#ifndef WIN32
- if (GetBoolArg("-sysperms", false)) {
-#ifdef ENABLE_WALLET
- if (!GetBoolArg("-disablewallet", false))
- return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
-#endif
- } else {
+ if (!GetBoolArg("-sysperms", false)) {
umask(077);
}
@@ -843,21 +846,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// also see: InitParameterInteraction()
- // if using block pruning, then disable txindex
+ // if using block pruning, then disallow txindex
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
-#ifdef ENABLE_WALLET
- if (GetBoolArg("-rescan", false)) {
- return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
- }
-#endif
}
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
- nMaxConnections = std::max(nUserMaxConnections, 0);
+ int nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
@@ -937,9 +935,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterAllCoreRPCCommands(tableRPC);
#ifdef ENABLE_WALLET
- bool fDisableWallet = GetBoolArg("-disablewallet", false);
- if (!fDisableWallet)
- RegisterWalletRPCCommands(tableRPC);
+ RegisterWalletRPCCommands(tableRPC);
#endif
nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
@@ -969,7 +965,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#ifdef ENABLE_WALLET
if (!CWallet::ParameterInteraction())
return false;
-#endif // ENABLE_WALLET
+#endif
fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
@@ -978,6 +974,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Option to startup with mocktime set (used for regression testing):
SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
+ ServiceFlags nLocalServices = NODE_NETWORK;
+ ServiceFlags nRelevantServices = NODE_NETWORK;
+
if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS))
nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM);
@@ -1094,13 +1093,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 5: verify wallet database integrity
#ifdef ENABLE_WALLET
- if (!fDisableWallet) {
- if (!CWallet::Verify())
- return false;
- } // (!fDisableWallet)
-#endif // ENABLE_WALLET
+ if (!CWallet::Verify())
+ return false;
+#endif
// ********************************************************* Step 6: network initialization
+ assert(!g_connman);
+ g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
+ CConnman& connman = *g_connman;
+
RegisterNodeSignals(GetNodeSignals());
// sanitize comments per BIP-0014, format user agent and check total size
@@ -1138,7 +1139,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
LookupSubNet(net.c_str(), subnet);
if (!subnet.IsValid())
return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net));
- CNode::AddWhitelistedRange(subnet);
+ connman.AddWhitelistedRange(subnet);
}
}
@@ -1183,14 +1184,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP);
fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
- bool fBound = false;
if (fListen) {
+ bool fBound = false;
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(ResolveErrMsg("bind", strBind));
- fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
+ fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
CService addrBind;
@@ -1198,14 +1199,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return InitError(ResolveErrMsg("whitebind", strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
- fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
+ fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
}
}
else {
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);
+ 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."));
@@ -1222,7 +1223,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
- AddOneShot(strDest);
+ connman.AddOneShot(strDest);
#if ENABLE_ZMQ
pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
@@ -1231,8 +1232,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
RegisterValidationInterface(pzmqNotificationInterface);
}
#endif
+ uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set
+ uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME;
+
if (mapArgs.count("-maxuploadtarget")) {
- CNode::SetMaxOutboundTarget(GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024);
+ nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024;
}
// ********************************************************* Step 7: load block chain
@@ -1357,6 +1361,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
LOCK(cs_main);
CBlockIndex* tip = chainActive.Tip();
+ RPCNotifyBlockChange(true, tip);
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
strLoadError = _("The block database contains a block which appears to be from the future. "
"This may be due to your computer's date and time being set incorrectly. "
@@ -1418,17 +1423,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
- if (fDisableWallet) {
- pwalletMain = NULL;
- LogPrintf("Wallet disabled!\n");
- } else {
- CWallet::InitLoadWallet();
- if (!pwalletMain)
- return false;
- }
-#else // ENABLE_WALLET
+ if (!CWallet::InitLoadWallet())
+ return false;
+#else
LogPrintf("No wallet support compiled in!\n");
-#endif // !ENABLE_WALLET
+#endif
// ********************************************************* Step 9: data directory maintenance
@@ -1497,7 +1496,28 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
StartTorControl(threadGroup, scheduler);
- StartNode(threadGroup, scheduler);
+ Discover(threadGroup);
+
+ // Map ports with UPnP
+ MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
+
+ std::string strNodeError;
+ CConnman::Options connOptions;
+ connOptions.nLocalServices = nLocalServices;
+ connOptions.nRelevantServices = nRelevantServices;
+ connOptions.nMaxConnections = nMaxConnections;
+ connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
+ connOptions.nMaxFeeler = 1;
+ connOptions.nBestHeight = chainActive.Height();
+ connOptions.uiInterface = &uiInterface;
+ connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
+ connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
+
+ connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe;
+ connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
+
+ if(!connman.Start(threadGroup, scheduler, strNodeError, connOptions))
+ return InitError(strNodeError);
// ********************************************************* Step 12: finished
diff --git a/src/main.cpp b/src/main.cpp
index 5160e60750..60bda426a6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -113,6 +113,8 @@ CScript COINBASE_FLAGS;
const string strMessageMagic = "Bitcoin Signed Message:\n";
+static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8]
+
// Internal stuff
namespace {
@@ -196,7 +198,7 @@ namespace {
*
* Memory used: 1.3 MB
*/
- boost::scoped_ptr<CRollingBloomFilter> recentRejects;
+ std::unique_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
@@ -325,12 +327,6 @@ CNodeState *State(NodeId pnode) {
return &it->second;
}
-int GetHeight()
-{
- LOCK(cs_main);
- return chainActive.Height();
-}
-
void UpdatePreferredDownload(CNode* node, CNodeState* state)
{
nPreferredDownload -= state->fPreferredDownload;
@@ -348,7 +344,8 @@ void InitializeNode(NodeId nodeid, const CNode *pnode) {
state.address = pnode->addr;
}
-void FinalizeNode(NodeId nodeid) {
+void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
+ fUpdateConnectionTime = false;
LOCK(cs_main);
CNodeState *state = State(nodeid);
@@ -356,7 +353,7 @@ void FinalizeNode(NodeId nodeid) {
nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
- AddressCurrentlyConnected(state->address);
+ fUpdateConnectionTime = true;
}
BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) {
@@ -469,8 +466,8 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
}
}
-void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom) {
- if (nLocalServices & NODE_WITNESS) {
+void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pfrom, CConnman& connman) {
+ if (pfrom->GetLocalServices() & NODE_WITNESS) {
// Don't ever request compact blocks when segwit is enabled.
return;
}
@@ -483,11 +480,12 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
- CNode* pnodeStop = FindNode(lNodesAnnouncingHeaderAndIDs.front());
- if (pnodeStop) {
+ bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
pnodeStop->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
+ return true;
+ });
+ if(found)
lNodesAnnouncingHeaderAndIDs.pop_front();
- }
}
fAnnounceUsingCMPCTBLOCK = true;
pfrom->PushMessage(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
@@ -532,7 +530,7 @@ CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) {
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries. */
-void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller) {
+void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBlockIndex*>& vBlocks, NodeId& nodeStaller, const Consensus::Params& consensusParams) {
if (count == 0)
return;
@@ -589,6 +587,10 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
// We consider the chain that this peer is on invalid.
return;
}
+ if (!State(nodeid)->fHaveWitness && IsWitnessEnabled(pindex->pprev, consensusParams)) {
+ // We wouldn't download this block or its descendants from this peer.
+ return;
+ }
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
if (pindex->nChainTx)
state->pindexLastCommonBlock = pindex;
@@ -633,7 +635,6 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
void RegisterNodeSignals(CNodeSignals& nodeSignals)
{
- nodeSignals.GetHeight.connect(&GetHeight);
nodeSignals.ProcessMessages.connect(&ProcessMessages);
nodeSignals.SendMessages.connect(&SendMessages);
nodeSignals.InitializeNode.connect(&InitializeNode);
@@ -642,7 +643,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals)
void UnregisterNodeSignals(CNodeSignals& nodeSignals)
{
- nodeSignals.GetHeight.disconnect(&GetHeight);
nodeSignals.ProcessMessages.disconnect(&ProcessMessages);
nodeSignals.SendMessages.disconnect(&SendMessages);
nodeSignals.InitializeNode.disconnect(&InitializeNode);
@@ -1492,13 +1492,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) {
+ PrecomputedTransactionData txdata(tx);
+ if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
- if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) {
- // Only the witness is wrong, so the transaction itself may be fine.
+ if (tx.wit.IsNull() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
+ !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
+ // Only the witness is missing, so the transaction itself may be fine.
state.SetCorruptionPossible();
}
return false;
@@ -1513,7 +1514,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
- if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
+ if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
{
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -1910,7 +1911,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL;
- if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
return false;
}
return true;
@@ -1969,7 +1970,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}// namespace Consensus
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1996,7 +1997,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@@ -2009,7 +2010,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
@@ -2063,7 +2064,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
// Open history file to read
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
- return error("%s: OpenBlockFile failed", __func__);
+ return error("%s: OpenUndoFile failed", __func__);
// Read block
uint256 hashChecksum;
@@ -2387,6 +2388,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Start enforcing WITNESS rules using versionbits logic.
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus())) {
flags |= SCRIPT_VERIFY_WITNESS;
+ flags |= SCRIPT_VERIFY_NULLDUMMY;
}
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1;
@@ -2405,6 +2407,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
vPos.reserve(block.vtx.size());
blockundo.vtxundo.reserve(block.vtx.size() - 1);
+ std::vector<PrecomputedTransactionData> txdata;
+ txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
const CTransaction &tx = block.vtx[i];
@@ -2451,13 +2455,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
+ txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
@@ -2785,7 +2790,7 @@ static int64_t nTimePostConnect = 0;
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
* corresponding to pindexNew, to bypass loading it again from disk.
*/
-bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::list<CTransaction> &txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int> > &txChanged)
+bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::list<CTransaction> &txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>> &txChanged)
{
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
@@ -2827,7 +2832,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
UpdateTip(pindexNew, chainparams);
for(unsigned int i=0; i < pblock->vtx.size(); i++)
- txChanged.push_back(std::make_tuple(pblock->vtx[i], pindexNew, i));
+ txChanged.emplace_back(pblock->vtx[i], pindexNew, i);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
@@ -2909,7 +2914,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::list<CTransaction>& txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int> >& txChanged)
+static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::list<CTransaction>& txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>>& txChanged)
{
AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -3008,17 +3013,20 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either NULL or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
-bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) {
+bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, CConnman* connman) {
CBlockIndex *pindexMostWork = NULL;
CBlockIndex *pindexNewTip = NULL;
+ std::vector<std::tuple<CTransaction,CBlockIndex*,int>> txChanged;
+ if (pblock)
+ txChanged.reserve(pblock->vtx.size());
do {
+ txChanged.clear();
boost::this_thread::interruption_point();
if (ShutdownRequested())
break;
const CBlockIndex *pindexFork;
std::list<CTransaction> txConflicted;
- std::vector<std::tuple<CTransaction,CBlockIndex*,int> > txChanged;
bool fInitialDownload;
int nNewHeight;
{
@@ -3048,6 +3056,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
+ if(connman)
+ connman->SetBestHeight(nNewHeight);
// throw all transactions though the signal-interface
// while _not_ holding the cs_main lock
@@ -3080,15 +3090,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
int nBlockEstimate = 0;
if (fCheckpointsEnabled)
nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes) {
+ if(connman) {
+ connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) {
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
pnode->PushBlockHash(hash);
}
}
- }
+ });
}
// Notify external listeners about the new tip.
if (!vHashes.empty()) {
@@ -3723,7 +3732,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
return true;
}
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman)
{
{
LOCK(cs_main);
@@ -3745,7 +3754,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
NotifyHeaderTip();
- if (!ActivateBestChain(state, chainparams, pblock))
+ if (!ActivateBestChain(state, chainparams, pblock, connman))
return error("%s: ActivateBestChain failed", __func__);
return true;
@@ -4653,12 +4662,12 @@ std::string GetWarnings(const std::string& strFor)
if (fLargeWorkForkFound)
{
strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.";
- strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.");
}
else if (fLargeWorkInvalidChainFound)
{
strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.";
- strGUI += strGUI.empty() ? "" : uiAlertSeperator + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
+ strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.");
}
if (strFor == "gui")
@@ -4717,9 +4726,45 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
return true;
}
-void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams)
+static void RelayTransaction(const CTransaction& tx, CConnman& connman)
+{
+ CInv inv(MSG_TX, tx.GetHash());
+ connman.ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
+}
+
+static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
+{
+ int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
+
+ // Relay to a limited number of other nodes
+ // Use deterministic randomness to send to the same nodes for 24 hours
+ // at a time so the addrKnowns of the chosen nodes prevent repeats
+ uint64_t hashAddr = addr.GetHash();
+ std::multimap<uint64_t, CNode*> mapMix;
+ const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
+
+ auto sortfunc = [&mapMix, &hasher](CNode* pnode) {
+ if (pnode->nVersion >= CADDR_TIME_VERSION) {
+ uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
+ mapMix.emplace(hashKey, pnode);
+ }
+ };
+
+ auto pushfunc = [&addr, &mapMix, &nRelayNodes] {
+ for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
+ mi->second->PushAddress(addr);
+ };
+
+ connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+}
+
+void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams, CConnman& connman)
{
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
+ unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
vector<CInv> vNotFound;
@@ -4727,7 +4772,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
while (it != pfrom->vRecvGetData.end()) {
// Don't bother if send buffer is too full to respond anyway
- if (pfrom->nSendSize >= SendBufferSize())
+ if (pfrom->nSendSize >= nMaxSendBufferSize)
break;
const CInv &inv = *it;
@@ -4759,7 +4804,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// disconnect node in case we have reached the outbound limit for serving historical blocks
// never disconnect whitelisted nodes
static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical
- if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
+ if (send && connman.OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted)
{
LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId());
@@ -4781,10 +4826,16 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
pfrom->PushMessage(NetMsgType::BLOCK, block);
else if (inv.type == MSG_FILTERED_BLOCK)
{
- LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
+ bool sendMerkleBlock = false;
+ CMerkleBlock merkleBlock;
{
- CMerkleBlock merkleBlock(block, *pfrom->pfilter);
+ LOCK(pfrom->cs_filter);
+ if (pfrom->pfilter) {
+ sendMerkleBlock = true;
+ merkleBlock = CMerkleBlock(block, *pfrom->pfilter);
+ }
+ }
+ if (sendMerkleBlock) {
pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock);
// CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see
// This avoids hurting performance by pointlessly requiring a round-trip
@@ -4877,8 +4928,10 @@ uint32_t GetFetchFlags(CNode* pfrom, CBlockIndex* pprev, const Consensus::Params
return nFetchFlags;
}
-bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams)
+bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman& connman)
{
+ unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
+
LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id);
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
{
@@ -4887,7 +4940,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- if (!(nLocalServices & NODE_BLOOM) &&
+ if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
(strCommand == NetMsgType::FILTERLOAD ||
strCommand == NetMsgType::FILTERADD ||
strCommand == NetMsgType::FILTERCLEAR))
@@ -4929,7 +4982,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->nServices = ServiceFlags(nServiceInt);
if (!pfrom->fInbound)
{
- addrman.SetServices(pfrom->addr, pfrom->nServices);
+ connman.SetServices(pfrom->addr, pfrom->nServices);
}
if (pfrom->nServicesExpected & ~pfrom->nServices)
{
@@ -4970,7 +5023,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// Disconnect if we connected to ourself
- if (nNonce == nLocalHostNonce && nNonce > 1)
+ if (pfrom->fInbound && !connman.CheckIncomingNonce(nNonce))
{
LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString());
pfrom->fDisconnect = true;
@@ -5010,7 +5063,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Advertise our address
if (fListen && !IsInitialBlockDownload())
{
- CAddress addr = GetLocalAddress(&pfrom->addr);
+ CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
if (addr.IsRoutable())
{
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
@@ -5023,18 +5076,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// Get recent addresses
- if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
+ if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000)
{
pfrom->PushMessage(NetMsgType::GETADDR);
pfrom->fGetAddr = true;
}
- addrman.Good(pfrom->addr);
- } else {
- if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
- {
- addrman.Add(addrFrom, addrFrom);
- addrman.Good(addrFrom);
- }
+ connman.MarkAddressGood(pfrom->addr);
}
pfrom->fSuccessfullyConnected = true;
@@ -5099,7 +5146,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> vAddr;
// Don't want addr from older versions unless seeding
- if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
+ if (pfrom->nVersion < CADDR_TIME_VERSION && connman.GetAddressCount() > 1000)
return true;
if (vAddr.size() > 1000)
{
@@ -5126,32 +5173,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
- {
- LOCK(cs_vNodes);
- // Use deterministic randomness to send to the same nodes for 24 hours
- // at a time so the addrKnowns of the chosen nodes prevent repeats
- static const uint64_t salt0 = GetRand(std::numeric_limits<uint64_t>::max());
- static const uint64_t salt1 = GetRand(std::numeric_limits<uint64_t>::max());
- uint64_t hashAddr = addr.GetHash();
- multimap<uint64_t, CNode*> mapMix;
- const CSipHasher hasher = CSipHasher(salt0, salt1).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- if (pnode->nVersion < CADDR_TIME_VERSION)
- continue;
- uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
- mapMix.insert(make_pair(hashKey, pnode));
- }
- int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
- for (multimap<uint64_t, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
- ((*mi).second)->PushAddress(addr);
- }
+ RelayAddress(addr, fReachable, connman);
}
// Do not store addresses outside our network
if (fReachable)
vAddrOk.push_back(addr);
}
- addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
+ connman.AddNewAddresses(vAddrOk, pfrom->addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom->fGetAddr = false;
if (pfrom->fOneShot)
@@ -5230,7 +5258,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
(!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
inv.type |= nFetchFlags;
- if (nodestate->fProvidesHeaderAndIDs && !(nLocalServices & NODE_WITNESS))
+ if (nodestate->fProvidesHeaderAndIDs && !(pfrom->GetLocalServices() & NODE_WITNESS))
vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash));
else
vToFetch.push_back(inv);
@@ -5253,7 +5281,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Track requests for our stuff
GetMainSignals().Inventory(inv.hash);
- if (pfrom->nSendSize > (SendBufferSize() * 2)) {
+ if (pfrom->nSendSize > (nMaxSendBufferSize * 2)) {
Misbehaving(pfrom->GetId(), 50);
return error("send buffer size() = %u", pfrom->nSendSize);
}
@@ -5282,7 +5310,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id);
pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end());
- ProcessGetData(pfrom, chainparams.GetConsensus());
+ ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
}
@@ -5395,7 +5423,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
- LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id);
+ LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->id);
for (; pindex; pindex = chainActive.Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
@@ -5439,7 +5467,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) {
mempool.check(pcoinsTip);
- RelayTransaction(tx);
+ RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i);
}
@@ -5476,7 +5504,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
continue;
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) {
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx);
+ RelayTransaction(orphanTx, connman);
for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
vWorkQueue.emplace_back(orphanHash, i);
}
@@ -5485,7 +5513,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (!fMissingInputs2)
{
int nDos = 0;
- if (stateDummy.IsInvalid(nDos) && nDos > 0 && (!state.CorruptionPossible() || State(fromPeer)->fHaveWitness))
+ if (stateDummy.IsInvalid(nDos) && nDos > 0)
{
// Punish peer that gave us an invalid orphan tx
Misbehaving(fromPeer, nDos);
@@ -5496,7 +5524,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash);
- if (!stateDummy.CorruptionPossible()) {
+ if (orphanTx.wit.IsNull() && !stateDummy.CorruptionPossible()) {
+ // Do not use rejection cache for witness transactions or
+ // witness-stripped transactions, as they can have been malleated.
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
assert(recentRejects);
recentRejects->insert(orphanHash);
}
@@ -5534,7 +5565,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
}
} else {
- if (!state.CorruptionPossible()) {
+ if (tx.wit.IsNull() && !state.CorruptionPossible()) {
+ // Do not use rejection cache for witness transactions or
+ // witness-stripped transactions, as they can have been malleated.
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
assert(recentRejects);
recentRejects->insert(tx.GetHash());
}
@@ -5551,7 +5585,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS = 0;
if (!state.IsInvalid(nDoS) || nDoS == 0) {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id);
- RelayTransaction(tx);
+ RelayTransaction(tx, connman);
} else {
LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state));
}
@@ -5566,9 +5600,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
- if (nDoS > 0 && (!state.CorruptionPossible() || State(pfrom->id)->fHaveWitness)) {
- // When a non-witness-supporting peer gives us a transaction that would
- // be accepted if witness validation was off, we can't blame them for it.
+ if (nDoS > 0) {
Misbehaving(pfrom->GetId(), nDoS);
}
}
@@ -5672,7 +5704,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
txn.blockhash = cmpctblock.header.GetHash();
CDataStream blockTxnMsg(SER_NETWORK, PROTOCOL_VERSION);
blockTxnMsg << txn;
- return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams);
+ return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman);
} else {
req.blockhash = pindex->GetBlockHash();
pfrom->PushMessage(NetMsgType::GETBLOCKTXN, req);
@@ -5693,7 +5725,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
headers.push_back(cmpctblock.header);
CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
vHeadersMsg << headers;
- return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams);
+ return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
}
}
@@ -5729,7 +5761,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->PushMessage(NetMsgType::GETDATA, invs);
} else {
CValidationState state;
- ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
+ ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, &connman);
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@@ -5874,10 +5906,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
}
if (vGetData.size() > 0) {
- if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(nLocalServices & NODE_WITNESS)) {
+ if (nodestate->fProvidesHeaderAndIDs && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN) && !(pfrom->GetLocalServices() & NODE_WITNESS)) {
// We seem to be rather well-synced, so it appears pfrom was the first to provide us
// with this block! Let's get them to announce using compact blocks in the future.
- MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom);
+ MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman);
// In any case, we want to download using a compact block, not a regular one
vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
}
@@ -5905,7 +5937,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Such an unrequested block may still be processed, subject to the
// conditions in AcceptBlock().
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
- ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
+ ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman);
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@@ -5941,7 +5973,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fSentAddr = true;
pfrom->vAddrToSend.clear();
- vector<CAddress> vAddr = addrman.GetAddr();
+ vector<CAddress> vAddr = connman.GetAddresses();
BOOST_FOREACH(const CAddress &addr, vAddr)
pfrom->PushAddress(addr);
}
@@ -5949,14 +5981,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
else if (strCommand == NetMsgType::MEMPOOL)
{
- if (!(nLocalServices & NODE_BLOOM) && !pfrom->fWhitelisted)
+ if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted)
{
LogPrint("net", "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
return true;
}
- if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted)
+ if (connman.OutboundTargetReached(false) && !pfrom->fWhitelisted)
{
LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
pfrom->fDisconnect = true;
@@ -6052,8 +6084,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CBloomFilter filter;
vRecv >> filter;
- LOCK(pfrom->cs_filter);
-
if (!filter.IsWithinSizeConstraints())
{
// There is no excuse for sending a too-large filter
@@ -6062,11 +6092,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
else
{
+ LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull();
+ pfrom->fRelayTxes = true;
}
- pfrom->fRelayTxes = true;
}
@@ -6077,20 +6108,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Nodes must NEVER send a data item > 520 bytes (the max size for a script data object,
// and thus, the maximum size any matched object can have) in a filteradd message
- if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE)
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
+ bool bad = false;
+ if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ bad = true;
} else {
LOCK(pfrom->cs_filter);
- if (pfrom->pfilter)
+ if (pfrom->pfilter) {
pfrom->pfilter->insert(vData);
- else
- {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), 100);
+ } else {
+ bad = true;
}
}
+ if (bad) {
+ LOCK(cs_main);
+ Misbehaving(pfrom->GetId(), 100);
+ }
}
@@ -6155,9 +6187,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
// requires LOCK(cs_vRecvMsg)
-bool ProcessMessages(CNode* pfrom)
+bool ProcessMessages(CNode* pfrom, CConnman& connman)
{
const CChainParams& chainparams = Params();
+ unsigned int nMaxSendBufferSize = connman.GetSendBufferSize();
//if (fDebug)
// LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size());
@@ -6172,7 +6205,7 @@ bool ProcessMessages(CNode* pfrom)
bool fOk = true;
if (!pfrom->vRecvGetData.empty())
- ProcessGetData(pfrom, chainparams.GetConsensus());
+ ProcessGetData(pfrom, chainparams.GetConsensus(), connman);
// this maintains the order of responses
if (!pfrom->vRecvGetData.empty()) return fOk;
@@ -6180,7 +6213,7 @@ bool ProcessMessages(CNode* pfrom)
std::deque<CNetMessage>::iterator it = pfrom->vRecvMsg.begin();
while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) {
// Don't bother if send buffer is too full to respond anyway
- if (pfrom->nSendSize >= SendBufferSize())
+ if (pfrom->nSendSize >= nMaxSendBufferSize)
break;
// get next message
@@ -6232,7 +6265,7 @@ bool ProcessMessages(CNode* pfrom)
bool fRet = false;
try
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams);
+ fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman);
boost::this_thread::interruption_point();
}
catch (const std::ios_base::failure& e)
@@ -6297,7 +6330,7 @@ public:
}
};
-bool SendMessages(CNode* pto)
+bool SendMessages(CNode* pto, CConnman& connman)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
@@ -6384,7 +6417,7 @@ bool SendMessages(CNode* pto)
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
else
{
- CNode::Ban(pto->addr, BanReasonNodeMisbehaving);
+ connman.Ban(pto->addr, BanReasonNodeMisbehaving);
}
}
state.fShouldBan = false;
@@ -6423,7 +6456,7 @@ bool SendMessages(CNode* pto)
// transactions become unconfirmed and spams other nodes.
if (!fReindex && !fImporting && !IsInitialBlockDownload())
{
- GetMainSignals().Broadcast(nTimeBestReceived);
+ GetMainSignals().Broadcast(nTimeBestReceived, &connman);
}
//
@@ -6713,15 +6746,13 @@ bool SendMessages(CNode* pto)
if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
vector<CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
- if (State(pto->GetId())->fHaveWitness || !IsWitnessEnabled(pindex->pprev, consensusParams)) {
- uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
- vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
- LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
- pindex->nHeight, pto->id);
- }
+ uint32_t nFetchFlags = GetFetchFlags(pto, pindex->pprev, consensusParams);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
+ LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
+ pindex->nHeight, pto->id);
}
if (state.nBlocksInFlight == 0 && staller != -1) {
if (State(staller)->nStallingSince == 0) {
diff --git a/src/main.h b/src/main.h
index e9106fccf7..2646d8f86b 100644
--- a/src/main.h
+++ b/src/main.h
@@ -34,11 +34,13 @@ class CBlockTreeDB;
class CBloomFilter;
class CChainParams;
class CInv;
+class CConnman;
class CScriptCheck;
class CTxMemPool;
class CValidationInterface;
class CValidationState;
+struct PrecomputedTransactionData;
struct CNodeStateStats;
struct LockPoints;
@@ -191,7 +193,7 @@ extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
-static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP;
+static const signed int DEFAULT_CHECKBLOCKS = 6;
static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
@@ -221,7 +223,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -239,13 +241,14 @@ bool LoadBlockIndex();
/** Unload database information */
void UnloadBlockIndex();
/** Process protocol messages received from a given node */
-bool ProcessMessages(CNode* pfrom);
+bool ProcessMessages(CNode* pfrom, CConnman& connman);
/**
* Send queued protocol messages to be sent to a give node.
*
* @param[in] pto The node which we are sending messages to.
+ * @param[in] connman The connection manager for that node.
*/
-bool SendMessages(CNode* pto);
+bool SendMessages(CNode* pto, CConnman& connman);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
@@ -261,7 +264,7 @@ std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */
-bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL);
+bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, CConnman* connman = NULL);
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
/**
@@ -347,7 +350,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
* instead of being performed inline.
*/
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
- unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL);
+ unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
@@ -421,12 +424,13 @@ private:
unsigned int nFlags;
bool cacheStore;
ScriptError error;
+ PrecomputedTransactionData *txdata;
public:
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
- CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
+ CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
- ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
@@ -438,6 +442,7 @@ public:
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
+ std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
diff --git a/src/net.cpp b/src/net.cpp
index 957388b8fd..cce06f2d64 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -61,63 +61,28 @@
#endif
#endif
-
-namespace {
- const int MAX_OUTBOUND_CONNECTIONS = 8;
- const int MAX_FEELER_CONNECTIONS = 1;
-
- struct ListenSocket {
- SOCKET socket;
- bool whitelisted;
-
- ListenSocket(SOCKET socket, bool whitelisted) : socket(socket), whitelisted(whitelisted) {}
- };
-}
-
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
-/** Services this node implementation cares about */
-ServiceFlags nRelevantServices = NODE_NETWORK;
-
+static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
//
// Global state variables
//
bool fDiscover = true;
bool fListen = true;
-ServiceFlags nLocalServices = NODE_NETWORK;
bool fRelayTxes = true;
CCriticalSection cs_mapLocalHost;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL;
-uint64_t nLocalHostNonce = 0;
-static std::vector<ListenSocket> vhListenSocket;
-CAddrMan addrman;
-int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
-bool fAddressesInitialized = false;
std::string strSubVersion;
-std::vector<CNode*> vNodes;
-CCriticalSection cs_vNodes;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
-static std::deque<std::string> vOneShots;
-CCriticalSection cs_vOneShots;
-
-std::vector<std::string> vAddedNodes;
-CCriticalSection cs_vAddedNodes;
-
-NodeId nLastNodeId = 0;
-CCriticalSection cs_nLastNodeId;
-
-static CSemaphore *semOutbound = NULL;
-boost::condition_variable messageHandlerCondition;
-
// Signals for message handling
static CNodeSignals g_signals;
CNodeSignals& GetNodeSignals() { return g_signals; }
-void AddOneShot(const std::string& strDest)
+void CConnman::AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
vOneShots.push_back(strDest);
@@ -178,7 +143,7 @@ static std::vector<CAddress> convertSeed6(const std::vector<SeedSpec6> &vSeedsIn
// Otherwise, return the unroutable 0.0.0.0 but filled in with
// the normal parameters, since the IP may be changed to a useful
// one by discovery.
-CAddress GetLocalAddress(const CNetAddr *paddrPeer)
+CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
{
CAddress ret(CService(CNetAddr(),GetListenPort()), NODE_NONE);
CService addr;
@@ -210,7 +175,7 @@ void AdvertiseLocal(CNode *pnode)
{
if (fListen && pnode->fSuccessfullyConnected)
{
- CAddress addrLocal = GetLocalAddress(&pnode->addr);
+ CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
@@ -321,23 +286,8 @@ bool IsReachable(const CNetAddr& addr)
return IsReachable(net);
}
-void AddressCurrentlyConnected(const CService& addr)
-{
- addrman.Connected(addr);
-}
-
-
-uint64_t CNode::nTotalBytesRecv = 0;
-uint64_t CNode::nTotalBytesSent = 0;
-CCriticalSection CNode::cs_totalBytesRecv;
-CCriticalSection CNode::cs_totalBytesSent;
-
-uint64_t CNode::nMaxOutboundLimit = 0;
-uint64_t CNode::nMaxOutboundTotalBytesSentInCycle = 0;
-uint64_t CNode::nMaxOutboundTimeframe = 60*60*24; //1 day
-uint64_t CNode::nMaxOutboundCycleStartTime = 0;
-CNode* FindNode(const CNetAddr& ip)
+CNode* CConnman::FindNode(const CNetAddr& ip)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -346,7 +296,7 @@ CNode* FindNode(const CNetAddr& ip)
return NULL;
}
-CNode* FindNode(const CSubNet& subNet)
+CNode* CConnman::FindNode(const CSubNet& subNet)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -355,7 +305,7 @@ CNode* FindNode(const CSubNet& subNet)
return NULL;
}
-CNode* FindNode(const std::string& addrName)
+CNode* CConnman::FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -364,7 +314,7 @@ CNode* FindNode(const std::string& addrName)
return NULL;
}
-CNode* FindNode(const CService& addr)
+CNode* CConnman::FindNode(const CService& addr)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -373,17 +323,17 @@ CNode* FindNode(const CService& addr)
return NULL;
}
-//TODO: This is used in only one place in main, and should be removed
-CNode* FindNode(const NodeId nodeid)
+bool CConnman::CheckIncomingNonce(uint64_t nonce)
{
LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->GetId() == nodeid)
- return (pnode);
- return NULL;
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce)
+ return false;
+ }
+ return true;
}
-CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
+CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure)
{
if (pszDest == NULL) {
if (IsLocal(addrConnect))
@@ -438,7 +388,8 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure
addrman.Attempt(addrConnect, fCountFailure);
// Add node
- CNode* pnode = new CNode(hSocket, addrConnect, pszDest ? pszDest : "", false);
+ CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), pszDest ? pszDest : "", false);
+ GetNodeSignals().InitializeNode(pnode->GetId(), pnode);
pnode->AddRef();
{
@@ -459,21 +410,21 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure
return NULL;
}
-static void DumpBanlist()
+void CConnman::DumpBanlist()
{
- CNode::SweepBanned(); // clean unused entries (if bantime has expired)
+ SweepBanned(); // clean unused entries (if bantime has expired)
- if (!CNode::BannedSetIsDirty())
+ if (!BannedSetIsDirty())
return;
int64_t nStart = GetTimeMillis();
CBanDB bandb;
banmap_t banmap;
- CNode::SetBannedSetDirty(false);
- CNode::GetBanned(banmap);
+ SetBannedSetDirty(false);
+ GetBanned(banmap);
if (!bandb.Write(banmap))
- CNode::SetBannedSetDirty(true);
+ SetBannedSetDirty(true);
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
@@ -496,29 +447,22 @@ void CNode::CloseSocketDisconnect()
void CNode::PushVersion()
{
- int nBestHeight = GetNodeSignals().GetHeight().get_value_or(0);
-
int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime());
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService(), addr.nServices));
- CAddress addrMe = GetLocalAddress(&addr);
- GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+ CAddress addrMe = CAddress(CService(), nLocalServices);
if (fLogIPs)
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), addrYou.ToString(), id);
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id);
else
- LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
+ LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), id);
PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, strSubVersion, nBestHeight, ::fRelayTxes);
+ nLocalHostNonce, strSubVersion, nMyStartingHeight, ::fRelayTxes);
}
-banmap_t CNode::setBanned;
-CCriticalSection CNode::cs_setBanned;
-bool CNode::setBannedIsDirty;
-
-void CNode::ClearBanned()
+void CConnman::ClearBanned()
{
{
LOCK(cs_setBanned);
@@ -526,10 +470,11 @@ void CNode::ClearBanned()
setBannedIsDirty = true;
}
DumpBanlist(); //store banlist to disk
- uiInterface.BannedListChanged();
+ if(clientInterface)
+ clientInterface->BannedListChanged();
}
-bool CNode::IsBanned(CNetAddr ip)
+bool CConnman::IsBanned(CNetAddr ip)
{
bool fResult = false;
{
@@ -546,7 +491,7 @@ bool CNode::IsBanned(CNetAddr ip)
return fResult;
}
-bool CNode::IsBanned(CSubNet subnet)
+bool CConnman::IsBanned(CSubNet subnet)
{
bool fResult = false;
{
@@ -562,12 +507,12 @@ bool CNode::IsBanned(CSubNet subnet)
return fResult;
}
-void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+void CConnman::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
CSubNet subNet(addr);
Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
}
-void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+void CConnman::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
CBanEntry banEntry(GetTime());
banEntry.banReason = banReason;
if (bantimeoffset <= 0)
@@ -586,7 +531,8 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
else
return;
}
- uiInterface.BannedListChanged();
+ if(clientInterface)
+ clientInterface->BannedListChanged();
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
@@ -598,37 +544,38 @@ void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t banti
DumpBanlist(); //store banlist to disk immediately if user requested ban
}
-bool CNode::Unban(const CNetAddr &addr) {
+bool CConnman::Unban(const CNetAddr &addr) {
CSubNet subNet(addr);
return Unban(subNet);
}
-bool CNode::Unban(const CSubNet &subNet) {
+bool CConnman::Unban(const CSubNet &subNet) {
{
LOCK(cs_setBanned);
if (!setBanned.erase(subNet))
return false;
setBannedIsDirty = true;
}
- uiInterface.BannedListChanged();
+ if(clientInterface)
+ clientInterface->BannedListChanged();
DumpBanlist(); //store banlist to disk immediately
return true;
}
-void CNode::GetBanned(banmap_t &banMap)
+void CConnman::GetBanned(banmap_t &banMap)
{
LOCK(cs_setBanned);
banMap = setBanned; //create a thread safe copy
}
-void CNode::SetBanned(const banmap_t &banMap)
+void CConnman::SetBanned(const banmap_t &banMap)
{
LOCK(cs_setBanned);
setBanned = banMap;
setBannedIsDirty = true;
}
-void CNode::SweepBanned()
+void CConnman::SweepBanned()
{
int64_t now = GetTime();
@@ -649,23 +596,20 @@ void CNode::SweepBanned()
}
}
-bool CNode::BannedSetIsDirty()
+bool CConnman::BannedSetIsDirty()
{
LOCK(cs_setBanned);
return setBannedIsDirty;
}
-void CNode::SetBannedSetDirty(bool dirty)
+void CConnman::SetBannedSetDirty(bool dirty)
{
LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
setBannedIsDirty = dirty;
}
-std::vector<CSubNet> CNode::vWhitelistedRange;
-CCriticalSection CNode::cs_vWhitelistedRange;
-
-bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
+bool CConnman::IsWhitelistedRange(const CNetAddr &addr) {
LOCK(cs_vWhitelistedRange);
BOOST_FOREACH(const CSubNet& subnet, vWhitelistedRange) {
if (subnet.Match(addr))
@@ -674,7 +618,7 @@ bool CNode::IsWhitelistedRange(const CNetAddr &addr) {
return false;
}
-void CNode::AddWhitelistedRange(const CSubNet &subnet) {
+void CConnman::AddWhitelistedRange(const CSubNet &subnet) {
LOCK(cs_vWhitelistedRange);
vWhitelistedRange.push_back(subnet);
}
@@ -723,8 +667,9 @@ void CNode::copyStats(CNodeStats &stats)
#undef X
// requires LOCK(cs_vRecvMsg)
-bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
+bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete)
{
+ complete = false;
while (nBytes > 0) {
// get current incomplete message, or create a new one
@@ -763,7 +708,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
msg.nTime = GetTimeMicros();
- messageHandlerCondition.notify_one();
+ complete = true;
}
}
@@ -826,9 +771,10 @@ int CNetMessage::readData(const char *pch, unsigned int nBytes)
// requires LOCK(cs_vSend)
-void SocketSendData(CNode *pnode)
+size_t SocketSendData(CNode *pnode)
{
std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin();
+ size_t nSentSize = 0;
while (it != pnode->vSendMsg.end()) {
const CSerializeData &data = *it;
@@ -838,7 +784,7 @@ void SocketSendData(CNode *pnode)
pnode->nLastSend = GetTime();
pnode->nSendBytes += nBytes;
pnode->nSendOffset += nBytes;
- pnode->RecordBytesSent(nBytes);
+ nSentSize += nBytes;
if (pnode->nSendOffset == data.size()) {
pnode->nSendOffset = 0;
pnode->nSendSize -= data.size();
@@ -867,10 +813,9 @@ void SocketSendData(CNode *pnode)
assert(pnode->nSendSize == 0);
}
pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
+ return nSentSize;
}
-static std::list<CNode*> vNodesDisconnected;
-
struct NodeEvictionCandidate
{
NodeId id;
@@ -924,7 +869,8 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
* to forge. In order to partition a node the attacker must be
* simultaneously better at all of them than honest peers.
*/
-static bool AttemptToEvictConnection() {
+bool CConnman::AttemptToEvictConnection()
+{
std::vector<NodeEvictionCandidate> vEvictionCandidates;
{
LOCK(cs_vNodes);
@@ -1015,20 +961,20 @@ static bool AttemptToEvictConnection() {
return false;
}
-static void AcceptConnection(const ListenSocket& hListenSocket) {
+void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
struct sockaddr_storage sockaddr;
socklen_t len = sizeof(sockaddr);
SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
CAddress addr;
int nInbound = 0;
- int nMaxInbound = nMaxConnections - (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS);
+ int nMaxInbound = nMaxConnections - (nMaxOutbound + nMaxFeeler);
assert(nMaxInbound > 0);
if (hSocket != INVALID_SOCKET)
if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
LogPrintf("Warning: Unknown socket family\n");
- bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
+ bool whitelisted = hListenSocket.whitelisted || IsWhitelistedRange(addr);
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
@@ -1060,7 +1006,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (void*)&set, sizeof(int));
#endif
- if (CNode::IsBanned(addr) && !whitelisted)
+ if (IsBanned(addr) && !whitelisted)
{
LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
CloseSocket(hSocket);
@@ -1077,7 +1023,8 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
}
}
- CNode* pnode = new CNode(hSocket, addr, "", true);
+ CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), "", true);
+ GetNodeSignals().InitializeNode(pnode->GetId(), pnode);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
@@ -1089,7 +1036,7 @@ static void AcceptConnection(const ListenSocket& hListenSocket) {
}
}
-void ThreadSocketHandler()
+void CConnman::ThreadSocketHandler()
{
unsigned int nPrevNodeCount = 0;
while (true)
@@ -1147,14 +1094,15 @@ void ThreadSocketHandler()
if (fDelete)
{
vNodesDisconnected.remove(pnode);
- delete pnode;
+ DeleteNode(pnode);
}
}
}
}
if(vNodes.size() != nPrevNodeCount) {
nPrevNodeCount = vNodes.size();
- uiInterface.NotifyNumConnectionsChanged(nPrevNodeCount);
+ if(clientInterface)
+ clientInterface->NotifyNumConnectionsChanged(nPrevNodeCount);
}
//
@@ -1206,16 +1154,22 @@ void ThreadSocketHandler()
// * We process a message in the buffer (message handler thread).
{
TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend && !pnode->vSendMsg.empty()) {
- FD_SET(pnode->hSocket, &fdsetSend);
- continue;
+ if (lockSend) {
+ if (pnode->nOptimisticBytesWritten) {
+ RecordBytesSent(pnode->nOptimisticBytesWritten);
+ pnode->nOptimisticBytesWritten = 0;
+ }
+ if (!pnode->vSendMsg.empty()) {
+ FD_SET(pnode->hSocket, &fdsetSend);
+ continue;
+ }
}
}
{
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv && (
pnode->vRecvMsg.empty() || !pnode->vRecvMsg.front().complete() ||
- pnode->GetTotalRecvSize() <= ReceiveFloodSize()))
+ pnode->GetTotalRecvSize() <= GetReceiveFloodSize()))
FD_SET(pnode->hSocket, &fdsetRecv);
}
}
@@ -1280,11 +1234,14 @@ void ThreadSocketHandler()
int nBytes = recv(pnode->hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);
if (nBytes > 0)
{
- if (!pnode->ReceiveMsgBytes(pchBuf, nBytes))
+ bool notify = false;
+ if (!pnode->ReceiveMsgBytes(pchBuf, nBytes, notify))
pnode->CloseSocketDisconnect();
+ if(notify)
+ messageHandlerCondition.notify_one();
pnode->nLastRecv = GetTime();
pnode->nRecvBytes += nBytes;
- pnode->RecordBytesRecv(nBytes);
+ RecordBytesRecv(nBytes);
}
else if (nBytes == 0)
{
@@ -1316,8 +1273,11 @@ void ThreadSocketHandler()
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{
TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend)
- SocketSendData(pnode);
+ if (lockSend) {
+ size_t nBytes = SocketSendData(pnode);
+ if (nBytes)
+ RecordBytesSent(nBytes);
+ }
}
//
@@ -1497,7 +1457,7 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe
}
-void ThreadDNSAddressSeed()
+void CConnman::ThreadDNSAddressSeed()
{
// goal: only query DNS seeds if address need is acute
if ((addrman.size() > 0) &&
@@ -1560,7 +1520,7 @@ void ThreadDNSAddressSeed()
-void DumpAddresses()
+void CConnman::DumpAddresses()
{
int64_t nStart = GetTimeMillis();
@@ -1571,13 +1531,13 @@ void DumpAddresses()
addrman.size(), GetTimeMillis() - nStart);
}
-void DumpData()
+void CConnman::DumpData()
{
DumpAddresses();
DumpBanlist();
}
-void static ProcessOneShot()
+void CConnman::ProcessOneShot()
{
std::string strDest;
{
@@ -1595,7 +1555,7 @@ void static ProcessOneShot()
}
}
-void ThreadOpenConnections()
+void CConnman::ThreadOpenConnections()
{
// Connect to specific addresses
if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0)
@@ -1660,7 +1620,7 @@ void ThreadOpenConnections()
}
}
}
- assert(nOutbound <= (MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS));
+ assert(nOutbound <= (nMaxOutbound + nMaxFeeler));
// Feeler Connections
//
@@ -1675,7 +1635,7 @@ void ThreadOpenConnections()
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false;
- if (nOutbound >= MAX_OUTBOUND_CONNECTIONS) {
+ if (nOutbound >= nMaxOutbound) {
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
if (nTime > nNextFeeler) {
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
@@ -1739,7 +1699,7 @@ void ThreadOpenConnections()
}
}
-std::vector<AddedNodeInfo> GetAddedNodeInfo()
+std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
{
std::vector<AddedNodeInfo> ret;
@@ -1791,7 +1751,7 @@ std::vector<AddedNodeInfo> GetAddedNodeInfo()
return ret;
}
-void ThreadOpenAddedConnections()
+void CConnman::ThreadOpenAddedConnections()
{
{
LOCK(cs_vAddedNodes);
@@ -1817,7 +1777,7 @@ void ThreadOpenAddedConnections()
}
// if successful, this moves the passed grant to the constructed node
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
+bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler)
{
//
// Initiate outbound network connection
@@ -1825,7 +1785,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem
boost::this_thread::interruption_point();
if (!pszDest) {
if (IsLocal(addrConnect) ||
- FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
+ FindNode((CNetAddr)addrConnect) || IsBanned(addrConnect) ||
FindNode(addrConnect.ToStringIPPort()))
return false;
} else if (FindNode(std::string(pszDest)))
@@ -1848,7 +1808,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSem
}
-void ThreadMessageHandler()
+void CConnman::ThreadMessageHandler()
{
boost::mutex condition_mutex;
boost::unique_lock<boost::mutex> lock(condition_mutex);
@@ -1876,10 +1836,10 @@ void ThreadMessageHandler()
TRY_LOCK(pnode->cs_vRecvMsg, lockRecv);
if (lockRecv)
{
- if (!GetNodeSignals().ProcessMessages(pnode))
+ if (!GetNodeSignals().ProcessMessages(pnode, *this))
pnode->CloseSocketDisconnect();
- if (pnode->nSendSize < SendBufferSize())
+ if (pnode->nSendSize < GetSendBufferSize())
{
if (!pnode->vRecvGetData.empty() || (!pnode->vRecvMsg.empty() && pnode->vRecvMsg[0].complete()))
{
@@ -1894,7 +1854,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- GetNodeSignals().SendMessages(pnode);
+ GetNodeSignals().SendMessages(pnode, *this);
}
boost::this_thread::interruption_point();
}
@@ -1915,7 +1875,7 @@ void ThreadMessageHandler()
-bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
+bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, bool fWhitelisted)
{
strError = "";
int nOne = 1;
@@ -2013,7 +1973,7 @@ bool BindListenPort(const CService &addrBind, std::string& strError, bool fWhite
return true;
}
-void static Discover(boost::thread_group& threadGroup)
+void Discover(boost::thread_group& threadGroup)
{
if (!fDiscover)
return;
@@ -2064,9 +2024,49 @@ void static Discover(boost::thread_group& threadGroup)
#endif
}
-void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
+CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSeed1(nSeed1In)
+{
+ setBannedIsDirty = false;
+ fAddressesInitialized = false;
+ nLastNodeId = 0;
+ nSendBufferMaxSize = 0;
+ nReceiveFloodSize = 0;
+ semOutbound = NULL;
+ nMaxConnections = 0;
+ nMaxOutbound = 0;
+ nBestHeight = 0;
+ clientInterface = NULL;
+}
+
+NodeId CConnman::GetNewNodeId()
{
- uiInterface.InitMessage(_("Loading addresses..."));
+ return nLastNodeId.fetch_add(1, std::memory_order_relaxed);
+}
+
+bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options connOptions)
+{
+ nTotalBytesRecv = 0;
+ nTotalBytesSent = 0;
+ nMaxOutboundTotalBytesSentInCycle = 0;
+ nMaxOutboundCycleStartTime = 0;
+
+ nRelevantServices = connOptions.nRelevantServices;
+ nLocalServices = connOptions.nLocalServices;
+ nMaxConnections = connOptions.nMaxConnections;
+ nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections);
+ nMaxFeeler = connOptions.nMaxFeeler;
+
+ nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
+ nReceiveFloodSize = connOptions.nSendBufferMaxSize;
+
+ nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ nMaxOutboundTimeframe = connOptions.nMaxOutboundTimeframe;
+
+ SetBestHeight(connOptions.nBestHeight);
+
+ clientInterface = connOptions.uiInterface;
+ if (clientInterface)
+ clientInterface->InitMessage(_("Loading addresses..."));
// Load addresses from peers.dat
int64_t nStart = GetTimeMillis();
{
@@ -2079,22 +2079,22 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
DumpAddresses();
}
}
-
- uiInterface.InitMessage(_("Loading banlist..."));
+ if (clientInterface)
+ clientInterface->InitMessage(_("Loading banlist..."));
// Load addresses from banlist.dat
nStart = GetTimeMillis();
CBanDB bandb;
banmap_t banmap;
if (bandb.Read(banmap)) {
- CNode::SetBanned(banmap); // thread save setter
- CNode::SetBannedSetDirty(false); // no need to write down, just read data
- CNode::SweepBanned(); // sweep out unused entries
+ SetBanned(banmap); // thread save setter
+ SetBannedSetDirty(false); // no need to write down, just read data
+ SweepBanned(); // sweep out unused entries
LogPrint("net", "Loaded %d banned node ips/subnets from banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
} else {
LogPrintf("Invalid or missing banlist.dat; recreating\n");
- CNode::SetBannedSetDirty(true); // force write
+ SetBannedSetDirty(true); // force write
DumpBanlist();
}
@@ -2104,18 +2104,16 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (semOutbound == NULL) {
// initialize semaphore
- int nMaxOutbound = std::min((MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS), nMaxConnections);
- semOutbound = new CSemaphore(nMaxOutbound);
+ semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
}
if (pnodeLocalHost == NULL) {
CNetAddr local;
LookupHost("127.0.0.1", local, false);
- pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices));
+ pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0);
+ GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost);
}
- Discover(threadGroup);
-
//
// Start threads
//
@@ -2123,33 +2121,46 @@ void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
if (!GetBoolArg("-dnsseed", true))
LogPrintf("DNS seeding disabled\n");
else
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "dnsseed", &ThreadDNSAddressSeed));
-
- // Map ports with UPnP
- MapPort(GetBoolArg("-upnp", DEFAULT_UPNP));
+ threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "dnsseed", boost::function<void()>(boost::bind(&CConnman::ThreadDNSAddressSeed, this))));
// Send and receive from sockets, accept connections
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "net", &ThreadSocketHandler));
+ threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "net", boost::function<void()>(boost::bind(&CConnman::ThreadSocketHandler, this))));
// Initiate outbound connections from -addnode
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "addcon", &ThreadOpenAddedConnections));
+ threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "addcon", boost::function<void()>(boost::bind(&CConnman::ThreadOpenAddedConnections, this))));
// Initiate outbound connections
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "opencon", &ThreadOpenConnections));
+ threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "opencon", boost::function<void()>(boost::bind(&CConnman::ThreadOpenConnections, this))));
// Process messages
- threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
+ threadGroup.create_thread(boost::bind(&TraceThread<boost::function<void()> >, "msghand", boost::function<void()>(boost::bind(&CConnman::ThreadMessageHandler, this))));
// Dump network addresses
- scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL);
+ scheduler.scheduleEvery(boost::bind(&CConnman::DumpData, this), DUMP_ADDRESSES_INTERVAL);
+
+ return true;
+}
+
+class CNetCleanup
+{
+public:
+ CNetCleanup() {}
+
+ ~CNetCleanup()
+ {
+#ifdef WIN32
+ // Shutdown Windows Sockets
+ WSACleanup();
+#endif
+ }
}
+instance_of_cnetcleanup;
-bool StopNode()
+void CConnman::Stop()
{
- LogPrintf("StopNode()\n");
- MapPort(false);
+ LogPrintf("%s\n",__func__);
if (semOutbound)
- for (int i=0; i<(MAX_OUTBOUND_CONNECTIONS + MAX_FEELER_CONNECTIONS); i++)
+ for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++)
semOutbound->post();
if (fAddressesInitialized)
@@ -2158,48 +2169,167 @@ bool StopNode()
fAddressesInitialized = false;
}
+ // Close sockets
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->hSocket != INVALID_SOCKET)
+ CloseSocket(pnode->hSocket);
+ BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
+ if (hListenSocket.socket != INVALID_SOCKET)
+ if (!CloseSocket(hListenSocket.socket))
+ LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
+
+ // clean up some globals (to help leak detection)
+ BOOST_FOREACH(CNode *pnode, vNodes) {
+ DeleteNode(pnode);
+ }
+ BOOST_FOREACH(CNode *pnode, vNodesDisconnected) {
+ DeleteNode(pnode);
+ }
+ vNodes.clear();
+ vNodesDisconnected.clear();
+ vhListenSocket.clear();
+ delete semOutbound;
+ semOutbound = NULL;
+ if(pnodeLocalHost)
+ DeleteNode(pnodeLocalHost);
+ pnodeLocalHost = NULL;
+}
+
+void CConnman::DeleteNode(CNode* pnode)
+{
+ assert(pnode);
+ bool fUpdateConnectionTime = false;
+ GetNodeSignals().FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
+ if(fUpdateConnectionTime)
+ addrman.Connected(pnode->addr);
+ delete pnode;
+}
+
+CConnman::~CConnman()
+{
+ Stop();
+}
+
+size_t CConnman::GetAddressCount() const
+{
+ return addrman.size();
+}
+
+void CConnman::SetServices(const CService &addr, ServiceFlags nServices)
+{
+ addrman.SetServices(addr, nServices);
+}
+
+void CConnman::MarkAddressGood(const CAddress& addr)
+{
+ addrman.Good(addr);
+}
+
+void CConnman::AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty)
+{
+ addrman.Add(addr, addrFrom, nTimePenalty);
+}
+
+void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
+{
+ addrman.Add(vAddr, addrFrom, nTimePenalty);
+}
+
+std::vector<CAddress> CConnman::GetAddresses()
+{
+ return addrman.GetAddr();
+}
+
+bool CConnman::AddNode(const std::string& strNode)
+{
+ LOCK(cs_vAddedNodes);
+ for(std::vector<std::string>::const_iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
+ if (strNode == *it)
+ return false;
+ }
+
+ vAddedNodes.push_back(strNode);
return true;
}
-class CNetCleanup
+bool CConnman::RemoveAddedNode(const std::string& strNode)
{
-public:
- CNetCleanup() {}
+ LOCK(cs_vAddedNodes);
+ for(std::vector<std::string>::iterator it = vAddedNodes.begin(); it != vAddedNodes.end(); ++it) {
+ if (strNode == *it) {
+ vAddedNodes.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
- ~CNetCleanup()
- {
- // Close sockets
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->hSocket != INVALID_SOCKET)
- CloseSocket(pnode->hSocket);
- BOOST_FOREACH(ListenSocket& hListenSocket, vhListenSocket)
- if (hListenSocket.socket != INVALID_SOCKET)
- if (!CloseSocket(hListenSocket.socket))
- LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError()));
-
- // clean up some globals (to help leak detection)
- BOOST_FOREACH(CNode *pnode, vNodes)
- delete pnode;
- BOOST_FOREACH(CNode *pnode, vNodesDisconnected)
- delete pnode;
- vNodes.clear();
- vNodesDisconnected.clear();
- vhListenSocket.clear();
- delete semOutbound;
- semOutbound = NULL;
- delete pnodeLocalHost;
- pnodeLocalHost = NULL;
+size_t CConnman::GetNodeCount(NumConnections flags)
+{
+ LOCK(cs_vNodes);
+ if (flags == CConnman::CONNECTIONS_ALL) // Shortcut if we want total
+ return vNodes.size();
-#ifdef WIN32
- // Shutdown Windows Sockets
- WSACleanup();
-#endif
+ int nNum = 0;
+ for(std::vector<CNode*>::const_iterator it = vNodes.begin(); it != vNodes.end(); ++it)
+ if (flags & ((*it)->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
+ nNum++;
+
+ return nNum;
+}
+
+void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats)
+{
+ vstats.clear();
+ LOCK(cs_vNodes);
+ vstats.reserve(vNodes.size());
+ for(std::vector<CNode*>::iterator it = vNodes.begin(); it != vNodes.end(); ++it) {
+ CNode* pnode = *it;
+ CNodeStats stats;
+ pnode->copyStats(stats);
+ vstats.push_back(stats);
}
}
-instance_of_cnetcleanup;
+bool CConnman::DisconnectAddress(const CNetAddr& netAddr)
+{
+ if (CNode* pnode = FindNode(netAddr)) {
+ pnode->fDisconnect = true;
+ return true;
+ }
+ return false;
+}
+
+bool CConnman::DisconnectSubnet(const CSubNet& subNet)
+{
+ if (CNode* pnode = FindNode(subNet)) {
+ pnode->fDisconnect = true;
+ return true;
+ }
+ return false;
+}
+
+bool CConnman::DisconnectNode(const std::string& strNode)
+{
+ if (CNode* pnode = FindNode(strNode)) {
+ pnode->fDisconnect = true;
+ return true;
+ }
+ return false;
+}
+bool CConnman::DisconnectNode(NodeId id)
+{
+ LOCK(cs_vNodes);
+ for(CNode* pnode : vNodes) {
+ if (id == pnode->id) {
+ pnode->fDisconnect = true;
+ return true;
+ }
+ }
+ return false;
+}
-void RelayTransaction(const CTransaction& tx)
+void CConnman::RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
LOCK(cs_vNodes);
@@ -2209,13 +2339,13 @@ void RelayTransaction(const CTransaction& tx)
}
}
-void CNode::RecordBytesRecv(uint64_t bytes)
+void CConnman::RecordBytesRecv(uint64_t bytes)
{
LOCK(cs_totalBytesRecv);
nTotalBytesRecv += bytes;
}
-void CNode::RecordBytesSent(uint64_t bytes)
+void CConnman::RecordBytesSent(uint64_t bytes)
{
LOCK(cs_totalBytesSent);
nTotalBytesSent += bytes;
@@ -2232,29 +2362,25 @@ void CNode::RecordBytesSent(uint64_t bytes)
nMaxOutboundTotalBytesSentInCycle += bytes;
}
-void CNode::SetMaxOutboundTarget(uint64_t limit)
+void CConnman::SetMaxOutboundTarget(uint64_t limit)
{
LOCK(cs_totalBytesSent);
- uint64_t recommendedMinimum = (nMaxOutboundTimeframe / 600) * MAX_BLOCK_SERIALIZED_SIZE;
nMaxOutboundLimit = limit;
-
- if (limit > 0 && limit < recommendedMinimum)
- LogPrintf("Max outbound target is very small (%s bytes) and will be overshot. Recommended minimum is %s bytes.\n", nMaxOutboundLimit, recommendedMinimum);
}
-uint64_t CNode::GetMaxOutboundTarget()
+uint64_t CConnman::GetMaxOutboundTarget()
{
LOCK(cs_totalBytesSent);
return nMaxOutboundLimit;
}
-uint64_t CNode::GetMaxOutboundTimeframe()
+uint64_t CConnman::GetMaxOutboundTimeframe()
{
LOCK(cs_totalBytesSent);
return nMaxOutboundTimeframe;
}
-uint64_t CNode::GetMaxOutboundTimeLeftInCycle()
+uint64_t CConnman::GetMaxOutboundTimeLeftInCycle()
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@@ -2268,7 +2394,7 @@ uint64_t CNode::GetMaxOutboundTimeLeftInCycle()
return (cycleEndTime < now) ? 0 : cycleEndTime - GetTime();
}
-void CNode::SetMaxOutboundTimeframe(uint64_t timeframe)
+void CConnman::SetMaxOutboundTimeframe(uint64_t timeframe)
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundTimeframe != timeframe)
@@ -2280,7 +2406,7 @@ void CNode::SetMaxOutboundTimeframe(uint64_t timeframe)
nMaxOutboundTimeframe = timeframe;
}
-bool CNode::OutboundTargetReached(bool historicalBlockServingLimit)
+bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit)
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@@ -2300,7 +2426,7 @@ bool CNode::OutboundTargetReached(bool historicalBlockServingLimit)
return false;
}
-uint64_t CNode::GetOutboundTargetBytesLeft()
+uint64_t CConnman::GetOutboundTargetBytesLeft()
{
LOCK(cs_totalBytesSent);
if (nMaxOutboundLimit == 0)
@@ -2309,18 +2435,33 @@ uint64_t CNode::GetOutboundTargetBytesLeft()
return (nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit) ? 0 : nMaxOutboundLimit - nMaxOutboundTotalBytesSentInCycle;
}
-uint64_t CNode::GetTotalBytesRecv()
+uint64_t CConnman::GetTotalBytesRecv()
{
LOCK(cs_totalBytesRecv);
return nTotalBytesRecv;
}
-uint64_t CNode::GetTotalBytesSent()
+uint64_t CConnman::GetTotalBytesSent()
{
LOCK(cs_totalBytesSent);
return nTotalBytesSent;
}
+ServiceFlags CConnman::GetLocalServices() const
+{
+ return nLocalServices;
+}
+
+void CConnman::SetBestHeight(int height)
+{
+ nBestHeight.store(height, std::memory_order_release);
+}
+
+int CConnman::GetBestHeight() const
+{
+ return nBestHeight.load(std::memory_order_acquire);
+}
+
void CNode::Fuzz(int nChance)
{
if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake
@@ -2356,121 +2497,13 @@ void CNode::Fuzz(int nChance)
Fuzz(2);
}
-//
-// CAddrDB
-//
-
-CAddrDB::CAddrDB()
-{
- pathAddr = GetDataDir() / "peers.dat";
-}
-
-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;
-
- // open temp output file, and associate with CAutoFile
- boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fopen(pathTmp.string().c_str(), "wb");
- CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (fileout.IsNull())
- return error("%s: Failed to open file %s", __func__, pathTmp.string());
-
- // 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();
-
- // replace existing peers.dat, if any, with new peers.dat.XXXX
- if (!RenameOver(pathTmp, pathAddr))
- return error("%s: Rename-into-place failed", __func__);
-
- return true;
-}
-
-bool CAddrDB::Read(CAddrMan& addr)
-{
- // open input file, and associate with CAutoFile
- FILE *file = fopen(pathAddr.string().c_str(), "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 = boost::filesystem::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);
-}
-
-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
- addr.Clear();
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
- }
-
- return true;
-}
-
-unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); }
-unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); }
+unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
+unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
-CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
+CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addr(addrIn),
- nKeyedNetGroup(CalculateKeyedNetGroup(addrIn)),
+ nKeyedNetGroup(nKeyedNetGroupIn),
addrKnown(5000, 0.001),
filterInventoryKnown(50000, 0.000001)
{
@@ -2520,16 +2553,17 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
minFeeFilter = 0;
lastSentFeeFilter = 0;
nextSendTimeFeeFilter = 0;
+ id = idIn;
+ nOptimisticBytesWritten = 0;
+ nLocalServices = nLocalServicesIn;
+
+ GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
+ nMyStartingHeight = nMyStartingHeightIn;
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
- {
- LOCK(cs_nLastNodeId);
- id = nLastNodeId++;
- }
-
if (fLogIPs)
LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
else
@@ -2538,8 +2572,6 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
// Be shy and don't send version until we hear
if (hSocket != INVALID_SOCKET && !fInbound)
PushVersion();
-
- GetNodeSignals().InitializeNode(GetId(), this);
}
CNode::~CNode()
@@ -2548,8 +2580,6 @@ CNode::~CNode()
if (pfilter)
delete pfilter;
-
- GetNodeSignals().FinalizeNode(GetId());
}
void CNode::AskFor(const CInv& inv)
@@ -2644,122 +2674,36 @@ void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend)
// If write queue empty, attempt "optimistic write"
if (it == vSendMsg.begin())
- SocketSendData(this);
+ nOptimisticBytesWritten += SocketSendData(this);
LEAVE_CRITICAL_SECTION(cs_vSend);
}
-//
-// CBanDB
-//
-
-CBanDB::CBanDB()
+bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func)
{
- pathBanlist = GetDataDir() / "banlist.dat";
-}
-
-bool CBanDB::Write(const banmap_t& banSet)
-{
- // 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;
-
- // open temp output file, and associate with CAutoFile
- boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
- FILE *file = fopen(pathTmp.string().c_str(), "wb");
- CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- 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());
- }
- FileCommit(fileout.Get());
- fileout.fclose();
-
- // replace existing banlist.dat, if any, with new banlist.dat.XXXX
- if (!RenameOver(pathTmp, pathBanlist))
- return error("%s: Rename-into-place failed", __func__);
-
- return true;
-}
-
-bool CBanDB::Read(banmap_t& banSet)
-{
- // open input file, and associate with CAutoFile
- FILE *file = fopen(pathBanlist.string().c_str(), "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 = boost::filesystem::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 {
- // de-serialize file header (network specific magic number) and ..
- ssBanlist >> 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
- ssBanlist >> banSet;
- }
- catch (const std::exception& e) {
- return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ CNode* found = nullptr;
+ LOCK(cs_vNodes);
+ for (auto&& pnode : vNodes) {
+ if(pnode->id == id) {
+ found = pnode;
+ break;
+ }
}
-
- return true;
+ return found != nullptr && func(found);
}
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) {
return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5);
}
-/* static */ uint64_t CNode::CalculateKeyedNetGroup(const CAddress& ad)
+CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id)
{
- static const uint64_t k0 = GetRand(std::numeric_limits<uint64_t>::max());
- static const uint64_t k1 = GetRand(std::numeric_limits<uint64_t>::max());
+ return CSipHasher(nSeed0, nSeed1).Write(id);
+}
+uint64_t CConnman::CalculateKeyedNetGroup(const CAddress& ad)
+{
std::vector<unsigned char> vchNetGroup(ad.GetGroup());
- return CSipHasher(k0, k1).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
+ return GetDeterministicRandomizer(RANDOMIZER_ID_NETGROUP).Write(&vchNetGroup[0], vchNetGroup.size()).Finalize();
}
diff --git a/src/net.h b/src/net.h
index 1ba2d47da7..d0b2773623 100644
--- a/src/net.h
+++ b/src/net.h
@@ -6,9 +6,12 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
+#include "addrdb.h"
+#include "addrman.h"
#include "amount.h"
#include "bloom.h"
#include "compat.h"
+#include "hash.h"
#include "limitedmap.h"
#include "netaddress.h"
#include "protocol.h"
@@ -20,6 +23,7 @@
#include <atomic>
#include <deque>
#include <stdint.h>
+#include <memory>
#ifndef WIN32
#include <arpa/inet.h>
@@ -51,6 +55,8 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000;
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
/** Maximum length of strSubVer in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
+/** Maximum number of outgoing nodes */
+static const int MAX_OUTBOUND_CONNECTIONS = 8;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@@ -67,6 +73,8 @@ static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
static const uint64_t DEFAULT_MAX_UPLOAD_TARGET = 0;
+/** The default timeframe for -maxuploadtarget. 1 day. */
+static const uint64_t MAX_UPLOAD_TIMEFRAME = 60 * 60 * 24;
/** Default for blocks only*/
static const bool DEFAULT_BLOCKSONLY = false;
@@ -79,25 +87,326 @@ static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
-unsigned int ReceiveFloodSize();
-unsigned int SendBufferSize();
-
typedef int NodeId;
-void AddOneShot(const std::string& strDest);
-void AddressCurrentlyConnected(const CService& addr);
-CNode* FindNode(const CNetAddr& ip);
-CNode* FindNode(const CSubNet& subNet);
-CNode* FindNode(const std::string& addrName);
-CNode* FindNode(const CService& ip);
-CNode* FindNode(const NodeId id); //TODO: Remove this
-bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
+struct AddedNodeInfo
+{
+ std::string strAddedNode;
+ CService resolvedAddress;
+ bool fConnected;
+ bool fInbound;
+};
+
+class CTransaction;
+class CNodeStats;
+class CClientUIInterface;
+
+class CConnman
+{
+public:
+
+ enum NumConnections {
+ CONNECTIONS_NONE = 0,
+ CONNECTIONS_IN = (1U << 0),
+ CONNECTIONS_OUT = (1U << 1),
+ CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
+ };
+
+ struct Options
+ {
+ ServiceFlags nLocalServices = NODE_NONE;
+ ServiceFlags nRelevantServices = NODE_NONE;
+ int nMaxConnections = 0;
+ int nMaxOutbound = 0;
+ int nMaxFeeler = 0;
+ int nBestHeight = 0;
+ CClientUIInterface* uiInterface = nullptr;
+ unsigned int nSendBufferMaxSize = 0;
+ unsigned int nReceiveFloodSize = 0;
+ uint64_t nMaxOutboundTimeframe = 0;
+ uint64_t nMaxOutboundLimit = 0;
+ };
+ CConnman(uint64_t seed0, uint64_t seed1);
+ ~CConnman();
+ bool Start(boost::thread_group& threadGroup, CScheduler& scheduler, std::string& strNodeError, Options options);
+ void Stop();
+ bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
+ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false);
+ bool CheckIncomingNonce(uint64_t nonce);
+
+ bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
+
+ template<typename Callable>
+ bool ForEachNodeContinueIf(Callable&& func)
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes)
+ if(!func(node))
+ return false;
+ return true;
+ };
+
+ template<typename Callable>
+ bool ForEachNodeContinueIf(Callable&& func) const
+ {
+ LOCK(cs_vNodes);
+ for (const auto& node : vNodes)
+ if(!func(node))
+ return false;
+ return true;
+ };
+
+ template<typename Callable, typename CallableAfter>
+ bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post)
+ {
+ bool ret = true;
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes)
+ if(!pre(node)) {
+ ret = false;
+ break;
+ }
+ post();
+ return ret;
+ };
+
+ template<typename Callable, typename CallableAfter>
+ bool ForEachNodeContinueIfThen(Callable&& pre, CallableAfter&& post) const
+ {
+ bool ret = true;
+ LOCK(cs_vNodes);
+ for (const auto& node : vNodes)
+ if(!pre(node)) {
+ ret = false;
+ break;
+ }
+ post();
+ return ret;
+ };
+
+ template<typename Callable>
+ void ForEachNode(Callable&& func)
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes)
+ func(node);
+ };
+
+ template<typename Callable>
+ void ForEachNode(Callable&& func) const
+ {
+ LOCK(cs_vNodes);
+ for (const auto& node : vNodes)
+ func(node);
+ };
+
+ template<typename Callable, typename CallableAfter>
+ void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes)
+ pre(node);
+ post();
+ };
+
+ template<typename Callable, typename CallableAfter>
+ void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
+ {
+ LOCK(cs_vNodes);
+ for (const auto& node : vNodes)
+ pre(node);
+ post();
+ };
+
+ void RelayTransaction(const CTransaction& tx);
+
+ // Addrman functions
+ size_t GetAddressCount() const;
+ void SetServices(const CService &addr, ServiceFlags nServices);
+ void MarkAddressGood(const CAddress& addr);
+ void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
+ void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
+ std::vector<CAddress> GetAddresses();
+ void AddressCurrentlyConnected(const CService& addr);
+
+ // Denial-of-service detection/prevention
+ // The idea is to detect peers that are behaving
+ // badly and disconnect/ban them, but do it in a
+ // one-coding-mistake-won't-shatter-the-entire-network
+ // way.
+ // IMPORTANT: There should be nothing I can give a
+ // node that it will forward on that will make that
+ // node's peers drop it. If there is, an attacker
+ // can isolate a node and/or try to split the network.
+ // Dropping a node for sending stuff that is invalid
+ // now but might be valid in a later version is also
+ // dangerous, because it can cause a network split
+ // between nodes running old code and nodes running
+ // new code.
+ void Ban(const CNetAddr& netAddr, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ void Ban(const CSubNet& subNet, const BanReason& reason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ void ClearBanned(); // needed for unit testing
+ bool IsBanned(CNetAddr ip);
+ bool IsBanned(CSubNet subnet);
+ bool Unban(const CNetAddr &ip);
+ bool Unban(const CSubNet &ip);
+ void GetBanned(banmap_t &banmap);
+ void SetBanned(const banmap_t &banmap);
+
+ void AddOneShot(const std::string& strDest);
+
+ bool AddNode(const std::string& node);
+ bool RemoveAddedNode(const std::string& node);
+ std::vector<AddedNodeInfo> GetAddedNodeInfo();
+
+ size_t GetNodeCount(NumConnections num);
+ void GetNodeStats(std::vector<CNodeStats>& vstats);
+ bool DisconnectAddress(const CNetAddr& addr);
+ bool DisconnectNode(const std::string& node);
+ bool DisconnectNode(NodeId id);
+ bool DisconnectSubnet(const CSubNet& subnet);
+
+ unsigned int GetSendBufferSize() const;
+
+ void AddWhitelistedRange(const CSubNet &subnet);
+
+ ServiceFlags GetLocalServices() const;
+
+ //!set the max outbound target in bytes
+ void SetMaxOutboundTarget(uint64_t limit);
+ uint64_t GetMaxOutboundTarget();
+
+ //!set the timeframe for the max outbound target
+ void SetMaxOutboundTimeframe(uint64_t timeframe);
+ uint64_t GetMaxOutboundTimeframe();
+
+ //!check if the outbound target is reached
+ // if param historicalBlockServingLimit is set true, the function will
+ // response true if the limit for serving historical blocks has been reached
+ bool OutboundTargetReached(bool historicalBlockServingLimit);
+
+ //!response the bytes left in the current max outbound cycle
+ // in case of no limit, it will always response 0
+ uint64_t GetOutboundTargetBytesLeft();
+
+ //!response the time in second left in the current max outbound cycle
+ // in case of no limit, it will always response 0
+ uint64_t GetMaxOutboundTimeLeftInCycle();
+
+ uint64_t GetTotalBytesRecv();
+ uint64_t GetTotalBytesSent();
+
+ void SetBestHeight(int height);
+ int GetBestHeight() const;
+
+ /** Get a unique deterministic randomizer. */
+ CSipHasher GetDeterministicRandomizer(uint64_t id);
+
+private:
+ struct ListenSocket {
+ SOCKET socket;
+ bool whitelisted;
+
+ ListenSocket(SOCKET socket_, bool whitelisted_) : socket(socket_), whitelisted(whitelisted_) {}
+ };
+
+ void ThreadOpenAddedConnections();
+ void ProcessOneShot();
+ void ThreadOpenConnections();
+ void ThreadMessageHandler();
+ void AcceptConnection(const ListenSocket& hListenSocket);
+ void ThreadSocketHandler();
+ void ThreadDNSAddressSeed();
+
+ uint64_t CalculateKeyedNetGroup(const CAddress& ad);
+
+ CNode* FindNode(const CNetAddr& ip);
+ CNode* FindNode(const CSubNet& subNet);
+ CNode* FindNode(const std::string& addrName);
+ CNode* FindNode(const CService& addr);
+
+ bool AttemptToEvictConnection();
+ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure);
+ bool IsWhitelistedRange(const CNetAddr &addr);
+
+ void DeleteNode(CNode* pnode);
+
+ NodeId GetNewNodeId();
+
+ //!check is the banlist has unwritten changes
+ bool BannedSetIsDirty();
+ //!set the "dirty" flag for the banlist
+ void SetBannedSetDirty(bool dirty=true);
+ //!clean unused entries (if bantime has expired)
+ void SweepBanned();
+ void DumpAddresses();
+ void DumpData();
+ void DumpBanlist();
+
+ unsigned int GetReceiveFloodSize() const;
+
+ // Network stats
+ void RecordBytesRecv(uint64_t bytes);
+ void RecordBytesSent(uint64_t bytes);
+
+ // Network usage totals
+ CCriticalSection cs_totalBytesRecv;
+ CCriticalSection cs_totalBytesSent;
+ uint64_t nTotalBytesRecv;
+ uint64_t nTotalBytesSent;
+
+ // outbound limit & stats
+ uint64_t nMaxOutboundTotalBytesSentInCycle;
+ uint64_t nMaxOutboundCycleStartTime;
+ uint64_t nMaxOutboundLimit;
+ uint64_t nMaxOutboundTimeframe;
+
+ // 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;
+
+ std::vector<ListenSocket> vhListenSocket;
+ banmap_t setBanned;
+ CCriticalSection cs_setBanned;
+ bool setBannedIsDirty;
+ bool fAddressesInitialized;
+ CAddrMan addrman;
+ std::deque<std::string> vOneShots;
+ CCriticalSection cs_vOneShots;
+ std::vector<std::string> vAddedNodes;
+ CCriticalSection cs_vAddedNodes;
+ std::vector<CNode*> vNodes;
+ std::list<CNode*> vNodesDisconnected;
+ mutable CCriticalSection cs_vNodes;
+ std::atomic<NodeId> nLastNodeId;
+ boost::condition_variable messageHandlerCondition;
+
+ /** Services this instance offers */
+ ServiceFlags nLocalServices;
+
+ /** Services this instance cares about */
+ ServiceFlags nRelevantServices;
+
+ CSemaphore *semOutbound;
+ int nMaxConnections;
+ int nMaxOutbound;
+ int nMaxFeeler;
+ std::atomic<int> nBestHeight;
+ CClientUIInterface* clientInterface;
+
+ /** SipHasher seeds for deterministic randomness */
+ const uint64_t nSeed0, nSeed1;
+};
+extern std::unique_ptr<CConnman> g_connman;
+void Discover(boost::thread_group& threadGroup);
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
-void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
-bool StopNode();
-void SocketSendData(CNode *pnode);
+size_t SocketSendData(CNode *pnode);
struct CombinerAll
{
@@ -117,11 +426,10 @@ struct CombinerAll
// Signals for message handling
struct CNodeSignals
{
- boost::signals2::signal<int ()> GetHeight;
- boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
- boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
+ boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> ProcessMessages;
+ boost::signals2::signal<bool (CNode*, CConnman&), CombinerAll> SendMessages;
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
- boost::signals2::signal<void (NodeId)> FinalizeNode;
+ boost::signals2::signal<void (NodeId, bool&)> FinalizeNode;
};
@@ -152,30 +460,15 @@ bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr);
-CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
+CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
extern bool fDiscover;
extern bool fListen;
-extern ServiceFlags nLocalServices;
-extern ServiceFlags nRelevantServices;
extern bool fRelayTxes;
-extern uint64_t nLocalHostNonce;
-extern CAddrMan addrman;
-/** Maximum number of connections to simultaneously allow (aka connection slots) */
-extern int nMaxConnections;
-
-extern std::vector<CNode*> vNodes;
-extern CCriticalSection cs_vNodes;
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
-extern std::vector<std::string> vAddedNodes;
-extern CCriticalSection cs_vAddedNodes;
-
-extern NodeId nLastNodeId;
-extern CCriticalSection cs_nLastNodeId;
-
/** Subversion as sent to the P2P network in `version` messages */
extern std::string strSubVersion;
@@ -256,67 +549,6 @@ public:
};
-typedef enum BanReason
-{
- BanReasonUnknown = 0,
- BanReasonNodeMisbehaving = 1,
- BanReasonManuallyAdded = 2
-} BanReason;
-
-class CBanEntry
-{
-public:
- static const int CURRENT_VERSION=1;
- int nVersion;
- int64_t nCreateTime;
- int64_t nBanUntil;
- uint8_t banReason;
-
- CBanEntry()
- {
- SetNull();
- }
-
- CBanEntry(int64_t nCreateTimeIn)
- {
- SetNull();
- nCreateTime = nCreateTimeIn;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- READWRITE(this->nVersion);
- nVersion = this->nVersion;
- READWRITE(nCreateTime);
- READWRITE(nBanUntil);
- READWRITE(banReason);
- }
-
- void SetNull()
- {
- nVersion = CBanEntry::CURRENT_VERSION;
- nCreateTime = 0;
- nBanUntil = 0;
- banReason = BanReasonUnknown;
- }
-
- std::string banReasonToString()
- {
- switch (banReason) {
- case BanReasonNodeMisbehaving:
- return "node misbehaving";
- case BanReasonManuallyAdded:
- return "manually added";
- default:
- return "unknown";
- }
- }
-};
-
-typedef std::map<CSubNet, CBanEntry> banmap_t;
-
/** Information about a peer */
class CNode
{
@@ -328,6 +560,7 @@ public:
CDataStream ssSend;
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
+ uint64_t nOptimisticBytesWritten;
uint64_t nSendBytes;
std::deque<CSerializeData> vSendMsg;
CCriticalSection cs_vSend;
@@ -374,17 +607,6 @@ public:
const uint64_t nKeyedNetGroup;
protected:
- // Denial-of-service detection/prevention
- // Key is IP address, value is banned-until-time
- static banmap_t setBanned;
- static CCriticalSection cs_setBanned;
- static bool setBannedIsDirty;
-
- // Whitelisted ranges. Any node connecting from these is automatically
- // whitelisted (as well as those connecting to whitelisted binds).
- static std::vector<CSubNet> vWhitelistedRange;
- static CCriticalSection cs_vWhitelistedRange;
-
mapMsgCmdSize mapSendBytesPerMsgCmd;
mapMsgCmdSize mapRecvBytesPerMsgCmd;
@@ -446,33 +668,28 @@ public:
CAmount lastSentFeeFilter;
int64_t nextSendTimeFeeFilter;
- CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
+ CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
private:
- // Network usage totals
- static CCriticalSection cs_totalBytesRecv;
- static CCriticalSection cs_totalBytesSent;
- static uint64_t nTotalBytesRecv;
- static uint64_t nTotalBytesSent;
-
- // outbound limit & stats
- static uint64_t nMaxOutboundTotalBytesSentInCycle;
- static uint64_t nMaxOutboundCycleStartTime;
- static uint64_t nMaxOutboundLimit;
- static uint64_t nMaxOutboundTimeframe;
-
CNode(const CNode&);
void operator=(const CNode&);
- static uint64_t CalculateKeyedNetGroup(const CAddress& ad);
+ uint64_t nLocalHostNonce;
+ // Services offered to this peer
+ ServiceFlags nLocalServices;
+ int nMyStartingHeight;
public:
NodeId GetId() const {
return id;
}
+ uint64_t GetLocalNonce() const {
+ return nLocalHostNonce;
+ }
+
int GetRefCount()
{
assert(nRefCount >= 0);
@@ -489,7 +706,7 @@ public:
}
// requires LOCK(cs_vRecvMsg)
- bool ReceiveMsgBytes(const char *pch, unsigned int nBytes);
+ bool ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete);
// requires LOCK(cs_vRecvMsg)
void SetRecvVersion(int nVersionIn)
@@ -512,21 +729,21 @@ public:
- void AddAddressKnown(const CAddress& addr)
+ void AddAddressKnown(const CAddress& _addr)
{
- addrKnown.insert(addr.GetKey());
+ addrKnown.insert(_addr.GetKey());
}
- void PushAddress(const CAddress& addr)
+ void PushAddress(const CAddress& _addr)
{
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
- if (addr.IsValid() && !addrKnown.contains(addr.GetKey())) {
+ if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
- vAddrToSend[insecure_rand() % vAddrToSend.size()] = addr;
+ vAddrToSend[insecure_rand() % vAddrToSend.size()] = _addr;
} else {
- vAddrToSend.push_back(addr);
+ vAddrToSend.push_back(_addr);
}
}
}
@@ -749,110 +966,19 @@ public:
void CloseSocketDisconnect();
- // Denial-of-service detection/prevention
- // The idea is to detect peers that are behaving
- // badly and disconnect/ban them, but do it in a
- // one-coding-mistake-won't-shatter-the-entire-network
- // way.
- // IMPORTANT: There should be nothing I can give a
- // node that it will forward on that will make that
- // node's peers drop it. If there is, an attacker
- // can isolate a node and/or try to split the network.
- // Dropping a node for sending stuff that is invalid
- // now but might be valid in a later version is also
- // dangerous, because it can cause a network split
- // between nodes running old code and nodes running
- // new code.
- static void ClearBanned(); // needed for unit testing
- static bool IsBanned(CNetAddr ip);
- static bool IsBanned(CSubNet subnet);
- static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
- static bool Unban(const CNetAddr &ip);
- static bool Unban(const CSubNet &ip);
- static void GetBanned(banmap_t &banmap);
- static void SetBanned(const banmap_t &banmap);
-
- //!check is the banlist has unwritten changes
- static bool BannedSetIsDirty();
- //!set the "dirty" flag for the banlist
- static void SetBannedSetDirty(bool dirty=true);
- //!clean unused entries (if bantime has expired)
- static void SweepBanned();
-
void copyStats(CNodeStats &stats);
- static bool IsWhitelistedRange(const CNetAddr &ip);
- static void AddWhitelistedRange(const CSubNet &subnet);
-
- // Network stats
- static void RecordBytesRecv(uint64_t bytes);
- static void RecordBytesSent(uint64_t bytes);
-
- static uint64_t GetTotalBytesRecv();
- static uint64_t GetTotalBytesSent();
-
- //!set the max outbound target in bytes
- static void SetMaxOutboundTarget(uint64_t limit);
- static uint64_t GetMaxOutboundTarget();
-
- //!set the timeframe for the max outbound target
- static void SetMaxOutboundTimeframe(uint64_t timeframe);
- static uint64_t GetMaxOutboundTimeframe();
-
- //!check if the outbound target is reached
- // if param historicalBlockServingLimit is set true, the function will
- // response true if the limit for serving historical blocks has been reached
- static bool OutboundTargetReached(bool historicalBlockServingLimit);
-
- //!response the bytes left in the current max outbound cycle
- // in case of no limit, it will always response 0
- static uint64_t GetOutboundTargetBytesLeft();
-
- //!response the time in second left in the current max outbound cycle
- // in case of no limit, it will always response 0
- static uint64_t GetMaxOutboundTimeLeftInCycle();
+ ServiceFlags GetLocalServices() const
+ {
+ return nLocalServices;
+ }
};
-class CTransaction;
-void RelayTransaction(const CTransaction& tx);
-/** Access to the (IP) address database (peers.dat) */
-class CAddrDB
-{
-private:
- boost::filesystem::path pathAddr;
-public:
- CAddrDB();
- bool Write(const CAddrMan& addr);
- bool Read(CAddrMan& addr);
- bool Read(CAddrMan& addr, CDataStream& ssPeers);
-};
-
-/** Access to the banlist database (banlist.dat) */
-class CBanDB
-{
-private:
- boost::filesystem::path pathBanlist;
-public:
- CBanDB();
- bool Write(const banmap_t& banSet);
- bool Read(banmap_t& banSet);
-};
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
-struct AddedNodeInfo
-{
- std::string strAddedNode;
- CService resolvedAddress;
- bool fConnected;
- bool fInbound;
-};
-
-std::vector<AddedNodeInfo> GetAddedNodeInfo();
-
#endif // BITCOIN_NET_H
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 7000ce3f0a..db5cc3bc20 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -197,8 +197,8 @@ bool CNetAddr::IsValid() const
return false;
// unspecified IPv6 address (::/128)
- unsigned char ipNone[16] = {};
- if (memcmp(ip, ipNone, 16) == 0)
+ unsigned char ipNone6[16] = {};
+ if (memcmp(ip, ipNone6, 16) == 0)
return false;
// documentation IPv6 address
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 4f243ec6f5..7d7f1b6788 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -631,8 +631,8 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SplitHostPort(std::string(pszDest), port, strDest);
- proxyType nameProxy;
- GetNameProxy(nameProxy);
+ proxyType proxy;
+ GetNameProxy(proxy);
std::vector<CService> addrResolved;
if (Lookup(strDest.c_str(), addrResolved, port, fNameLookup && !HaveNameProxy(), 256)) {
@@ -646,7 +646,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
if (!HaveNameProxy())
return false;
- return ConnectThroughProxy(nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
+ return ConnectThroughProxy(proxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
}
bool LookupSubNet(const char* pszName, CSubNet& ret)
diff --git a/src/netbase.h b/src/netbase.h
index bb12019a82..eb39d16578 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -29,7 +29,7 @@ class proxyType
{
public:
proxyType(): randomize_credentials(false) {}
- proxyType(const CService &proxy, bool randomize_credentials=false): proxy(proxy), randomize_credentials(randomize_credentials) {}
+ proxyType(const CService &_proxy, bool _randomize_credentials=false): proxy(_proxy), randomize_credentials(_randomize_credentials) {}
bool IsValid() const { return proxy.IsValid(); }
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 2fdc59ea07..4afbe99fd3 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -131,6 +131,11 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
return nTxSize;
}
+unsigned int CTransaction::GetTotalSize() const
+{
+ return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+}
+
std::string CTransaction::ToString() const
{
std::string str;
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 5689d15bf7..16c2e5c454 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -415,6 +415,13 @@ public:
// Compute modified tx size for priority calculation (optionally given tx size)
unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
+
+ /**
+ * Get the total transaction size in bytes, including witness data.
+ * "Total Size" defined in BIP141 and BIP144.
+ * @return Total transaction size in bytes
+ */
+ unsigned int GetTotalSize() const;
bool IsCoinBase() const
{
diff --git a/src/protocol.h b/src/protocol.h
index 015215b2a6..9b474ec79c 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -267,6 +267,9 @@ enum ServiceFlags : uint64_t {
// Indicates that a node can be asked for blocks and transactions including
// witness data.
NODE_WITNESS = (1 << 3),
+ // NODE_XTHIN means the node supports Xtreme Thinblocks
+ // If this is turned off then the node will not service nor make xthin requests
+ NODE_XTHIN = (1 << 4),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 135f15ffa8..58cf4dede0 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -21,12 +21,12 @@
#include <QMessageBox>
#include <QSortFilterProxyModel>
-AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent) :
+AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
model(0),
- mode(mode),
- tab(tab)
+ mode(_mode),
+ tab(_tab)
{
ui->setupUi(this);
@@ -107,14 +107,14 @@ AddressBookPage::~AddressBookPage()
delete ui;
}
-void AddressBookPage::setModel(AddressTableModel *model)
+void AddressBookPage::setModel(AddressTableModel *_model)
{
- this->model = model;
- if(!model)
+ this->model = _model;
+ if(!_model)
return;
proxyModel = new QSortFilterProxyModel(this);
- proxyModel->setSourceModel(model);
+ proxyModel->setSourceModel(_model);
proxyModel->setDynamicSortFilter(true);
proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
@@ -147,7 +147,7 @@ void AddressBookPage::setModel(AddressTableModel *model)
this, SLOT(selectionChanged()));
// Select row for newly created address
- connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));
+ connect(_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectNewAddress(QModelIndex,int,int)));
selectionChanged();
}
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 71ed3618e4..830c9cdf19 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -31,8 +31,8 @@ struct AddressTableEntry
QString address;
AddressTableEntry() {}
- AddressTableEntry(Type type, const QString &label, const QString &address):
- type(type), label(label), address(address) {}
+ AddressTableEntry(Type _type, const QString &_label, const QString &_address):
+ type(_type), label(_label), address(_address) {}
};
struct AddressTableEntryLessThan
@@ -73,8 +73,8 @@ public:
QList<AddressTableEntry> cachedAddressTable;
AddressTableModel *parent;
- AddressTablePriv(CWallet *wallet, AddressTableModel *parent):
- wallet(wallet), parent(parent) {}
+ AddressTablePriv(CWallet *_wallet, AddressTableModel *_parent):
+ wallet(_wallet), parent(_parent) {}
void refreshAddressTable()
{
@@ -164,8 +164,8 @@ public:
}
};
-AddressTableModel::AddressTableModel(CWallet *wallet, WalletModel *parent) :
- QAbstractTableModel(parent),walletModel(parent),wallet(wallet),priv(0)
+AddressTableModel::AddressTableModel(CWallet *_wallet, WalletModel *parent) :
+ QAbstractTableModel(parent),walletModel(parent),wallet(_wallet),priv(0)
{
columns << tr("Label") << tr("Address");
priv = new AddressTablePriv(wallet, this);
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index e8aa79679c..129ea1efa4 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -18,10 +18,10 @@
#include <QMessageBox>
#include <QPushButton>
-AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
+AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) :
QDialog(parent),
ui(new Ui::AskPassphraseDialog),
- mode(mode),
+ mode(_mode),
model(0),
fCapsLock(false)
{
@@ -81,9 +81,9 @@ AskPassphraseDialog::~AskPassphraseDialog()
delete ui;
}
-void AskPassphraseDialog::setModel(WalletModel *model)
+void AskPassphraseDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
}
void AskPassphraseDialog::accept()
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index d95106b5ac..6e11e23904 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -48,7 +48,8 @@ public:
void refreshBanlist()
{
banmap_t banMap;
- CNode::GetBanned(banMap);
+ if(g_connman)
+ g_connman->GetBanned(banMap);
cachedBanlist.clear();
#if QT_VERSION >= 0x040700
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 2a9afc51a0..dd022ee762 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -76,8 +76,9 @@ const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
+BitcoinGUI::BitcoinGUI(const PlatformStyle *_platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
+ enableWallet(false),
clientModel(0),
walletFrame(0),
unitDisplayControl(0),
@@ -118,16 +119,13 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
modalOverlay(0),
prevBlocks(0),
spinnerFrame(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
QString windowTitle = tr(PACKAGE_NAME) + " - ";
#ifdef ENABLE_WALLET
- /* if compiled with wallet support, -disablewallet can still disable the wallet */
- enableWallet = !GetBoolArg("-disablewallet", false);
-#else
- enableWallet = false;
+ enableWallet = WalletModel::isWalletEnabled();
#endif // ENABLE_WALLET
if(enableWallet)
{
@@ -150,13 +148,13 @@ BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *n
setUnifiedTitleAndToolBarOnMac(true);
#endif
- rpcConsole = new RPCConsole(platformStyle, 0);
+ rpcConsole = new RPCConsole(_platformStyle, 0);
helpMessageDialog = new HelpMessageDialog(this, false);
#ifdef ENABLE_WALLET
if(enableWallet)
{
/** Create wallet frame and make it the central widget */
- walletFrame = new WalletFrame(platformStyle, this);
+ walletFrame = new WalletFrame(_platformStyle, this);
setCentralWidget(walletFrame);
} else
#endif // ENABLE_WALLET
@@ -459,38 +457,38 @@ void BitcoinGUI::createToolBars()
}
}
-void BitcoinGUI::setClientModel(ClientModel *clientModel)
+void BitcoinGUI::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
- if(clientModel)
+ this->clientModel = _clientModel;
+ if(_clientModel)
{
// Create system tray menu (or setup the dock menu) that late to prevent users from calling actions,
// while the client has not yet fully loaded
createTrayIconMenu();
// Keep up to date with client
- setNumConnections(clientModel->getNumConnections());
- connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
+ setNumConnections(_clientModel->getNumConnections());
+ connect(_clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL), false);
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
+ setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(NULL), false);
+ connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
// Receive and report messages from client model
- connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
+ connect(_clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
// Show progress dialog
- connect(clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
+ connect(_clientModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
- rpcConsole->setClientModel(clientModel);
+ rpcConsole->setClientModel(_clientModel);
#ifdef ENABLE_WALLET
if(walletFrame)
{
- walletFrame->setClientModel(clientModel);
+ walletFrame->setClientModel(_clientModel);
}
#endif // ENABLE_WALLET
- unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
+ unitDisplayControl->setOptionsModel(_clientModel->getOptionsModel());
- OptionsModel* optionsModel = clientModel->getOptionsModel();
+ OptionsModel* optionsModel = _clientModel->getOptionsModel();
if(optionsModel)
{
// be aware of the tray icon disable state change reported by the OptionsModel object.
@@ -1179,17 +1177,17 @@ void UnitDisplayStatusBarControl::createContextMenu()
}
/** Lets the control know about the Options Model (and its signals) */
-void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *optionsModel)
+void UnitDisplayStatusBarControl::setOptionsModel(OptionsModel *_optionsModel)
{
- if (optionsModel)
+ if (_optionsModel)
{
- this->optionsModel = optionsModel;
+ this->optionsModel = _optionsModel;
// be aware of a display unit change reported by the OptionsModel object.
- connect(optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
+ connect(_optionsModel,SIGNAL(displayUnitChanged(int)),this,SLOT(updateDisplayUnit(int)));
// initialize the display units label with the current value in the model.
- updateDisplayUnit(optionsModel->getDisplayUnit());
+ updateDisplayUnit(_optionsModel->getDisplayUnit());
}
}
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index fb0cce59cc..6d19b3d122 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -27,9 +27,9 @@ static const int64_t nClientStartupTime = GetTime();
static int64_t nLastHeaderTipUpdateNotification = 0;
static int64_t nLastBlockTipUpdateNotification = 0;
-ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
+ClientModel::ClientModel(OptionsModel *_optionsModel, QObject *parent) :
QObject(parent),
- optionsModel(optionsModel),
+ optionsModel(_optionsModel),
peerTableModel(0),
banTableModel(0),
pollTimer(0)
@@ -50,16 +50,18 @@ ClientModel::~ClientModel()
int ClientModel::getNumConnections(unsigned int flags) const
{
- LOCK(cs_vNodes);
- if (flags == CONNECTIONS_ALL) // Shortcut if we want total
- return vNodes.size();
+ CConnman::NumConnections connections = CConnman::CONNECTIONS_NONE;
- int nNum = 0;
- BOOST_FOREACH(const CNode* pnode, vNodes)
- if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
- nNum++;
+ if(flags == CONNECTIONS_IN)
+ connections = CConnman::CONNECTIONS_IN;
+ else if (flags == CONNECTIONS_OUT)
+ connections = CConnman::CONNECTIONS_OUT;
+ else if (flags == CONNECTIONS_ALL)
+ connections = CConnman::CONNECTIONS_ALL;
- return nNum;
+ if(g_connman)
+ return g_connman->GetNodeCount(connections);
+ return 0;
}
int ClientModel::getNumBlocks() const
@@ -86,12 +88,16 @@ int64_t ClientModel::getHeaderTipTime() const
quint64 ClientModel::getTotalBytesRecv() const
{
- return CNode::GetTotalBytesRecv();
+ if(!g_connman)
+ return 0;
+ return g_connman->GetTotalBytesRecv();
}
quint64 ClientModel::getTotalBytesSent() const
{
- return CNode::GetTotalBytesSent();
+ if(!g_connman)
+ return 0;
+ return g_connman->GetTotalBytesSent();
}
QDateTime ClientModel::getLastBlockDate() const
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index f53242100c..86fd4ebd65 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -35,11 +35,11 @@ QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
bool CoinControlDialog::fSubtractFeeFromAmount = false;
-CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::CoinControlDialog),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -152,15 +152,15 @@ CoinControlDialog::~CoinControlDialog()
delete ui;
}
-void CoinControlDialog::setModel(WalletModel *model)
+void CoinControlDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model && model->getOptionsModel() && model->getAddressTableModel())
+ if(_model && _model->getOptionsModel() && _model->getAddressTableModel())
{
updateView();
updateLabelLocked();
- CoinControlDialog::updateLabels(model, this);
+ CoinControlDialog::updateLabels(_model, this);
}
}
diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp
index 8a1a49bb06..f424e6cd98 100644
--- a/src/qt/csvmodelwriter.cpp
+++ b/src/qt/csvmodelwriter.cpp
@@ -8,15 +8,15 @@
#include <QFile>
#include <QTextStream>
-CSVModelWriter::CSVModelWriter(const QString &filename, QObject *parent) :
+CSVModelWriter::CSVModelWriter(const QString &_filename, QObject *parent) :
QObject(parent),
- filename(filename), model(0)
+ filename(_filename), model(0)
{
}
-void CSVModelWriter::setModel(const QAbstractItemModel *model)
+void CSVModelWriter::setModel(const QAbstractItemModel *_model)
{
- this->model = model;
+ this->model = _model;
}
void CSVModelWriter::addColumn(const QString &title, int column, int role)
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index 5f45031e9e..a9ffe016fd 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -11,11 +11,11 @@
#include <QDataWidgetMapper>
#include <QMessageBox>
-EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) :
+EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
QDialog(parent),
ui(new Ui::EditAddressDialog),
mapper(0),
- mode(mode),
+ mode(_mode),
model(0)
{
ui->setupUi(this);
@@ -49,13 +49,13 @@ EditAddressDialog::~EditAddressDialog()
delete ui;
}
-void EditAddressDialog::setModel(AddressTableModel *model)
+void EditAddressDialog::setModel(AddressTableModel *_model)
{
- this->model = model;
- if(!model)
+ this->model = _model;
+ if(!_model)
return;
- mapper->setModel(model);
+ mapper->setModel(_model);
mapper->addMapping(ui->labelEdit, AddressTableModel::Label);
mapper->addMapping(ui->addressEdit, AddressTableModel::Address);
}
@@ -137,8 +137,8 @@ QString EditAddressDialog::getAddress() const
return address;
}
-void EditAddressDialog::setAddress(const QString &address)
+void EditAddressDialog::setAddress(const QString &_address)
{
- this->address = address;
- ui->addressEdit->setText(address);
+ this->address = _address;
+ ui->addressEdit->setText(_address);
}
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index fe9de1c7a1..0beaddf997 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -291,17 +291,17 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
}
}
-QString getEntryData(QAbstractItemView *view, int column, int role)
+QVariant getEntryData(QAbstractItemView *view, int column, int role)
{
if(!view || !view->selectionModel())
- return QString();
+ return QVariant();
QModelIndexList selection = view->selectionModel()->selectedRows(column);
if(!selection.isEmpty()) {
// Return first item
- return (selection.at(0).data(role).toString());
+ return (selection.at(0).data(role));
}
- return QString();
+ return QVariant();
}
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
@@ -462,9 +462,9 @@ void SubstituteFonts(const QString& language)
#endif
}
-ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
+ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) :
QObject(parent),
- size_threshold(size_threshold)
+ size_threshold(_size_threshold)
{
}
@@ -930,6 +930,9 @@ QString formatServicesStr(quint64 mask)
case NODE_WITNESS:
strList.append("WITNESS");
break;
+ case NODE_XTHIN:
+ strList.append("XTHIN");
+ break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 7697e53ae9..e28f68930f 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -70,7 +70,7 @@ namespace GUIUtil
@param[in] role Data role to extract from the model
@see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
*/
- QString getEntryData(QAbstractItemView *view, int column, int role);
+ QVariant getEntryData(QAbstractItemView *view, int column, int role);
void setClipboard(const QString& str);
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 1a241ae0f0..5a336b105e 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -63,9 +63,9 @@ private:
#include "intro.moc"
-FreespaceChecker::FreespaceChecker(Intro *intro)
+FreespaceChecker::FreespaceChecker(Intro *_intro)
{
- this->intro = intro;
+ this->intro = _intro;
}
void FreespaceChecker::check()
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 5f31f49372..acbfee0868 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -22,9 +22,9 @@ static const struct {
static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles);
// titleAddText needs to be const char* for tr()
-NetworkStyle::NetworkStyle(const QString &appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *titleAddText):
- appName(appName),
- titleAddText(qApp->translate("SplashScreen", titleAddText))
+NetworkStyle::NetworkStyle(const QString &_appName, const int iconColorHueShift, const int iconColorSaturationReduction, const char *_titleAddText):
+ appName(_appName),
+ titleAddText(qApp->translate("SplashScreen", _titleAddText))
{
// load pixmap
QPixmap pixmap(":/icons/bitcoin");
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index a45afde566..8277e20c90 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -33,17 +33,17 @@
const int FREEDESKTOP_NOTIFICATION_ICON_SIZE = 128;
#endif
-Notificator::Notificator(const QString &programName, QSystemTrayIcon *trayicon, QWidget *parent) :
- QObject(parent),
- parent(parent),
- programName(programName),
+Notificator::Notificator(const QString &_programName, QSystemTrayIcon *_trayIcon, QWidget *_parent) :
+ QObject(_parent),
+ parent(_parent),
+ programName(_programName),
mode(None),
- trayIcon(trayicon)
+ trayIcon(_trayIcon)
#ifdef USE_DBUS
,interface(0)
#endif
{
- if(trayicon && trayicon->supportsMessages())
+ if(_trayIcon && _trayIcon->supportsMessages())
{
mode = QSystemTray;
}
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index f73bb87064..588059d0c5 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -135,22 +135,22 @@ OptionsDialog::~OptionsDialog()
delete ui;
}
-void OptionsDialog::setModel(OptionsModel *model)
+void OptionsDialog::setModel(OptionsModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model)
+ if(_model)
{
/* check if client restart is needed and show persistent message */
- if (model->isRestartRequired())
+ if (_model->isRestartRequired())
showRestartWarning(true);
- QString strLabel = model->getOverriddenByCommandLine();
+ QString strLabel = _model->getOverriddenByCommandLine();
if (strLabel.isEmpty())
strLabel = tr("none");
ui->overriddenByCommandLineLabel->setText(strLabel);
- mapper->setModel(model);
+ mapper->setModel(_model);
setMapper();
mapper->toFirst();
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index e415a6c4dd..7ccdb89c0c 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -25,9 +25,9 @@ class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(const PlatformStyle *platformStyle):
+ TxViewDelegate(const PlatformStyle *_platformStyle):
QAbstractItemDelegate(), unit(BitcoinUnits::BTC),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
}
diff --git a/src/qt/paymentrequest.proto b/src/qt/paymentrequest.proto
index b2281c4c7b..d2721a34bd 100644
--- a/src/qt/paymentrequest.proto
+++ b/src/qt/paymentrequest.proto
@@ -6,6 +6,8 @@
// https://en.bitcoin.it/wiki/Payment_Request
//
+syntax = "proto2";
+
package payments;
option java_package = "org.bitcoin.protocols.payments";
option java_outer_classname = "Protos";
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index c80aebb009..9f23e77a13 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -749,9 +749,9 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
}
-void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
+void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
{
- this->optionsModel = optionsModel;
+ this->optionsModel = _optionsModel;
}
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 84ad0052fd..a820bd791f 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -24,6 +24,8 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
switch(column)
{
+ case PeerTableModel::NetNodeId:
+ return pLeft->nodeid < pRight->nodeid;
case PeerTableModel::Address:
return pLeft->addrName.compare(pRight->addrName) < 0;
case PeerTableModel::Subversion:
@@ -52,24 +54,21 @@ public:
void refreshPeers()
{
{
- TRY_LOCK(cs_vNodes, lockNodes);
- if (!lockNodes)
- {
- // skip the refresh if we can't immediately get the lock
- return;
- }
cachedNodeStats.clear();
+ std::vector<CNodeStats> vstats;
+ if(g_connman)
+ g_connman->GetNodeStats(vstats);
#if QT_VERSION >= 0x040700
- cachedNodeStats.reserve(vNodes.size());
+ cachedNodeStats.reserve(vstats.size());
#endif
- Q_FOREACH (CNode* pnode, vNodes)
+ Q_FOREACH (const CNodeStats& nodestats, vstats)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
stats.nodeStateStats.nSyncHeight = -1;
stats.nodeStateStats.nCommonHeight = -1;
stats.fNodeStateStatsAvailable = false;
- pnode->copyStats(stats.nodeStats);
+ stats.nodeStats = nodestats;
cachedNodeStats.append(stats);
}
}
@@ -114,7 +113,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
clientModel(parent),
timer(0)
{
- columns << tr("Node/Service") << tr("User Agent") << tr("Ping Time");
+ columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping Time");
priv = new PeerTablePriv();
// default to unsorted
priv->sortColumn = -1;
@@ -160,6 +159,8 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
switch(index.column())
{
+ case NetNodeId:
+ return rec->nodeStats.nodeid;
case Address:
return QString::fromStdString(rec->nodeStats.addrName);
case Subversion:
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index a2aaaa5d24..a4f7bbdb3d 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -52,9 +52,10 @@ public:
void stopAutoRefresh();
enum ColumnIndex {
- Address = 0,
- Subversion = 1,
- Ping = 2
+ NetNodeId = 0,
+ Address = 1,
+ Subversion = 2,
+ Ping = 3
};
/** @name Methods overridden from QAbstractTableModel
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index 11cbc7a47c..e4438cc43d 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -73,11 +73,11 @@ QIcon ColorizeIcon(const QString& filename, const QColor& colorbase)
}
-PlatformStyle::PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing):
- name(name),
- imagesOnButtons(imagesOnButtons),
- colorizeIcons(colorizeIcons),
- useExtraSpacing(useExtraSpacing),
+PlatformStyle::PlatformStyle(const QString &_name, bool _imagesOnButtons, bool _colorizeIcons, bool _useExtraSpacing):
+ name(_name),
+ imagesOnButtons(_imagesOnButtons),
+ colorizeIcons(_colorizeIcons),
+ useExtraSpacing(_useExtraSpacing),
singleColor(0,0,0),
textColor(0,0,0)
{
diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp
index baa2eb67f7..492b96ff09 100644
--- a/src/qt/qvalidatedlineedit.cpp
+++ b/src/qt/qvalidatedlineedit.cpp
@@ -15,14 +15,14 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
connect(this, SIGNAL(textChanged(QString)), this, SLOT(markValid()));
}
-void QValidatedLineEdit::setValid(bool valid)
+void QValidatedLineEdit::setValid(bool _valid)
{
- if(valid == this->valid)
+ if(_valid == this->valid)
{
return;
}
- if(valid)
+ if(_valid)
{
setStyleSheet("");
}
@@ -30,7 +30,7 @@ void QValidatedLineEdit::setValid(bool valid)
{
setStyleSheet(STYLE_INVALID);
}
- this->valid = valid;
+ this->valid = _valid;
}
void QValidatedLineEdit::focusInEvent(QFocusEvent *evt)
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index 146f3dd578..2f2478783c 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -20,9 +20,9 @@ void QValueComboBox::setValue(const QVariant &value)
setCurrentIndex(findData(value, role));
}
-void QValueComboBox::setRole(int role)
+void QValueComboBox::setRole(int _role)
{
- this->role = role;
+ this->role = _role;
}
void QValueComboBox::handleSelectionChanged(int idx)
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 0b355837ab..5c6dc97b20 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -22,24 +22,24 @@
#include <QScrollBar>
#include <QTextDocument>
-ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::ReceiveCoinsDialog),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
- if (!platformStyle->getImagesOnButtons()) {
+ if (!_platformStyle->getImagesOnButtons()) {
ui->clearButton->setIcon(QIcon());
ui->receiveButton->setIcon(QIcon());
ui->showRequestButton->setIcon(QIcon());
ui->removeRequestButton->setIcon(QIcon());
} else {
- ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
- ui->receiveButton->setIcon(platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
- ui->showRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
- ui->removeRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
+ ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
}
// context menu actions
@@ -62,21 +62,21 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidg
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
}
-void ReceiveCoinsDialog::setModel(WalletModel *model)
+void ReceiveCoinsDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model && model->getOptionsModel())
+ if(_model && _model->getOptionsModel())
{
- model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ _model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateDisplayUnit();
QTableView* tableView = ui->recentRequestsView;
tableView->verticalHeader()->hide();
tableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- tableView->setModel(model->getRecentRequestsTableModel());
+ tableView->setModel(_model->getRecentRequestsTableModel());
tableView->setAlternatingRowColors(true);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index b13ea3df70..998c9176d7 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -109,20 +109,20 @@ ReceiveRequestDialog::~ReceiveRequestDialog()
delete ui;
}
-void ReceiveRequestDialog::setModel(OptionsModel *model)
+void ReceiveRequestDialog::setModel(OptionsModel *_model)
{
- this->model = model;
+ this->model = _model;
- if (model)
- connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(update()));
+ if (_model)
+ connect(_model, SIGNAL(displayUnitChanged(int)), this, SLOT(update()));
// update the display unit if necessary
update();
}
-void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &info)
+void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &_info)
{
- this->info = info;
+ this->info = _info;
update();
}
diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh
index a4c2fddbbf..d0deb1238c 100755
--- a/src/qt/res/movies/makespinner.sh
+++ b/src/qt/res/movies/makespinner.sh
@@ -1,3 +1,7 @@
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
FRAMEDIR=$(dirname $0)
for i in {0..35}
do
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index bcaa9164c9..ace9f1ceaa 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -83,8 +83,8 @@ class QtRPCTimerBase: public QObject, public RPCTimerBase
{
Q_OBJECT
public:
- QtRPCTimerBase(boost::function<void(void)>& func, int64_t millis):
- func(func)
+ QtRPCTimerBase(boost::function<void(void)>& _func, int64_t millis):
+ func(_func)
{
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
@@ -113,9 +113,11 @@ public:
#include "rpcconsole.moc"
/**
- * Split shell command line into a list of arguments. Aims to emulate \c bash and friends.
+ * Split shell command line into a list of arguments and execute the command(s).
+ * Aims to emulate \c bash and friends.
*
- * - Arguments are delimited with whitespace
+ * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())]
+ * - Arguments are delimited with whitespace or comma
* - Extra whitespace at the beginning and end and between arguments will be ignored
* - Text can be "double" or 'single' quoted
* - The backslash \c \ is used as escape character
@@ -123,11 +125,15 @@ public:
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
* - Within single quotes, no escaping is possible and no special interpretation takes place
*
- * @param[out] args Parsed arguments will be appended to this list
+ * @param[out] result stringified Result from the executed command(chain)
* @param[in] strCommand Command line to split
*/
-bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand)
+
+bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand)
{
+ std::vector< std::vector<std::string> > stack;
+ stack.push_back(std::vector<std::string>());
+
enum CmdParseState
{
STATE_EATING_SPACES,
@@ -135,95 +141,180 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm
STATE_SINGLEQUOTED,
STATE_DOUBLEQUOTED,
STATE_ESCAPE_OUTER,
- STATE_ESCAPE_DOUBLEQUOTED
+ STATE_ESCAPE_DOUBLEQUOTED,
+ STATE_COMMAND_EXECUTED,
+ STATE_COMMAND_EXECUTED_INNER
} state = STATE_EATING_SPACES;
std::string curarg;
- Q_FOREACH(char ch, strCommand)
+ UniValue lastResult;
+
+ std::string strCommandTerminated = strCommand;
+ if (strCommandTerminated.back() != '\n')
+ strCommandTerminated += "\n";
+ for(char ch: strCommandTerminated)
{
switch(state)
{
- case STATE_ARGUMENT: // In or after argument
- case STATE_EATING_SPACES: // Handle runs of whitespace
- switch(ch)
+ case STATE_COMMAND_EXECUTED_INNER:
+ case STATE_COMMAND_EXECUTED:
{
- case '"': state = STATE_DOUBLEQUOTED; break;
- case '\'': state = STATE_SINGLEQUOTED; break;
- case '\\': state = STATE_ESCAPE_OUTER; break;
- case ' ': case '\n': case '\t':
- if(state == STATE_ARGUMENT) // Space ends argument
+ bool breakParsing = true;
+ switch(ch)
{
- args.push_back(curarg);
- curarg.clear();
+ case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;
+ default:
+ if (state == STATE_COMMAND_EXECUTED_INNER)
+ {
+ if (ch != ']')
+ {
+ // append char to the current argument (which is also used for the query command)
+ curarg += ch;
+ break;
+ }
+ if (curarg.size())
+ {
+ // if we have a value query, query arrays with index and objects with a string key
+ UniValue subelement;
+ if (lastResult.isArray())
+ {
+ for(char argch: curarg)
+ if (!std::isdigit(argch))
+ throw std::runtime_error("Invalid result query");
+ subelement = lastResult[atoi(curarg.c_str())];
+ }
+ else if (lastResult.isObject())
+ subelement = find_value(lastResult, curarg);
+ else
+ throw std::runtime_error("Invalid result query"); //no array or object: abort
+ lastResult = subelement;
+ }
+
+ state = STATE_COMMAND_EXECUTED;
+ break;
+ }
+ // don't break parsing when the char is required for the next argument
+ breakParsing = false;
+
+ // pop the stack and return the result to the current command arguments
+ stack.pop_back();
+
+ // don't stringify the json in case of a string to avoid doublequotes
+ if (lastResult.isStr())
+ curarg = lastResult.get_str();
+ else
+ curarg = lastResult.write(2);
+
+ // if we have a non empty result, use it as stack argument otherwise as general result
+ if (curarg.size())
+ {
+ if (stack.size())
+ stack.back().push_back(curarg);
+ else
+ strResult = curarg;
+ }
+ curarg.clear();
+ // assume eating space state
+ state = STATE_EATING_SPACES;
}
- state = STATE_EATING_SPACES;
- break;
- default: curarg += ch; state = STATE_ARGUMENT;
+ if (breakParsing)
+ break;
}
- break;
- case STATE_SINGLEQUOTED: // Single-quoted string
- switch(ch)
+ case STATE_ARGUMENT: // In or after argument
+ case STATE_EATING_SPACES: // Handle runs of whitespace
+ switch(ch)
{
- case '\'': state = STATE_ARGUMENT; break;
- default: curarg += ch;
+ case '"': state = STATE_DOUBLEQUOTED; break;
+ case '\'': state = STATE_SINGLEQUOTED; break;
+ case '\\': state = STATE_ESCAPE_OUTER; break;
+ case '(': case ')': case '\n':
+ if (state == STATE_ARGUMENT)
+ {
+ if (ch == '(' && stack.size() && stack.back().size() > 0)
+ stack.push_back(std::vector<std::string>());
+ if (curarg.size())
+ {
+ // don't allow commands after executed commands on baselevel
+ if (!stack.size())
+ throw std::runtime_error("Invalid Syntax");
+ stack.back().push_back(curarg);
+ }
+ curarg.clear();
+ state = STATE_EATING_SPACES;
+ }
+ if ((ch == ')' || ch == '\n') && stack.size() > 0)
+ {
+ std::string strPrint;
+ // Convert argument list to JSON objects in method-dependent way,
+ // and pass it along with the method name to the dispatcher.
+ lastResult = tableRPC.execute(stack.back()[0], RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end())));
+
+ state = STATE_COMMAND_EXECUTED;
+ curarg.clear();
+ }
+ break;
+ case ' ': case ',': case '\t':
+ if(state == STATE_ARGUMENT) // Space ends argument
+ {
+ if (curarg.size())
+ stack.back().push_back(curarg);
+ curarg.clear();
+ }
+ state = STATE_EATING_SPACES;
+ break;
+ default: curarg += ch; state = STATE_ARGUMENT;
}
- break;
- case STATE_DOUBLEQUOTED: // Double-quoted string
- switch(ch)
+ break;
+ case STATE_SINGLEQUOTED: // Single-quoted string
+ switch(ch)
{
- case '"': state = STATE_ARGUMENT; break;
- case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
- default: curarg += ch;
+ case '\'': state = STATE_ARGUMENT; break;
+ default: curarg += ch;
}
- break;
- case STATE_ESCAPE_OUTER: // '\' outside quotes
- curarg += ch; state = STATE_ARGUMENT;
- break;
- case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
- if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
- curarg += ch; state = STATE_DOUBLEQUOTED;
- break;
+ break;
+ case STATE_DOUBLEQUOTED: // Double-quoted string
+ switch(ch)
+ {
+ case '"': state = STATE_ARGUMENT; break;
+ case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
+ default: curarg += ch;
+ }
+ break;
+ case STATE_ESCAPE_OUTER: // '\' outside quotes
+ curarg += ch; state = STATE_ARGUMENT;
+ break;
+ case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
+ if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
+ curarg += ch; state = STATE_DOUBLEQUOTED;
+ break;
}
}
switch(state) // final state
{
- case STATE_EATING_SPACES:
- return true;
- case STATE_ARGUMENT:
- args.push_back(curarg);
- return true;
- default: // ERROR to end in one of the other states
- return false;
+ case STATE_COMMAND_EXECUTED:
+ if (lastResult.isStr())
+ strResult = lastResult.get_str();
+ else
+ strResult = lastResult.write(2);
+ case STATE_ARGUMENT:
+ case STATE_EATING_SPACES:
+ return true;
+ default: // ERROR to end in one of the other states
+ return false;
}
}
void RPCExecutor::request(const QString &command)
{
- std::vector<std::string> args;
- if(!parseCommandLine(args, command.toStdString()))
- {
- Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
- return;
- }
- if(args.empty())
- return; // Nothing to do
try
{
- std::string strPrint;
- // Convert argument list to JSON objects in method-dependent way,
- // and pass it along with the method name to the dispatcher.
- UniValue result = tableRPC.execute(
- args[0],
- RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
-
- // Format result reply
- if (result.isNull())
- strPrint = "";
- else if (result.isStr())
- strPrint = result.get_str();
- else
- strPrint = result.write(2);
-
- Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
+ std::string result;
+ std::string executableCommand = command.toStdString() + "\n";
+ if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand))
+ {
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
+ return;
+ }
+ Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
}
catch (UniValue& objError)
{
@@ -244,13 +335,13 @@ void RPCExecutor::request(const QString &command)
}
}
-RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
+RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::RPCConsole),
clientModel(0),
historyPtr(0),
cachedNodeid(-1),
- platformStyle(platformStyle),
+ platformStyle(_platformStyle),
peersTableContextMenu(0),
banTableContextMenu(0),
consoleFontSize(0)
@@ -876,37 +967,34 @@ void RPCConsole::showBanTableContextMenu(const QPoint& point)
void RPCConsole::disconnectSelectedNode()
{
+ if(!g_connman)
+ return;
// Get currently selected peer address
- QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ NodeId id = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::NetNodeId).toInt();
// Find the node, disconnect it and clear the selected node
- if (CNode *bannedNode = FindNode(strNode.toStdString())) {
- bannedNode->fDisconnect = true;
+ if(g_connman->DisconnectNode(id))
clearSelectedNode();
- }
}
void RPCConsole::banSelectedNode(int bantime)
{
- if (!clientModel)
+ if (!clientModel || !g_connman)
return;
// Get currently selected peer address
- QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address).toString();
// Find possible nodes, ban it and clear the selected node
- if (FindNode(strNode.toStdString())) {
- std::string nStr = strNode.toStdString();
- std::string addr;
- int port = 0;
- SplitHostPort(nStr, port, addr);
-
- CNetAddr resolved;
- if(!LookupHost(addr.c_str(), resolved, false))
- return;
- CNode::Ban(resolved, BanReasonManuallyAdded, bantime);
+ std::string nStr = strNode.toStdString();
+ std::string addr;
+ int port = 0;
+ SplitHostPort(nStr, port, addr);
- clearSelectedNode();
- clientModel->getBanTableModel()->refresh();
- }
+ CNetAddr resolved;
+ if(!LookupHost(addr.c_str(), resolved, false))
+ return;
+ g_connman->Ban(resolved, BanReasonManuallyAdded, bantime);
+ clearSelectedNode();
+ clientModel->getBanTableModel()->refresh();
}
void RPCConsole::unbanSelectedNode()
@@ -915,13 +1003,13 @@ void RPCConsole::unbanSelectedNode()
return;
// Get currently selected ban address
- QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address);
+ QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address).toString();
CSubNet possibleSubnet;
LookupSubNet(strNode.toStdString().c_str(), possibleSubnet);
- if (possibleSubnet.IsValid())
+ if (possibleSubnet.IsValid() && g_connman)
{
- CNode::Unban(possibleSubnet);
+ g_connman->Unban(possibleSubnet);
clientModel->getBanTableModel()->refresh();
}
}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 28affa954d..50224a1cc0 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -35,6 +35,8 @@ public:
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
+ static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand);
+
void setClientModel(ClientModel *model);
enum MessageClass {
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 3e96bb18c3..4b2ba7d624 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -30,25 +30,25 @@
#define SEND_CONFIRM_DELAY 3
-SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
clientModel(0),
model(0),
fNewRecipientAllowed(true),
fFeeMinimized(true),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
- if (!platformStyle->getImagesOnButtons()) {
+ if (!_platformStyle->getImagesOnButtons()) {
ui->addButton->setIcon(QIcon());
ui->clearButton->setIcon(QIcon());
ui->sendButton->setIcon(QIcon());
} else {
- ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
- ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
- ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send"));
+ ui->addButton->setIcon(_platformStyle->SingleColorIcon(":/icons/add"));
+ ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->sendButton->setIcon(_platformStyle->SingleColorIcon(":/icons/send"));
}
GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
@@ -116,40 +116,40 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *pa
minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool());
}
-void SendCoinsDialog::setClientModel(ClientModel *clientModel)
+void SendCoinsDialog::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
+ this->clientModel = _clientModel;
- if (clientModel) {
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel()));
+ if (_clientModel) {
+ connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(updateSmartFeeLabel()));
}
}
-void SendCoinsDialog::setModel(WalletModel *model)
+void SendCoinsDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if(model && model->getOptionsModel())
+ if(_model && _model->getOptionsModel())
{
for(int i = 0; i < ui->entries->count(); ++i)
{
SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if(entry)
{
- entry->setModel(model);
+ entry->setModel(_model);
}
}
- setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(),
- model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance());
- connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ setBalance(_model->getBalance(), _model->getUnconfirmedBalance(), _model->getImmatureBalance(),
+ _model->getWatchBalance(), _model->getWatchUnconfirmedBalance(), _model->getWatchImmatureBalance());
+ connect(_model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)));
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateDisplayUnit();
// Coin Control
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels()));
- connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool)));
- ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures());
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels()));
+ connect(_model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool)));
+ ui->frameCoinControl->setVisible(_model->getOptionsModel()->getCoinControlFeatures());
coinControlUpdateLabels();
// fee section
@@ -589,6 +589,9 @@ void SendCoinsDialog::updateGlobalFeeVariables()
{
nTxConfirmTarget = defaultConfirmTarget - ui->sliderSmartFee->value();
payTxFee = CFeeRate(0);
+
+ // set nMinimumTotalFee to 0 to not accidentally pay a custom fee
+ CoinControlDialog::coinControl->nMinimumTotalFee = 0;
}
else
{
@@ -781,7 +784,7 @@ void SendCoinsDialog::coinControlUpdateLabels()
ui->radioCustomAtLeast->setVisible(true);
// only enable the feature if inputs are selected
- ui->radioCustomAtLeast->setEnabled(CoinControlDialog::coinControl->HasSelected());
+ ui->radioCustomAtLeast->setEnabled(ui->radioCustomFee->isChecked() && !ui->checkBoxMinimumFee->isChecked() &&CoinControlDialog::coinControl->HasSelected());
}
else
{
@@ -823,9 +826,9 @@ void SendCoinsDialog::coinControlUpdateLabels()
}
}
-SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int secDelay,
+SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay,
QWidget *parent) :
- QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(secDelay)
+ QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
{
setDefaultButton(QMessageBox::Cancel);
yesButton = button(QMessageBox::Yes);
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index d063f2c891..7eb1eb7e3a 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -15,11 +15,11 @@
#include <QApplication>
#include <QClipboard>
-SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) :
+SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) :
QStackedWidget(parent),
ui(new Ui::SendCoinsEntry),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -79,12 +79,12 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
updateLabel(address);
}
-void SendCoinsEntry::setModel(WalletModel *model)
+void SendCoinsEntry::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
- if (model && model->getOptionsModel())
- connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
+ if (_model && _model->getOptionsModel())
+ connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
clear();
}
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 8e2e8a5098..4061909b71 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -20,11 +20,11 @@
#include <QClipboard>
-SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent) :
+SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SignVerifyMessageDialog),
model(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
ui->setupUi(this);
@@ -60,9 +60,9 @@ SignVerifyMessageDialog::~SignVerifyMessageDialog()
delete ui;
}
-void SignVerifyMessageDialog::setModel(WalletModel *model)
+void SignVerifyMessageDialog::setModel(WalletModel *_model)
{
- this->model = model;
+ this->model = _model;
}
void SignVerifyMessageDialog::setAddress_SM(const QString &address)
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
new file mode 100644
index 0000000000..3dae33bafb
--- /dev/null
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -0,0 +1,93 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "rpcnestedtests.h"
+
+#include "chainparams.h"
+#include "consensus/validation.h"
+#include "main.h"
+#include "rpc/register.h"
+#include "rpc/server.h"
+#include "rpcconsole.h"
+#include "test/testutil.h"
+#include "univalue.h"
+#include "util.h"
+
+#include <QDir>
+
+#include <boost/filesystem.hpp>
+
+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();
+ RegisterAllCoreRPCCommands(tableRPC);
+ ClearDatadirCache();
+ std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
+ QDir dir(QString::fromStdString(path));
+ dir.mkpath(".");
+ mapArgs["-datadir"] = path;
+ //mempool.setSanityCheck(1.0);
+ pblocktree = new CBlockTreeDB(1 << 20, true);
+ pcoinsdbview = new CCoinsViewDB(1 << 23, true);
+ pcoinsTip = new CCoinsViewCache(pcoinsdbview);
+ InitBlockIndex(chainparams);
+ {
+ CValidationState state;
+ bool ok = ActivateBestChain(state, chainparams);
+ QVERIFY(ok);
+ }
+
+ SetRPCWarmupFinished();
+
+ std::string result;
+ std::string result2;
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]"); //simple result filtering with path
+ QVERIFY(result=="main");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo");
+ QVERIFY(result.substr(0,1) == "{");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()");
+ QVERIFY(result.substr(0,1) == "{");
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
+ QVERIFY(result.substr(0,1) == "{");
+
+#if QT_VERSION >= 0x050300
+ // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
+#endif
+
+ (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
+ QVERIFY(result == "null");
+
+ (RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
+ (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
+ QVERIFY(result == result2);
+ (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed
+ QVERIFY(result == result2);
+
+ RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]");
+ QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
+
+ delete pcoinsTip;
+ delete pcoinsdbview;
+ delete pblocktree;
+
+ boost::filesystem::remove_all(boost::filesystem::path(path));
+}
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
new file mode 100644
index 0000000000..9ad409019f
--- /dev/null
+++ b/src/qt/test/rpcnestedtests.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
+#define BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
+
+#include <QObject>
+#include <QTest>
+
+#include "txdb.h"
+#include "txmempool.h"
+
+class RPCNestedTests : public QObject
+{
+ Q_OBJECT
+
+ private Q_SLOTS:
+ void rpcNestedTests();
+
+private:
+ CCoinsViewDB *pcoinsdbview;
+};
+
+#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index db193420bf..dbaab54fb6 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -6,6 +6,9 @@
#include "config/bitcoin-config.h"
#endif
+#include "chainparams.h"
+#include "key.h"
+#include "rpcnestedtests.h"
#include "util.h"
#include "uritests.h"
@@ -27,10 +30,17 @@ Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
#endif
+extern void noui_connect();
+
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
+ ECC_Start();
SetupEnvironment();
+ SetupNetworking();
+ SelectParams(CBaseChainParams::MAIN);
+ noui_connect();
+
bool fInvalid = false;
// Don't remove this, it's needed to access
@@ -48,6 +58,10 @@ int main(int argc, char *argv[])
if (QTest::qExec(&test2) != 0)
fInvalid = true;
#endif
+ RPCNestedTests test3;
+ if (QTest::qExec(&test3) != 0)
+ fInvalid = true;
+ ECC_Stop();
return fInvalid;
}
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index bae0cbd1c8..65144e7865 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -241,6 +241,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + rec->getTxID() + "<br>";
+ strHTML += "<b>" + tr("Transaction total size") + ":</b> " + QString::number(wtx.GetTotalSize()) + " bytes<br>";
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 9dcb72f55e..e21b89b935 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -66,9 +66,9 @@ void TransactionFilterProxy::setDateRange(const QDateTime &from, const QDateTime
invalidateFilter();
}
-void TransactionFilterProxy::setAddressPrefix(const QString &addrPrefix)
+void TransactionFilterProxy::setAddressPrefix(const QString &_addrPrefix)
{
- this->addrPrefix = addrPrefix;
+ this->addrPrefix = _addrPrefix;
invalidateFilter();
}
@@ -95,9 +95,9 @@ void TransactionFilterProxy::setLimit(int limit)
this->limitRows = limit;
}
-void TransactionFilterProxy::setShowInactive(bool showInactive)
+void TransactionFilterProxy::setShowInactive(bool _showInactive)
{
- this->showInactive = showInactive;
+ this->showInactive = _showInactive;
invalidateFilter();
}
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index 8c754c3aad..8eff302aff 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -88,16 +88,16 @@ public:
{
}
- TransactionRecord(uint256 hash, qint64 time):
- hash(hash), time(time), type(Other), address(""), debit(0),
+ TransactionRecord(uint256 _hash, qint64 _time):
+ hash(_hash), time(_time), type(Other), address(""), debit(0),
credit(0), idx(0)
{
}
- TransactionRecord(uint256 hash, qint64 time,
- Type type, const std::string &address,
- const CAmount& debit, const CAmount& credit):
- hash(hash), time(time), type(type), address(address), debit(debit), credit(credit),
+ TransactionRecord(uint256 _hash, qint64 _time,
+ Type _type, const std::string &_address,
+ const CAmount& _debit, const CAmount& _credit):
+ hash(_hash), time(_time), type(_type), address(_address), debit(_debit), credit(_credit),
idx(0)
{
}
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index b29ecf8348..52261ff04b 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -59,9 +59,9 @@ struct TxLessThan
class TransactionTablePriv
{
public:
- TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent) :
- wallet(wallet),
- parent(parent)
+ TransactionTablePriv(CWallet *_wallet, TransactionTableModel *_parent) :
+ wallet(_wallet),
+ parent(_parent)
{
}
@@ -235,13 +235,13 @@ public:
}
};
-TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent):
+TransactionTableModel::TransactionTableModel(const PlatformStyle *_platformStyle, CWallet* _wallet, WalletModel *parent):
QAbstractTableModel(parent),
- wallet(wallet),
+ wallet(_wallet),
walletModel(parent),
- priv(new TransactionTablePriv(wallet, this)),
+ priv(new TransactionTablePriv(_wallet, this)),
fProcessingQueuedTransactions(false),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet();
@@ -714,8 +714,8 @@ struct TransactionNotification
{
public:
TransactionNotification() {}
- TransactionNotification(uint256 hash, ChangeType status, bool showTransaction):
- hash(hash), status(status), showTransaction(showTransaction) {}
+ TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
+ hash(_hash), status(_status), showTransaction(_showTransaction) {}
void invoke(QObject *ttm)
{
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 48cf940502..856b16d2c4 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -184,13 +184,13 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa
connect(showDetailsAction, SIGNAL(triggered()), this, SLOT(showDetails()));
}
-void TransactionView::setModel(WalletModel *model)
+void TransactionView::setModel(WalletModel *_model)
{
- this->model = model;
- if(model)
+ this->model = _model;
+ if(_model)
{
transactionProxyModel = new TransactionFilterProxy(this);
- transactionProxyModel->setSourceModel(model->getTransactionTableModel());
+ transactionProxyModel->setSourceModel(_model->getTransactionTableModel());
transactionProxyModel->setDynamicSortFilter(true);
transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
@@ -214,10 +214,10 @@ void TransactionView::setModel(WalletModel *model)
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH);
- if (model->getOptionsModel())
+ if (_model->getOptionsModel())
{
// Add third party transaction URLs to context menu
- QStringList listUrls = model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
+ QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
for (int i = 0; i < listUrls.size(); ++i)
{
QString host = QUrl(listUrls[i].trimmed(), QUrl::StrictMode).host();
@@ -234,10 +234,10 @@ void TransactionView::setModel(WalletModel *model)
}
// show/hide column Watch-only
- updateWatchOnlyColumn(model->haveWatchOnly());
+ updateWatchOnlyColumn(_model->haveWatchOnly());
// Watch-only signal
- connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
+ connect(_model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
}
}
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 518d9ea90a..69dcc9abb1 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -12,10 +12,10 @@
#include <QHBoxLayout>
#include <QLabel>
-WalletFrame::WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui) :
+WalletFrame::WalletFrame(const PlatformStyle *_platformStyle, BitcoinGUI *_gui) :
QFrame(_gui),
gui(_gui),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
// Leave HBox hook for adding a list view later
QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
@@ -33,9 +33,9 @@ WalletFrame::~WalletFrame()
{
}
-void WalletFrame::setClientModel(ClientModel *clientModel)
+void WalletFrame::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
+ this->clientModel = _clientModel;
}
bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel)
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index ae7efc7a0d..c8a2cb37ec 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -27,8 +27,8 @@
#include <boost/foreach.hpp>
-WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
- QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
+WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *_wallet, OptionsModel *_optionsModel, QObject *parent) :
+ QObject(parent), wallet(_wallet), optionsModel(_optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
@@ -328,7 +328,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
}
CReserveKey *keyChange = transaction.getPossibleKeyChange();
- if(!wallet->CommitTransaction(*newTx, *keyChange))
+ if(!wallet->CommitTransaction(*newTx, *keyChange, g_connman.get()))
return TransactionCommitFailed;
CTransaction* t = (CTransaction*)newTx;
@@ -531,10 +531,10 @@ WalletModel::UnlockContext WalletModel::requestUnlock()
return UnlockContext(this, valid, was_locked);
}
-WalletModel::UnlockContext::UnlockContext(WalletModel *wallet, bool valid, bool relock):
- wallet(wallet),
- valid(valid),
- relock(relock)
+WalletModel::UnlockContext::UnlockContext(WalletModel *_wallet, bool _valid, bool _relock):
+ wallet(_wallet),
+ valid(_valid),
+ relock(_relock)
{
}
@@ -684,6 +684,11 @@ bool WalletModel::abandonTransaction(uint256 hash) const
return wallet->AbandonTransaction(hash);
}
+bool WalletModel::isWalletEnabled()
+{
+ return !GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET);
+}
+
bool WalletModel::hdEnabled() const
{
return wallet->IsHDEnabled();
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index a15ecf899b..e233fa690d 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -38,8 +38,8 @@ class SendCoinsRecipient
{
public:
explicit SendCoinsRecipient() : amount(0), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) { }
- explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message):
- address(addr), label(label), amount(amount), message(message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
+ explicit SendCoinsRecipient(const QString &addr, const QString &_label, const CAmount& _amount, const QString &_message):
+ address(addr), label(_label), amount(_amount), message(_message), fSubtractFeeFromAmount(false), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
// If from an unauthenticated payment request, this is used for storing
// the addresses, e.g. address-A<br />address-B<br />address-C.
@@ -145,8 +145,8 @@ public:
// Return status record for SendCoins, contains error id + information
struct SendCoinsReturn
{
- SendCoinsReturn(StatusCode status = OK):
- status(status) {}
+ SendCoinsReturn(StatusCode _status = OK):
+ status(_status) {}
StatusCode status;
};
@@ -203,6 +203,8 @@ public:
bool transactionCanBeAbandoned(uint256 hash) const;
bool abandonTransaction(uint256 hash) const;
+ static bool isWalletEnabled();
+
bool hdEnabled() const;
private:
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index ffadf89cc8..fdec6a1c86 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -7,8 +7,8 @@
#include "policy/policy.h"
#include "wallet/wallet.h"
-WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &recipients) :
- recipients(recipients),
+WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
+ recipients(_recipients),
walletTransaction(0),
keyChange(0),
fee(0)
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index b163ce3dcf..a9518413c2 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -29,11 +29,11 @@
#include <QPushButton>
#include <QVBoxLayout>
-WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent):
+WalletView::WalletView(const PlatformStyle *_platformStyle, QWidget *parent):
QStackedWidget(parent),
clientModel(0),
walletModel(0),
- platformStyle(platformStyle)
+ platformStyle(_platformStyle)
{
// Create tabs
overviewPage = new OverviewPage(platformStyle);
@@ -105,47 +105,47 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui)
}
}
-void WalletView::setClientModel(ClientModel *clientModel)
+void WalletView::setClientModel(ClientModel *_clientModel)
{
- this->clientModel = clientModel;
+ this->clientModel = _clientModel;
- overviewPage->setClientModel(clientModel);
- sendCoinsPage->setClientModel(clientModel);
+ overviewPage->setClientModel(_clientModel);
+ sendCoinsPage->setClientModel(_clientModel);
}
-void WalletView::setWalletModel(WalletModel *walletModel)
+void WalletView::setWalletModel(WalletModel *_walletModel)
{
- this->walletModel = walletModel;
+ this->walletModel = _walletModel;
// Put transaction list in tabs
- transactionView->setModel(walletModel);
- overviewPage->setWalletModel(walletModel);
- receiveCoinsPage->setModel(walletModel);
- sendCoinsPage->setModel(walletModel);
- usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel());
- usedSendingAddressesPage->setModel(walletModel->getAddressTableModel());
-
- if (walletModel)
+ transactionView->setModel(_walletModel);
+ overviewPage->setWalletModel(_walletModel);
+ receiveCoinsPage->setModel(_walletModel);
+ sendCoinsPage->setModel(_walletModel);
+ usedReceivingAddressesPage->setModel(_walletModel->getAddressTableModel());
+ usedSendingAddressesPage->setModel(_walletModel->getAddressTableModel());
+
+ if (_walletModel)
{
// Receive and pass through messages from wallet model
- connect(walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int)));
+ connect(_walletModel, SIGNAL(message(QString,QString,unsigned int)), this, SIGNAL(message(QString,QString,unsigned int)));
// Handle changes in encryption status
- connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int)));
+ connect(_walletModel, SIGNAL(encryptionStatusChanged(int)), this, SIGNAL(encryptionStatusChanged(int)));
updateEncryptionStatus();
// update HD status
- Q_EMIT hdEnabledStatusChanged(walletModel->hdEnabled());
+ Q_EMIT hdEnabledStatusChanged(_walletModel->hdEnabled());
// Balloon pop-up for new transaction
- connect(walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
+ connect(_walletModel->getTransactionTableModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(processNewTransaction(QModelIndex,int,int)));
// Ask for passphrase if needed
- connect(walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
+ connect(_walletModel, SIGNAL(requireUnlock()), this, SLOT(unlockWallet()));
// Show progress dialog
- connect(walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
+ connect(_walletModel, SIGNAL(showProgress(QString,int)), this, SLOT(showProgress(QString,int)));
}
}
diff --git a/src/rest.cpp b/src/rest.cpp
index 2dff8d7dad..c815592124 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -420,7 +420,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// throw exception in case of a empty request
std::string strRequestMutable = req->ReadBody();
if (strRequestMutable.length() == 0 && uriParts.size() == 0)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
bool fInputParsed = false;
bool fCheckMemPool = false;
@@ -444,7 +444,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1);
if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
txid.SetHex(strTxid);
vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
@@ -453,7 +453,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (vOutPoints.size() > 0)
fInputParsed = true;
else
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
}
switch (rf) {
@@ -469,7 +469,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (strRequestMutable.size() > 0)
{
if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Combination of URI scheme inputs and raw post data is not allowed");
CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
oss << strRequestMutable;
@@ -478,14 +478,14 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
}
} catch (const std::ios_base::failure& e) {
// abort in case of unreadable binary data
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Parse error");
}
break;
}
case RF_JSON: {
if (!fInputParsed)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ return RESTERR(req, HTTP_BAD_REQUEST, "Error: empty request");
break;
}
default: {
@@ -495,7 +495,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// limit max outpoints
if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
- return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
+ return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
// check spentness and form a bitmap (as well as a JSON capable human-readable string representation)
vector<unsigned char> bitmap;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index e3c32d905a..f05f8ff358 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -26,8 +26,20 @@
#include <boost/thread/thread.hpp> // boost::thread::interrupt
+#include <mutex>
+#include <condition_variable>
using namespace std;
+struct CUpdatedBlock
+{
+ uint256 hash;
+ int height;
+};
+
+static std::mutex cs_blockchange;
+static std::condition_variable cond_blockchange;
+static CUpdatedBlock latestblock;
+
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
@@ -168,6 +180,138 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp)
return chainActive.Tip()->GetBlockHash().GetHex();
}
+void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
+{
+ if(pindex) {
+ std::lock_guard<std::mutex> lock(cs_blockchange);
+ latestblock.hash = pindex->GetBlockHash();
+ latestblock.height = pindex->nHeight;
+ }
+ cond_blockchange.notify_all();
+}
+
+UniValue waitfornewblock(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() > 1)
+ throw runtime_error(
+ "waitfornewblock\n"
+ "\nWaits for a specific new block and returns useful info about it.\n"
+ "\nReturns the current block on timeout or exit.\n"
+ "\nArguments:\n"
+ "1. timeout (milliseconds) (int, optional, default=false)\n"
+ "\nResult::\n"
+ "{ (json object)\n"
+ " \"hash\" : { (string) The blockhash\n"
+ " \"height\" : { (int) Block height\n"
+ "}\n"
+ "\nExamples\n"
+ + HelpExampleCli("waitfornewblock", "1000")
+ + HelpExampleRpc("waitfornewblock", "1000")
+ );
+ int timeout = 0;
+ if (params.size() > 0)
+ timeout = params[0].get_int();
+
+ CUpdatedBlock block;
+ {
+ std::unique_lock<std::mutex> lock(cs_blockchange);
+ block = latestblock;
+ if(timeout)
+ cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
+ else
+ cond_blockchange.wait(lock, [&block]{return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
+ block = latestblock;
+ }
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("hash", block.hash.GetHex()));
+ ret.push_back(Pair("height", block.height));
+ return ret;
+}
+
+UniValue waitforblock(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "waitforblock\n"
+ "\nWaits for a specific new block and returns useful info about it.\n"
+ "\nReturns the current block on timeout or exit.\n"
+ "\nArguments:\n"
+ "1. blockhash to wait for (string)\n"
+ "2. timeout (milliseconds) (int, optional, default=false)\n"
+ "\nResult::\n"
+ "{ (json object)\n"
+ " \"hash\" : { (string) The blockhash\n"
+ " \"height\" : { (int) Block height\n"
+ "}\n"
+ "\nExamples\n"
+ + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
+ );
+ int timeout = 0;
+
+ uint256 hash = uint256S(params[0].get_str());
+
+ if (params.size() > 1)
+ timeout = params[1].get_int();
+
+ CUpdatedBlock block;
+ {
+ std::unique_lock<std::mutex> lock(cs_blockchange);
+ if(timeout)
+ cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]{return latestblock.hash == hash || !IsRPCRunning();});
+ else
+ cond_blockchange.wait(lock, [&hash]{return latestblock.hash == hash || !IsRPCRunning(); });
+ block = latestblock;
+ }
+
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("hash", block.hash.GetHex()));
+ ret.push_back(Pair("height", block.height));
+ return ret;
+}
+
+UniValue waitforblockheight(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "waitforblock\n"
+ "\nWaits for (at least) block height and returns the height and hash\n"
+ "\nof the current tip.\n"
+ "\nReturns the current block on timeout or exit.\n"
+ "\nArguments:\n"
+ "1. block height to wait for (int)\n"
+ "2. timeout (milliseconds) (int, optional, default=false)\n"
+ "\nResult::\n"
+ "{ (json object)\n"
+ " \"hash\" : { (string) The blockhash\n"
+ " \"height\" : { (int) Block height\n"
+ "}\n"
+ "\nExamples\n"
+ + HelpExampleCli("waitforblockheight", "\"100\", 1000")
+ + HelpExampleRpc("waitforblockheight", "\"100\", 1000")
+ );
+ int timeout = 0;
+
+ int height = params[0].get_int();
+
+ if (params.size() > 1)
+ timeout = params[1].get_int();
+
+ CUpdatedBlock block;
+ {
+ std::unique_lock<std::mutex> lock(cs_blockchange);
+ if(timeout)
+ cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]{return latestblock.height >= height || !IsRPCRunning();});
+ else
+ cond_blockchange.wait(lock, [&height]{return latestblock.height >= height || !IsRPCRunning(); });
+ block = latestblock;
+ }
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("hash", block.hash.GetHex()));
+ ret.push_back(Pair("height", block.height));
+ return ret;
+}
+
UniValue getdifficulty(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -632,7 +776,7 @@ struct CCoinsStats
//! Calculate statistics about the unspent transaction output set
static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
{
- boost::scoped_ptr<CCoinsViewCursor> pcursor(view->Cursor());
+ std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
stats.hashBlock = pcursor->GetBestBlock();
@@ -1133,7 +1277,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
}
if (state.IsValid()) {
- ActivateBestChain(state, Params());
+ ActivateBestChain(state, Params(), NULL, g_connman.get());
}
if (!state.IsValid()) {
@@ -1171,7 +1315,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
}
CValidationState state;
- ActivateBestChain(state, Params());
+ ActivateBestChain(state, Params(), NULL, g_connman.get());
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
@@ -1203,10 +1347,13 @@ static const CRPCCommand commands[] =
/* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, true },
{ "hidden", "reconsiderblock", &reconsiderblock, true },
+ { "hidden", "waitfornewblock", &waitfornewblock, true },
+ { "hidden", "waitforblock", &waitforblock, true },
+ { "hidden", "waitforblockheight", &waitforblockheight, true },
};
-void RegisterBlockchainRPCCommands(CRPCTable &tableRPC)
+void RegisterBlockchainRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index d0675fdb49..c14d9d6747 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -26,7 +26,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{
{ "stop", 0 },
{ "setmocktime", 0 },
- { "getaddednodeinfo", 0 },
{ "generate", 0 },
{ "generate", 1 },
{ "generatetoaddress", 0 },
@@ -47,6 +46,12 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getbalance", 1 },
{ "getbalance", 2 },
{ "getblockhash", 0 },
+ { "waitforblockheight", 0 },
+ { "waitforblockheight", 1 },
+ { "waitforblock", 1 },
+ { "waitforblock", 2 },
+ { "waitfornewblock", 0 },
+ { "waitfornewblock", 1 },
{ "move", 2 },
{ "move", 3 },
{ "sendfrom", 2 },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index a26340f3e4..7794ac619d 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
continue;
}
CValidationState state;
- if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
+ if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, g_connman.get()))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -457,7 +457,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
- if (vNodes.empty())
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
if (IsInitialBlockDownload())
@@ -754,7 +757,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL);
+ bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, g_connman.get());
UnregisterValidationInterface(&sc);
if (fBlockPresent)
{
@@ -919,8 +922,8 @@ static const CRPCCommand commands[] =
{ "util", "estimatesmartpriority", &estimatesmartpriority, true },
};
-void RegisterMiningRPCCommands(CRPCTable &tableRPC)
+void RegisterMiningRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index a8c5bcd177..5afcf6353c 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -89,7 +89,8 @@ UniValue getinfo(const UniValue& params, bool fHelp)
#endif
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
- obj.push_back(Pair("connections", (int)vNodes.size()));
+ if(g_connman)
+ obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
@@ -320,43 +321,6 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
return result;
}
-UniValue createwitnessaddress(const UniValue& params, bool fHelp)
-{
- if (fHelp || params.size() < 1 || params.size() > 1)
- {
- string msg = "createwitnessaddress \"script\"\n"
- "\nCreates a witness address for a particular script.\n"
- "It returns a json object with the address and witness script.\n"
-
- "\nArguments:\n"
- "1. \"script\" (string, required) A hex encoded script\n"
-
- "\nResult:\n"
- "{\n"
- " \"address\":\"multisigaddress\", (string) The value of the new address (P2SH of witness script).\n"
- " \"witnessScript\":\"script\" (string) The string value of the hex-encoded witness script.\n"
- "}\n"
- ;
- throw runtime_error(msg);
- }
-
- if (!IsHex(params[0].get_str())) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Script must be hex-encoded");
- }
-
- std::vector<unsigned char> code = ParseHex(params[0].get_str());
- CScript script(code.begin(), code.end());
- CScript witscript = GetScriptForWitness(script);
- CScriptID witscriptid(witscript);
- CBitcoinAddress address(witscriptid);
-
- UniValue result(UniValue::VOBJ);
- result.push_back(Pair("address", address.ToString()));
- result.push_back(Pair("witnessScript", HexStr(witscript.begin(), witscript.end())));
-
- return result;
-}
-
UniValue verifymessage(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
@@ -471,14 +435,16 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
// atomically with the time change to prevent peers from being
// disconnected because we think we haven't communicated with them
// in a long time.
- LOCK2(cs_main, cs_vNodes);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64());
uint64_t t = GetTime();
- BOOST_FOREACH(CNode* pnode, vNodes) {
- pnode->nLastSend = pnode->nLastRecv = t;
+ if(g_connman) {
+ g_connman->ForEachNode([t](CNode* pnode) {
+ pnode->nLastSend = pnode->nLastRecv = t;
+ });
}
return NullUniValue;
@@ -490,7 +456,6 @@ static const CRPCCommand commands[] =
{ "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */
{ "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */
{ "util", "createmultisig", &createmultisig, true },
- { "util", "createwitnessaddress", &createwitnessaddress, true },
{ "util", "verifymessage", &verifymessage, true },
{ "util", "signmessagewithprivkey", &signmessagewithprivkey, true },
@@ -498,8 +463,8 @@ static const CRPCCommand commands[] =
{ "hidden", "setmocktime", &setmocktime, true },
};
-void RegisterMiscRPCCommands(CRPCTable &tableRPC)
+void RegisterMiscRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 4ce122648b..b011029f51 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -36,9 +36,10 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getconnectioncount", "")
);
- LOCK2(cs_main, cs_vNodes);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- return (int)vNodes.size();
+ return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
}
UniValue ping(const UniValue& params, bool fHelp)
@@ -54,29 +55,16 @@ UniValue ping(const UniValue& params, bool fHelp)
+ HelpExampleRpc("ping", "")
);
- // Request that each node send a ping during next message processing pass
- LOCK2(cs_main, cs_vNodes);
-
- BOOST_FOREACH(CNode* pNode, vNodes) {
- pNode->fPingQueued = true;
- }
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ // Request that each node send a ping during next message processing pass
+ g_connman->ForEachNode([](CNode* pnode) {
+ pnode->fPingQueued = true;
+ });
return NullUniValue;
}
-static void CopyNodeStats(std::vector<CNodeStats>& vstats)
-{
- vstats.clear();
-
- LOCK(cs_vNodes);
- vstats.reserve(vNodes.size());
- BOOST_FOREACH(CNode* pnode, vNodes) {
- CNodeStats stats;
- pnode->copyStats(stats);
- vstats.push_back(stats);
- }
-}
-
UniValue getpeerinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -127,10 +115,11 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getpeerinfo", "")
);
- LOCK(cs_main);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
vector<CNodeStats> vstats;
- CopyNodeStats(vstats);
+ g_connman->GetNodeStats(vstats);
UniValue ret(UniValue::VARR);
@@ -214,32 +203,27 @@ UniValue addnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
string strNode = params[0].get_str();
if (strCommand == "onetry")
{
CAddress addr;
- OpenNetworkConnection(addr, false, NULL, strNode.c_str());
+ g_connman->OpenNetworkConnection(addr, false, NULL, strNode.c_str());
return NullUniValue;
}
- LOCK(cs_vAddedNodes);
- vector<string>::iterator it = vAddedNodes.begin();
- for(; it != vAddedNodes.end(); it++)
- if (strNode == *it)
- break;
-
if (strCommand == "add")
{
- if (it != vAddedNodes.end())
+ if(!g_connman->AddNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
- vAddedNodes.push_back(strNode);
}
else if(strCommand == "remove")
{
- if (it == vAddedNodes.end())
+ if(!g_connman->RemoveAddedNode(strNode))
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
- vAddedNodes.erase(it);
}
return NullUniValue;
@@ -258,25 +242,25 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
);
- CNode* pNode = FindNode(params[0].get_str());
- if (pNode == NULL)
- throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- pNode->fDisconnect = true;
+ bool ret = g_connman->DisconnectNode(params[0].get_str());
+ if (!ret)
+ throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
return NullUniValue;
}
UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (fHelp || params.size() > 1)
throw runtime_error(
- "getaddednodeinfo dummy ( \"node\" )\n"
+ "getaddednodeinfo ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n"
"\nArguments:\n"
- "1. dummy (boolean, required) Kept for historical purposes but ignored\n"
- "2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
+ "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
"\nResult:\n"
"[\n"
" {\n"
@@ -297,12 +281,15 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
+ HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\"")
);
- std::vector<AddedNodeInfo> vInfo = GetAddedNodeInfo();
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
+ std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (params.size() == 2) {
+ if (params.size() == 1) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
- if (info.strAddedNode == params[1].get_str()) {
+ if (info.strAddedNode == params[0].get_str()) {
vInfo.assign(1, info);
found = true;
break;
@@ -359,19 +346,21 @@ UniValue getnettotals(const UniValue& params, bool fHelp)
+ HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
UniValue obj(UniValue::VOBJ);
- obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
- obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
+ obj.push_back(Pair("totalbytesrecv", g_connman->GetTotalBytesRecv()));
+ obj.push_back(Pair("totalbytessent", g_connman->GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
UniValue outboundLimit(UniValue::VOBJ);
- outboundLimit.push_back(Pair("timeframe", CNode::GetMaxOutboundTimeframe()));
- outboundLimit.push_back(Pair("target", CNode::GetMaxOutboundTarget()));
- outboundLimit.push_back(Pair("target_reached", CNode::OutboundTargetReached(false)));
- outboundLimit.push_back(Pair("serve_historical_blocks", !CNode::OutboundTargetReached(true)));
- outboundLimit.push_back(Pair("bytes_left_in_cycle", CNode::GetOutboundTargetBytesLeft()));
- outboundLimit.push_back(Pair("time_left_in_cycle", CNode::GetMaxOutboundTimeLeftInCycle()));
+ outboundLimit.push_back(Pair("timeframe", g_connman->GetMaxOutboundTimeframe()));
+ outboundLimit.push_back(Pair("target", g_connman->GetMaxOutboundTarget()));
+ outboundLimit.push_back(Pair("target_reached", g_connman->OutboundTargetReached(false)));
+ outboundLimit.push_back(Pair("serve_historical_blocks", !g_connman->OutboundTargetReached(true)));
+ outboundLimit.push_back(Pair("bytes_left_in_cycle", g_connman->GetOutboundTargetBytesLeft()));
+ outboundLimit.push_back(Pair("time_left_in_cycle", g_connman->GetMaxOutboundTimeLeftInCycle()));
obj.push_back(Pair("uploadtarget", outboundLimit));
return obj;
}
@@ -438,15 +427,16 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
-
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
- obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
+ if(g_connman)
+ obj.push_back(Pair("localservices", strprintf("%016x", g_connman->GetLocalServices())));
obj.push_back(Pair("localrelay", fRelayTxes));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
- obj.push_back(Pair("connections", (int)vNodes.size()));
+ if(g_connman)
+ obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
UniValue localAddresses(UniValue::VARR);
@@ -486,6 +476,8 @@ UniValue setban(const UniValue& params, bool fHelp)
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
CSubNet subNet;
CNetAddr netAddr;
@@ -507,7 +499,7 @@ UniValue setban(const UniValue& params, bool fHelp)
if (strCommand == "add")
{
- if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
+ if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
@@ -518,11 +510,11 @@ UniValue setban(const UniValue& params, bool fHelp)
if (params.size() == 4 && params[3].isTrue())
absolute = true;
- isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+ isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
}
else if(strCommand == "remove")
{
- if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
+ if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
}
return NullUniValue;
@@ -539,8 +531,11 @@ UniValue listbanned(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listbanned", "")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
banmap_t banMap;
- CNode::GetBanned(banMap);
+ g_connman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
@@ -568,8 +563,10 @@ UniValue clearbanned(const UniValue& params, bool fHelp)
+ HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "")
);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- CNode::ClearBanned();
+ g_connman->ClearBanned();
return NullUniValue;
}
@@ -590,8 +587,8 @@ static const CRPCCommand commands[] =
{ "network", "clearbanned", &clearbanned, true },
};
-void RegisterNetRPCCommands(CRPCTable &tableRPC)
+void RegisterNetRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 55d0aac68b..1d2ef0e41e 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -38,18 +38,18 @@ enum RPCErrorCode
RPC_PARSE_ERROR = -32700,
//! General application defined errors
- RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
- RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
- RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
- RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
- RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
- RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
- RPC_DATABASE_ERROR = -20, //! Database error
- RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
- RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
- RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules
- RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain
- RPC_IN_WARMUP = -28, //! Client still warming up
+ RPC_MISC_ERROR = -1, //!< std::exception thrown in command handling
+ RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode
+ RPC_TYPE_ERROR = -3, //!< Unexpected type was passed as parameter
+ RPC_INVALID_ADDRESS_OR_KEY = -5, //!< Invalid address or key
+ RPC_OUT_OF_MEMORY = -7, //!< Ran out of memory during operation
+ RPC_INVALID_PARAMETER = -8, //!< Invalid, missing or duplicate parameter
+ RPC_DATABASE_ERROR = -20, //!< Database error
+ RPC_DESERIALIZATION_ERROR = -22, //!< Error parsing or validating structure in raw format
+ RPC_VERIFY_ERROR = -25, //!< General error during transaction or block submission
+ RPC_VERIFY_REJECTED = -26, //!< Transaction or block was rejected by network rules
+ RPC_VERIFY_ALREADY_IN_CHAIN = -27, //!< Transaction already in chain
+ RPC_IN_WARMUP = -28, //!< Client still warming up
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
@@ -57,23 +57,24 @@ enum RPCErrorCode
RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,
//! P2P client errors
- RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected
- RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
- RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
- RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
- RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
- RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
+ RPC_CLIENT_NOT_CONNECTED = -9, //!< Bitcoin is not connected
+ RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //!< Still downloading initial blocks
+ RPC_CLIENT_NODE_ALREADY_ADDED = -23, //!< Node is already added
+ RPC_CLIENT_NODE_NOT_ADDED = -24, //!< Node has not been added before
+ RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
+ RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
+ RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
//! Wallet errors
- RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
- RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
- RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
- RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
- RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
- RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
- RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
- RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet
- RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
+ RPC_WALLET_ERROR = -4, //!< Unspecified problem with wallet (key not found etc.)
+ RPC_WALLET_INSUFFICIENT_FUNDS = -6, //!< Not enough funds in wallet or account
+ RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //!< Invalid account name
+ RPC_WALLET_KEYPOOL_RAN_OUT = -12, //!< Keypool ran out, call keypoolrefill first
+ RPC_WALLET_UNLOCK_NEEDED = -13, //!< Enter the wallet passphrase with walletpassphrase first
+ RPC_WALLET_PASSPHRASE_INCORRECT = -14, //!< The wallet passphrase entered was incorrect
+ RPC_WALLET_WRONG_ENC_STATE = -15, //!< Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
+ RPC_WALLET_ENCRYPTION_FAILED = -16, //!< Failed to encrypt the wallet
+ RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
};
std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 3270cd384f..d2ad0a52b7 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -891,8 +891,14 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
- RelayTransaction(tx);
+ if(!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ CInv inv(MSG_TX, hashTx);
+ g_connman->ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
return hashTx.GetHex();
}
@@ -910,8 +916,8 @@ static const CRPCCommand commands[] =
{ "blockchain", "verifytxoutproof", &verifytxoutproof, true },
};
-void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC)
+void RegisterRawTransactionRPCCommands(CRPCTable &t)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/rpc/register.h b/src/rpc/register.h
index 01aa58a25d..49aee2365f 100644
--- a/src/rpc/register.h
+++ b/src/rpc/register.h
@@ -20,13 +20,13 @@ void RegisterMiningRPCCommands(CRPCTable &tableRPC);
/** Register raw transaction RPC commands */
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
-static inline void RegisterAllCoreRPCCommands(CRPCTable &tableRPC)
+static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
{
- RegisterBlockchainRPCCommands(tableRPC);
- RegisterNetRPCCommands(tableRPC);
- RegisterMiscRPCCommands(tableRPC);
- RegisterMiningRPCCommands(tableRPC);
- RegisterRawTransactionRPCCommands(tableRPC);
+ RegisterBlockchainRPCCommands(t);
+ RegisterNetRPCCommands(t);
+ RegisterMiscRPCCommands(t);
+ RegisterMiningRPCCommands(t);
+ RegisterRawTransactionRPCCommands(t);
}
#endif
diff --git a/src/rpc/server.h b/src/rpc/server.h
index b5ccc153d0..4e0aa2c6d6 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -194,5 +194,6 @@ bool StartRPC();
void InterruptRPC();
void StopRPC();
std::string JSONRPCExecBatch(const UniValue& vReq);
+void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
#endif // BITCOIN_RPCSERVER_H
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 62fd9031f8..b629f4278b 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -84,8 +84,8 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
// Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK);
-
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount), NULL);
+ PrecomputedTransactionData txdata(tx);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), nIn < tx.wit.vtxinwit.size() ? &tx.wit.vtxinwit[nIn].scriptWitness : NULL, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata), NULL);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index bc027e9f0c..47ea261e31 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1108,9 +1108,40 @@ public:
}
};
+uint256 GetPrevoutHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].prevout;
+ }
+ return ss.GetHash();
+}
+
+uint256 GetSequenceHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vin.size(); n++) {
+ ss << txTo.vin[n].nSequence;
+ }
+ return ss.GetHash();
+}
+
+uint256 GetOutputsHash(const CTransaction& txTo) {
+ CHashWriter ss(SER_GETHASH, 0);
+ for (unsigned int n = 0; n < txTo.vout.size(); n++) {
+ ss << txTo.vout[n];
+ }
+ return ss.GetHash();
+}
+
} // anon namespace
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion)
+PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
+{
+ hashPrevouts = GetPrevoutHash(txTo);
+ hashSequence = GetSequenceHash(txTo);
+ hashOutputs = GetOutputsHash(txTo);
+}
+
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
if (sigversion == SIGVERSION_WITNESS_V0) {
uint256 hashPrevouts;
@@ -1118,27 +1149,16 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
uint256 hashOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].prevout;
- }
- hashPrevouts = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vin.size(); n++) {
- ss << txTo.vin[n].nSequence;
- }
- hashSequence = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
}
+
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
- CHashWriter ss(SER_GETHASH, 0);
- for (unsigned int n = 0; n < txTo.vout.size(); n++) {
- ss << txTo.vout[n];
- }
- hashOutputs = ss.GetHash(); // TODO: cache this value for all signatures in a transaction
+ hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
@@ -1209,7 +1229,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
int nHashType = vchSig.back();
vchSig.pop_back();
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index bd2f211663..e5d7865cd3 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -98,13 +98,20 @@ enum
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
+struct PrecomputedTransactionData
+{
+ uint256 hashPrevouts, hashSequence, hashOutputs;
+
+ PrecomputedTransactionData(const CTransaction& tx);
+};
+
enum SigVersion
{
SIGVERSION_BASE = 0,
SIGVERSION_WITNESS_V0 = 1,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion);
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker
{
@@ -133,12 +140,14 @@ private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
+ const PrecomputedTransactionData* txdata;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
+ TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
bool CheckSequence(const CScriptNum& nSequence) const;
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 050bf8cc42..44551ec2bc 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -22,7 +22,7 @@ private:
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, nInIn, amount), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
diff --git a/src/script/sign.h b/src/script/sign.h
index 6404b4523e..f9aa6fca27 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -51,7 +51,7 @@ public:
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
-/** A signature creator that just produces 72-byte empty signatyres. */
+/** A signature creator that just produces 72-byte empty signatures. */
class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
diff --git a/src/sync.h b/src/sync.h
index 0c58fb6b4e..7733910749 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -171,7 +171,10 @@ public:
typedef CMutexLock<CCriticalSection> CCriticalBlock;
-#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__)
+#define PASTE(x, y) x ## y
+#define PASTE2(x, y) PASTE(x, y)
+
+#define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
#define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
#define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index a8c5f95ace..97abeb7211 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -40,69 +40,75 @@ CService ip(uint32_t i)
return CService(CNetAddr(s), Params().GetDefaultPort());
}
+static NodeId id = 0;
+
BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(DoS_banning)
{
- CNode::ClearBanned();
+ connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, "", true);
+ GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
- SendMessages(&dummyNode1);
- BOOST_CHECK(CNode::IsBanned(addr1));
- BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
+ SendMessages(&dummyNode1, *connman);
+ BOOST_CHECK(connman->IsBanned(addr1));
+ BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
- CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
+ CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, "", true);
+ GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2);
dummyNode2.nVersion = 1;
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2);
- BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
- BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
+ SendMessages(&dummyNode2, *connman);
+ BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
+ BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2);
- BOOST_CHECK(CNode::IsBanned(addr2));
+ SendMessages(&dummyNode2, *connman);
+ BOOST_CHECK(connman->IsBanned(addr2));
}
BOOST_AUTO_TEST_CASE(DoS_banscore)
{
- CNode::ClearBanned();
+ connman->ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, "", true);
+ GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100);
- SendMessages(&dummyNode1);
- BOOST_CHECK(!CNode::IsBanned(addr1));
+ SendMessages(&dummyNode1, *connman);
+ BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 10);
- SendMessages(&dummyNode1);
- BOOST_CHECK(!CNode::IsBanned(addr1));
+ SendMessages(&dummyNode1, *connman);
+ BOOST_CHECK(!connman->IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 1);
- SendMessages(&dummyNode1);
- BOOST_CHECK(CNode::IsBanned(addr1));
+ SendMessages(&dummyNode1, *connman);
+ BOOST_CHECK(connman->IsBanned(addr1));
mapArgs.erase("-banscore");
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
{
- CNode::ClearBanned();
+ connman->ClearBanned();
int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(INVALID_SOCKET, addr, "", true);
+ CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, "", true);
+ GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode);
dummyNode.nVersion = 1;
Misbehaving(dummyNode.GetId(), 100);
- SendMessages(&dummyNode);
- BOOST_CHECK(CNode::IsBanned(addr));
+ SendMessages(&dummyNode, *connman);
+ BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60);
- BOOST_CHECK(CNode::IsBanned(addr));
+ BOOST_CHECK(connman->IsBanned(addr));
SetMockTime(nStartTime+60*60*24+1);
- BOOST_CHECK(!CNode::IsBanned(addr));
+ BOOST_CHECK(!connman->IsBanned(addr));
}
CTransaction RandomOrphan()
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 53ab7e95ee..b19d2faea0 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE( basics ) // constructors, equality, inequality
BOOST_CHECK( (R1L & arith_uint256("0xffffffffffffffff")) == arith_uint256(R1LLow64));
BOOST_CHECK(ZeroL == arith_uint256(0));
BOOST_CHECK(OneL == arith_uint256(1));
- BOOST_CHECK(arith_uint256("0xffffffffffffffff") = arith_uint256(0xffffffffffffffffULL));
+ BOOST_CHECK(arith_uint256("0xffffffffffffffff") == arith_uint256(0xffffffffffffffffULL));
// Assignment (from base_uint)
arith_uint256 tmpL = ~ZeroL; BOOST_CHECK(tmpL == ~ZeroL);
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 3884bf3fe3..d2392cfb22 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -283,7 +283,6 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest)
std::vector<CTransaction> vtx_missing;
BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK);
BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString());
- bool mutated;
BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString());
BOOST_CHECK(!mutated);
}
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index a0bdcf4afb..d4d825d199 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
uint256 in2 = GetRandHash();
BOOST_CHECK(dbw.Write(key2, in2));
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
// Be sure to seek past the obfuscation key (if it exists)
it->Seek(key);
@@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(iterator_ordering)
BOOST_CHECK(dbw.Write(key, value));
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
@@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
}
}
- boost::scoped_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
+ std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper*>(&dbw)->NewIterator());
for (int c=0; c<2; ++c) {
int seek_start;
if (c == 0)
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 15fceb963a..d3aa2364d1 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
CValidationState state;
- BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
+ BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, connman));
BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash();
}
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 267d1b55e1..680708533e 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -153,6 +153,8 @@ BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
SOCKET hSocket = INVALID_SOCKET;
+ NodeId id = 0;
+ int height = 0;
in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;
@@ -162,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
bool fInboundIn = false;
// Test that fFeeler is false by default.
- CNode* pnode1 = new CNode(hSocket, addr, pszDest, fInboundIn);
+ CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true;
- CNode* pnode2 = new CNode(hSocket, addr, pszDest, fInboundIn);
+ CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index d1407c1da9..b8c45ca564 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -26,57 +26,70 @@ class prevector_tester {
pretype pre_vector_alt;
typedef typename pretype::size_type Size;
+ bool passed = true;
+ uint32_t insecure_rand_Rz_cache;
+ uint32_t insecure_rand_Rw_cache;
+
+ template <typename A, typename B>
+ void local_check_equal(A a, B b)
+ {
+ local_check(a == b);
+ }
+ void local_check(bool b)
+ {
+ passed &= b;
+ }
void test() {
const pretype& const_pre_vector = pre_vector;
- BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size());
- BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty());
+ local_check_equal(real_vector.size(), pre_vector.size());
+ local_check_equal(real_vector.empty(), pre_vector.empty());
for (Size s = 0; s < real_vector.size(); s++) {
- BOOST_CHECK(real_vector[s] == pre_vector[s]);
- BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s]));
- BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s));
- BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
+ local_check(real_vector[s] == pre_vector[s]);
+ local_check(&(pre_vector[s]) == &(pre_vector.begin()[s]));
+ local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s));
+ local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
}
- // BOOST_CHECK(realtype(pre_vector) == real_vector);
- BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
- BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
+ // local_check(realtype(pre_vector) == real_vector);
+ local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
+ local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
size_t pos = 0;
BOOST_FOREACH(const T& v, pre_vector) {
- BOOST_CHECK(v == real_vector[pos++]);
+ local_check(v == real_vector[pos++]);
}
BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
- BOOST_CHECK(v == real_vector[--pos]);
+ local_check(v == real_vector[--pos]);
}
BOOST_FOREACH(const T& v, const_pre_vector) {
- BOOST_CHECK(v == real_vector[pos++]);
+ local_check(v == real_vector[pos++]);
}
BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
- BOOST_CHECK(v == real_vector[--pos]);
+ local_check(v == real_vector[--pos]);
}
CDataStream ss1(SER_DISK, 0);
CDataStream ss2(SER_DISK, 0);
ss1 << real_vector;
ss2 << pre_vector;
- BOOST_CHECK_EQUAL(ss1.size(), ss2.size());
+ local_check_equal(ss1.size(), ss2.size());
for (Size s = 0; s < ss1.size(); s++) {
- BOOST_CHECK_EQUAL(ss1[s], ss2[s]);
+ local_check_equal(ss1[s], ss2[s]);
}
}
public:
void resize(Size s) {
real_vector.resize(s);
- BOOST_CHECK_EQUAL(real_vector.size(), s);
+ local_check_equal(real_vector.size(), s);
pre_vector.resize(s);
- BOOST_CHECK_EQUAL(pre_vector.size(), s);
+ local_check_equal(pre_vector.size(), s);
test();
}
void reserve(Size s) {
real_vector.reserve(s);
- BOOST_CHECK(real_vector.capacity() >= s);
+ local_check(real_vector.capacity() >= s);
pre_vector.reserve(s);
- BOOST_CHECK(pre_vector.capacity() >= s);
+ local_check(pre_vector.capacity() >= s);
test();
}
@@ -157,6 +170,17 @@ public:
pre_vector.swap(pre_vector_alt);
test();
}
+ ~prevector_tester() {
+ BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: "
+ << insecure_rand_Rz_cache
+ << ", insecure_rand_Rw: "
+ << insecure_rand_Rw_cache);
+ }
+ prevector_tester() {
+ seed_insecure_rand();
+ insecure_rand_Rz_cache = insecure_rand_Rz;
+ insecure_rand_Rw_cache = insecure_rand_Rw;
+ }
};
BOOST_AUTO_TEST_CASE(PrevectorTestInt)
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 5224b57ca4..1a01593a8e 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -107,18 +107,20 @@ BOOST_AUTO_TEST_CASE(sign)
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
- for (int i = 0; i < 8; i++)
+ for (int i = 0; i < 8; i++) {
+ PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
- bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
+ bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
txTo[i].vin[0].scriptSig = sigSave;
}
+ }
}
BOOST_AUTO_TEST_CASE(norecurse)
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 056f2982cf..02843d8525 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -26,6 +26,8 @@
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
+std::unique_ptr<CConnman> g_connman;
+
extern bool fPrintToConsole;
extern void noui_connect();
@@ -43,6 +45,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
+ g_connman.reset();
}
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
@@ -50,6 +53,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
const CChainParams& chainparams = Params();
// Ideally we'd move all the RPC tests to the functional testing framework
// instead of unit tests, but for now we need these here.
+
RegisterAllCoreRPCCommands(tableRPC);
ClearDatadirCache();
pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
@@ -68,6 +72,8 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck);
+ g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
+ connman = g_connman.get();
RegisterNodeSignals(GetNodeSignals());
}
@@ -118,7 +124,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
CValidationState state;
- ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
+ ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, connman);
CBlock result = block;
delete pblocktemplate;
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index bc0d2fe316..9819a7097d 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -27,10 +27,12 @@ struct BasicTestingSetup {
/** Testing setup that configures a complete environment.
* Included are data directory, coins database, script check threads setup.
*/
+class CConnman;
struct TestingSetup: public BasicTestingSetup {
CCoinsViewDB *pcoinsdbview;
boost::filesystem::path pathTemp;
boost::thread_group threadGroup;
+ CConnman* connman;
TestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~TestingSetup();
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index fd4f174b40..b5af400bc5 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -7,6 +7,7 @@
#include "test/test_bitcoin.h"
#include "clientversion.h"
+#include "checkqueue.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
@@ -153,6 +154,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
BOOST_CHECK(state.IsValid());
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -168,7 +170,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err),
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
@@ -237,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid();
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@@ -252,7 +255,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
}
const CScriptWitness *witness = (i < tx.wit.vtxinwit.size()) ? &tx.wit.vtxinwit[i].scriptWitness : NULL;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- witness, verify_flags, TransactionSignatureChecker(&tx, i, amount), &err);
+ witness, verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
@@ -419,6 +422,86 @@ void ReplaceRedeemScript(CScript& script, const CScript& redeemScript)
script = PushAll(stack);
}
+BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
+ CMutableTransaction mtx;
+ mtx.nVersion = 1;
+
+ CKey key;
+ key.MakeNewKey(false);
+ CBasicKeyStore keystore;
+ keystore.AddKeyPubKey(key, key.GetPubKey());
+ CKeyID hash = key.GetPubKey().GetID();
+ CScript scriptPubKey = CScript() << OP_0 << std::vector<unsigned char>(hash.begin(), hash.end());
+
+ vector<int> sigHashes;
+ sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
+ sigHashes.push_back(SIGHASH_NONE);
+ sigHashes.push_back(SIGHASH_SINGLE);
+ sigHashes.push_back(SIGHASH_ALL);
+
+ // create a big transaction of 4500 inputs signed by the same key
+ for(uint32_t ij = 0; ij < 4500; ij++) {
+ uint32_t i = mtx.vin.size();
+ uint256 prevId;
+ prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
+ COutPoint outpoint(prevId, i);
+
+ mtx.vin.resize(mtx.vin.size() + 1);
+ mtx.vin[i].prevout = outpoint;
+ mtx.vin[i].scriptSig = CScript();
+
+ mtx.vout.resize(mtx.vout.size() + 1);
+ mtx.vout[i].nValue = 1000;
+ mtx.vout[i].scriptPubKey = CScript() << OP_1;
+ }
+
+ // sign all inputs
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()));
+ assert(hashSigned);
+ }
+
+ CTransaction tx;
+ CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
+ WithOrVersion(&ssout, 0) << mtx;
+ WithOrVersion(&ssout, 0) >> tx;
+
+ // check all inputs concurrently, with the cache
+ PrecomputedTransactionData txdata(tx);
+ boost::thread_group threadGroup;
+ CCheckQueue<CScriptCheck> scriptcheckqueue(128);
+ CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
+
+ for (int i=0; i<20; i++)
+ threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
+
+ CCoins coins;
+ coins.nVersion = 1;
+ coins.fCoinBase = false;
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ CTxOut txout;
+ txout.nValue = 1000;
+ txout.scriptPubKey = scriptPubKey;
+ coins.vout.push_back(txout);
+ }
+
+ for(uint32_t i = 0; i < mtx.vin.size(); i++) {
+ std::vector<CScriptCheck> vChecks;
+ CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false, &txdata);
+ vChecks.push_back(CScriptCheck());
+ check.swap(vChecks.back());
+ control.Add(vChecks);
+ }
+
+ bool controlCheck = control.Wait();
+ assert(controlCheck);
+
+ threadGroup.interrupt_all();
+ threadGroup.join_all();
+}
+
BOOST_AUTO_TEST_CASE(test_witness)
{
CBasicKeyStore keystore, keystore2;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 078c29def3..4f11c7b951 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -173,7 +173,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
- boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
+ std::unique_ptr<CDBIterator> pcursor(NewIterator());
pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));
diff --git a/src/txdb.h b/src/txdb.h
index 5b98d2792c..adb3f66327 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -92,7 +92,7 @@ public:
private:
CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256 &hashBlockIn):
CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
- boost::scoped_ptr<CDBIterator> pcursor;
+ std::unique_ptr<CDBIterator> pcursor;
std::pair<char, uint256> keyTmp;
friend class CCoinsViewDB;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index b631c48484..0a00d757a2 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -576,7 +576,6 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed)
{
// Remove transactions which depend on inputs of tx, recursively
- list<CTransaction> result;
LOCK(cs);
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
auto it = mapNextTx.find(txin.prevout);
diff --git a/src/util.cpp b/src/util.cpp
index 9a9209c621..93cc0412b5 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -107,7 +107,6 @@ map<string, vector<string> > mapMultiArgs;
bool fDebug = false;
bool fPrintToConsole = false;
bool fPrintToDebugLog = true;
-bool fDaemon = false;
bool fServer = false;
string strMiscWarning;
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
@@ -601,19 +600,19 @@ bool TryCreateDirectory(const boost::filesystem::path& p)
return false;
}
-void FileCommit(FILE *fileout)
+void FileCommit(FILE *file)
{
- fflush(fileout); // harmless if redundantly called
+ fflush(file); // harmless if redundantly called
#ifdef WIN32
- HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout));
+ HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
FlushFileBuffers(hFile);
#else
#if defined(__linux__) || defined(__NetBSD__)
- fdatasync(fileno(fileout));
+ fdatasync(fileno(file));
#elif defined(__APPLE__) && defined(F_FULLFSYNC)
- fcntl(fileno(fileout), F_FULLFSYNC, 0);
+ fcntl(fileno(file), F_FULLFSYNC, 0);
#else
- fsync(fileno(fileout));
+ fsync(fileno(file));
#endif
#endif
}
@@ -801,11 +800,10 @@ int GetNumCores()
std::string CopyrightHolders(const std::string& strPrefix)
{
- std::string strCopyrightHolders = strPrefix + _(COPYRIGHT_HOLDERS);
- if (strCopyrightHolders.find("%s") != strCopyrightHolders.npos) {
- strCopyrightHolders = strprintf(strCopyrightHolders, _(COPYRIGHT_HOLDERS_SUBSTITUTION));
- }
- if (strCopyrightHolders.find("Bitcoin Core developers") == strCopyrightHolders.npos) {
+ std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
+
+ // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident
+ if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) {
strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
}
return strCopyrightHolders;
diff --git a/src/util.h b/src/util.h
index 39328b51ef..45b3658557 100644
--- a/src/util.h
+++ b/src/util.h
@@ -93,7 +93,7 @@ bool error(const char* fmt, const Args&... args)
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
void ParseParameters(int argc, const char*const argv[]);
-void FileCommit(FILE *fileout);
+void FileCommit(FILE *file);
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index cf1d6ca086..6ddf37658d 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -18,7 +18,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
- g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
+ g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
@@ -28,7 +28,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
- g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
+ g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 094b1cfe26..0c91ec8308 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -13,6 +13,7 @@ class CBlock;
class CBlockIndex;
struct CBlockLocator;
class CBlockIndex;
+class CConnman;
class CReserveScript;
class CTransaction;
class CValidationInterface;
@@ -37,7 +38,7 @@ protected:
virtual void SetBestChain(const CBlockLocator &locator) {}
virtual void UpdatedTransaction(const uint256 &hash) {}
virtual void Inventory(const uint256 &hash) {}
- virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
+ virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
virtual void ResetRequestCount(const uint256 &hash) {};
@@ -58,7 +59,7 @@ struct CMainSignals {
/** Notifies listeners about an inventory item being seen on the network. */
boost::signals2::signal<void (const uint256 &)> Inventory;
/** Tells listeners to broadcast their data. */
- boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast;
+ boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
/** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
/** Notifies listeners that a key for mining is required (coinbase) */
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index cfd007ca1c..a809c9ad64 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv(0).remove(strPath.c_str(), 0);
+ DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
}
void CDBEnv::Reset()
@@ -387,11 +387,11 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip)
while (fSuccess) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
- if (ret == DB_NOTFOUND) {
+ int ret1 = db.ReadAtCursor(pcursor, ssKey, ssValue);
+ if (ret1 == DB_NOTFOUND) {
pcursor->close();
break;
- } else if (ret != 0) {
+ } else if (ret1 != 0) {
pcursor->close();
fSuccess = false;
break;
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 01b8c71a04..a0f673ecfc 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -228,19 +228,17 @@ protected:
return pcursor;
}
- int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, unsigned int fFlags = DB_NEXT)
+ int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
{
// Read at cursor
Dbt datKey;
- if (fFlags == DB_SET || fFlags == DB_SET_RANGE || fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
+ unsigned int fFlags = DB_NEXT;
+ if (setRange) {
datKey.set_data(&ssKey[0]);
datKey.set_size(ssKey.size());
+ fFlags = DB_SET_RANGE;
}
Dbt datValue;
- if (fFlags == DB_GET_BOTH || fFlags == DB_GET_BOTH_RANGE) {
- datValue.set_data(&ssValue[0]);
- datValue.set_size(ssValue.size());
- }
datKey.set_flags(DB_DBT_MALLOC);
datValue.set_flags(DB_DBT_MALLOC);
int ret = pcursor->get(&datKey, &datValue, fFlags);
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index fe8b53ceb0..e80fa7dff8 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -257,14 +257,13 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (fHelp || params.size() != 2)
throw runtime_error(
"importprunedfunds\n"
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
"\nArguments:\n"
"1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n"
"2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n"
- "3. \"label\" (string, optional) An optional label\n"
);
CTransaction tx;
@@ -277,10 +276,6 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
- string strLabel = "";
- if (params.size() == 3)
- strLabel = params[2].get_str();
-
//Search partial merkle tree in proof for our transaction and index in valid block
vector<uint256> vMatch;
vector<unsigned int> vIndex;
@@ -349,8 +344,6 @@ UniValue removeprunedfunds(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet.");
}
- ThreadFlushWalletDB(pwalletMain->strWalletFile);
-
return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index aa0a9374c1..3eb7e5d9ba 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -346,6 +346,9 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
if (nValue > curBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
+ if (pwalletMain->GetBroadcastTransactions() && !g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
// Parse Bitcoin address
CScript scriptPubKey = GetScriptForDestination(address);
@@ -362,7 +365,7 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
strError = strprintf("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds!", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
- if (!pwalletMain->CommitTransaction(wtxNew, reservekey))
+ if (!pwalletMain->CommitTransaction(wtxNew, reservekey, g_connman.get()))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here.");
}
@@ -891,6 +894,9 @@ UniValue sendmany(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
+ if (pwalletMain->GetBroadcastTransactions() && !g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
string strAccount = AccountFromValue(params[0]);
UniValue sendTo = params[1].get_obj();
int nMinDepth = 1;
@@ -953,7 +959,7 @@ UniValue sendmany(const UniValue& params, bool fHelp)
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
- if (!pwalletMain->CommitTransaction(wtx, keyChange))
+ if (!pwalletMain->CommitTransaction(wtx, keyChange, g_connman.get()))
throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed");
return wtx.GetHash().GetHex();
@@ -1087,6 +1093,8 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet");
}
+ pwalletMain->SetAddressBook(w.result, "", "receive");
+
return CBitcoinAddress(w.result).ToString();
}
@@ -1176,10 +1184,10 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
if (fByAccounts)
{
- tallyitem& item = mapAccountTally[strAccount];
- item.nAmount += nAmount;
- item.nConf = min(item.nConf, nConf);
- item.fIsWatchonly = fIsWatchonly;
+ tallyitem& _item = mapAccountTally[strAccount];
+ _item.nAmount += nAmount;
+ _item.nConf = min(_item.nConf, nConf);
+ _item.fIsWatchonly = fIsWatchonly;
}
else
{
@@ -1195,9 +1203,9 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
- BOOST_FOREACH(const uint256& item, (*it).second.txids)
+ BOOST_FOREACH(const uint256& _item, (*it).second.txids)
{
- transactions.push_back(item.GetHex());
+ transactions.push_back(_item.GetHex());
}
}
obj.push_back(Pair("txids", transactions));
@@ -2308,9 +2316,12 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
"Returns array of transaction ids that were re-broadcast.\n"
);
+ if (!g_connman)
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
- std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
+ std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime(), g_connman.get());
UniValue result(UniValue::VARR);
BOOST_FOREACH(const uint256& txid, txids)
{
@@ -2617,8 +2628,11 @@ static const CRPCCommand commands[] =
{ "wallet", "removeprunedfunds", &removeprunedfunds, true },
};
-void RegisterWalletRPCCommands(CRPCTable &tableRPC)
+void RegisterWalletRPCCommands(CRPCTable &t)
{
+ if (GetBoolArg("-disablewallet", false))
+ return;
+
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ t.appendCommand(commands[vcidx].name, &commands[vcidx]);
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index a5de7e2de1..3a68ccf1b2 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -7,6 +7,6 @@
class CRPCTable;
-void RegisterWalletRPCCommands(CRPCTable &tableRPC);
+void RegisterWalletRPCCommands(CRPCTable &t);
#endif //BITCOIN_WALLET_RPCWALLET_H
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index a6cada46a2..a833be13d0 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
#include "wallet/test/wallet_test_fixture.h"
@@ -17,13 +16,13 @@ extern CWallet* pwalletMain;
BOOST_FIXTURE_TEST_SUITE(accounting_tests, WalletTestingSetup)
static void
-GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results)
+GetResults(std::map<CAmount, CAccountingEntry>& results)
{
std::list<CAccountingEntry> aes;
results.clear();
- BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK);
- walletdb.ListAccountCreditDebit("", aes);
+ BOOST_CHECK(pwalletMain->ReorderTransactions() == DB_LOAD_OK);
+ pwalletMain->ListAccountCreditDebit("", aes);
BOOST_FOREACH(CAccountingEntry& ae, aes)
{
results[ae.nOrderPos] = ae;
@@ -32,7 +31,6 @@ GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results)
BOOST_AUTO_TEST_CASE(acc_orderupgrade)
{
- CWalletDB walletdb(pwalletMain->strWalletFile);
std::vector<CWalletTx*> vpwtx;
CWalletTx wtx;
CAccountingEntry ae;
@@ -45,7 +43,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333333;
ae.strOtherAccount = "b";
ae.strComment = "";
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
wtx.mapValue["comment"] = "z";
pwalletMain->AddToWallet(wtx);
@@ -55,9 +53,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333336;
ae.strOtherAccount = "c";
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(pwalletMain->nOrderPosNext == 3);
BOOST_CHECK(2 == results.size());
@@ -71,9 +69,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333330;
ae.strOtherAccount = "d";
ae.nOrderPos = pwalletMain->IncOrderPosNext();
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 4);
@@ -105,7 +103,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
vpwtx[2]->nTimeReceived = (unsigned int)1333333329;
vpwtx[2]->nOrderPos = -1;
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(results.size() == 3);
BOOST_CHECK(pwalletMain->nOrderPosNext == 6);
@@ -121,9 +119,9 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
ae.nTime = 1333333334;
ae.strOtherAccount = "e";
ae.nOrderPos = -1;
- pwalletMain->AddAccountingEntry(ae, walletdb);
+ pwalletMain->AddAccountingEntry(ae);
- GetResults(walletdb, results);
+ GetResults(results);
BOOST_CHECK(results.size() == 4);
BOOST_CHECK(pwalletMain->nOrderPosNext == 7);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index c6c5058984..acf980c784 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
// run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
empty_wallet();
- for (int i = 0; i < 20; i++)
+ for (int j = 0; j < 20; j++)
add_coin(50000 * COIN);
BOOST_CHECK( wallet.SelectCoinsMinConf(500000 * COIN, 1, 1, vCoins, setCoinsRet, nValueRet));
@@ -296,7 +296,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
int fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
@@ -317,7 +317,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
add_coin(25 * CENT);
fails = 0;
- for (int i = 0; i < RANDOM_REPEATS; i++)
+ for (int j = 0; j < RANDOM_REPEATS; j++)
{
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
// run the test RANDOM_REPEATS times and only complain if all of them fail
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 769322969d..abb1ea7e76 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -40,6 +40,7 @@ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
+bool fWalletRbf = DEFAULT_WALLET_RBF;
const char * DEFAULT_WALLET_DAT = "wallet.dat";
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
@@ -413,6 +414,9 @@ void CWallet::Flush(bool shutdown)
bool CWallet::Verify()
{
+ if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
+
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
@@ -648,6 +652,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
return true;
}
+DBErrors CWallet::ReorderTransactions()
+{
+ CWalletDB walletdb(strWalletFile);
+ return walletdb.ReorderTransactions(this);
+}
+
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{
AssertLockHeld(cs_wallet); // nOrderPosNext
@@ -676,7 +686,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun
debit.nTime = nNow;
debit.strOtherAccount = strTo;
debit.strComment = strComment;
- AddAccountingEntry(debit, walletdb);
+ AddAccountingEntry(debit, &walletdb);
// Credit
CAccountingEntry credit;
@@ -686,7 +696,7 @@ bool CWallet::AccountMove(std::string strFrom, std::string strTo, CAmount nAmoun
credit.nTime = nNow;
credit.strOtherAccount = strFrom;
credit.strComment = strComment;
- AddAccountingEntry(credit, walletdb);
+ AddAccountingEntry(credit, &walletdb);
if (!walletdb.TxnCommit())
return false;
@@ -1453,15 +1463,21 @@ void CWallet::ReacceptWalletTransactions()
}
}
-bool CWalletTx::RelayWalletTransaction()
+bool CWalletTx::RelayWalletTransaction(CConnman* connman)
{
assert(pwallet->GetBroadcastTransactions());
if (!IsCoinBase())
{
if (GetDepthInMainChain() == 0 && !isAbandoned() && InMempool()) {
LogPrintf("Relaying wtx %s\n", GetHash().ToString());
- RelayTransaction((CTransaction)*this);
- return true;
+ if (connman) {
+ CInv inv(MSG_TX, GetHash());
+ connman->ForEachNode([&inv](CNode* pnode)
+ {
+ pnode->PushInventory(inv);
+ });
+ return true;
+ }
}
}
return false;
@@ -1688,7 +1704,7 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
return CTransaction(tx1) == CTransaction(tx2);
}
-std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
+std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman)
{
std::vector<uint256> result;
@@ -1706,13 +1722,13 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
{
CWalletTx& wtx = *item.second;
- if (wtx.RelayWalletTransaction())
+ if (wtx.RelayWalletTransaction(connman))
result.push_back(wtx.GetHash());
}
return result;
}
-void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
+void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
@@ -1730,7 +1746,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
// Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found:
- std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60);
+ std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60, connman);
if (!relayed.empty())
LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
}
@@ -2209,6 +2225,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
nChangePosInOut = nChangePosRequest;
txNew.vin.clear();
txNew.vout.clear();
+ txNew.wit.SetNull();
wtxNew.fFromMe = true;
bool fFirst = true;
@@ -2355,11 +2372,17 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Fill vin
//
- // Note how the sequence number is set to max()-1 so that the
- // nLockTime set above actually works.
+ // Note how the sequence number is set to non-maxint so that
+ // the nLockTime set above actually works.
+ //
+ // BIP125 defines opt-in RBF as any nSequence < maxint-1, so
+ // we use the highest possible value in that range (maxint-2)
+ // to avoid conflicting with other possible uses of nSequence,
+ // and in the spirit of "smallest posible change from prior
+ // behavior."
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(),
- std::numeric_limits<unsigned int>::max()-1));
+ std::numeric_limits<unsigned int>::max() - (fWalletRbf ? 2 : 1)));
// Sign
int nIn = 0;
@@ -2447,7 +2470,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
/**
* Call after CreateTransaction unless you want to abort
*/
-bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
+bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman)
{
{
LOCK2(cs_main, cs_wallet);
@@ -2461,7 +2484,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
AddToWallet(wtxNew);
// Notify that old coins are spent
- set<CWalletTx*> setCoins;
BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
{
CWalletTx &coin = mapWallet[txin.prevout.hash];
@@ -2482,15 +2504,27 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
}
- wtxNew.RelayWalletTransaction();
+ wtxNew.RelayWalletTransaction(connman);
}
}
return true;
}
-bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb)
+void CWallet::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) {
+ CWalletDB walletdb(strWalletFile);
+ return walletdb.ListAccountCreditDebit(strAccount, entries);
+}
+
+bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry)
{
- if (!pwalletdb.WriteAccountingEntry_Backend(acentry))
+ CWalletDB walletdb(strWalletFile);
+
+ return AddAccountingEntry(acentry, &walletdb);
+}
+
+bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwalletdb)
+{
+ if (!pwalletdb->WriteAccountingEntry_Backend(acentry))
return false;
laccentries.push_back(acentry);
@@ -3240,6 +3274,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
+ strUsage += HelpMessageOpt("-walletrbf", strprintf(_("Send transactions with full-RBF opt-in enabled (default: %u)"), DEFAULT_WALLET_RBF));
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format on startup"));
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), DEFAULT_WALLET_DAT));
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), DEFAULT_WALLETBROADCAST));
@@ -3261,6 +3296,12 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
bool CWallet::InitLoadWallet()
{
+ if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ pwalletMain = NULL;
+ LogPrintf("Wallet disabled!\n");
+ return true;
+ }
+
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
// needed to restore wallet transaction meta data after -zapwallettxes
@@ -3432,6 +3473,18 @@ bool CWallet::InitLoadWallet()
bool CWallet::ParameterInteraction()
{
+ if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ return true;
+
+ if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && SoftSetBoolArg("-walletbroadcast", false)) {
+ LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
+ }
+
+ if (GetBoolArg("-sysperms", false))
+ return InitError("-sysperms is not allowed in combination with enabled wallet functionality");
+ if (GetArg("-prune", 0) && GetBoolArg("-rescan", false))
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
+
if (mapArgs.count("-mintxfee"))
{
CAmount n = 0;
@@ -3480,6 +3533,7 @@ bool CWallet::ParameterInteraction()
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
+ fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
return true;
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index c06513650c..f6c658928f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -37,6 +37,7 @@ extern CFeeRate payTxFee;
extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange;
extern bool fSendFreeTransactions;
+extern bool fWalletRbf;
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
//! -paytxfee default
@@ -53,10 +54,12 @@ static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
+//! -walletrbf default
+static const bool DEFAULT_WALLET_RBF = false;
//! Largest (in bytes) free transaction we're willing to create
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
-
+static const bool DEFAULT_DISABLE_WALLET = false;
//! if set, all keys will be derived by using BIP32
static const bool DEFAULT_USE_HD_WALLET = true;
@@ -401,7 +404,7 @@ public:
int64_t GetTxTime() const;
int GetRequestCount() const;
- bool RelayWalletTransaction();
+ bool RelayWalletTransaction(CConnman* connman);
std::set<uint256> GetConflicts() const;
};
@@ -738,6 +741,7 @@ public:
* @return next transaction order id
*/
int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
+ DBErrors ReorderTransactions();
bool AccountMove(std::string strFrom, std::string strTo, CAmount nAmount, std::string strComment = "");
bool GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bForceNew = false);
@@ -748,8 +752,8 @@ public:
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime);
- std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
+ void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman);
+ std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime, CConnman* connman);
CAmount GetBalance() const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
@@ -770,9 +774,11 @@ public:
*/
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut,
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
- bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
+ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman);
- bool AddAccountingEntry(const CAccountingEntry&, CWalletDB & pwalletdb);
+ void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries);
+ bool AddAccountingEntry(const CAccountingEntry&);
+ bool AddAccountingEntry(const CAccountingEntry&, CWalletDB *pwalletdb);
static CFeeRate minTxFee;
static CFeeRate fallbackFee;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index e6e9fc484b..80bfe8255d 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -18,7 +18,6 @@
#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
-#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
using namespace std;
@@ -216,16 +215,16 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
Dbc* pcursor = GetCursor();
if (!pcursor)
throw runtime_error(std::string(__func__) + ": cannot create DB cursor");
- unsigned int fFlags = DB_SET_RANGE;
+ bool setRange = true;
while (true)
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- if (fFlags == DB_SET_RANGE)
+ if (setRange)
ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
+ int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange);
+ setRange = false;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
@@ -887,8 +886,8 @@ void ThreadFlushWalletDB(const string& strFile)
if (nRefCount == 0)
{
boost::this_thread::interruption_point();
- map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
- if (mi != bitdb.mapFileUseCount.end())
+ map<string, int>::iterator _mi = bitdb.mapFileUseCount.find(strFile);
+ if (_mi != bitdb.mapFileUseCount.end())
{
LogPrint("db", "Flushing %s\n", strFile);
nLastFlushed = nWalletDBUpdated;
@@ -898,7 +897,7 @@ void ThreadFlushWalletDB(const string& strFile)
bitdb.CloseDb(strFile);
bitdb.CheckpointLSN(strFile);
- bitdb.mapFileUseCount.erase(mi++);
+ bitdb.mapFileUseCount.erase(_mi++);
LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
}
}
@@ -941,7 +940,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
}
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
- boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
+ std::unique_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 22f02a3d0d..751ded3957 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -12,7 +12,7 @@ class CBlockIndex;
class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
{
private:
- uint32_t nSequence; //! upcounting per message sequence number
+ uint32_t nSequence; //!< upcounting per message sequence number
public: