aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--README.md2
-rw-r--r--configure.ac2
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml2
-rwxr-xr-xdepends/config.guess5
-rwxr-xr-xdepends/config.sub8
-rw-r--r--depends/packages/boost.mk6
-rw-r--r--depends/packages/miniupnpc.mk6
-rw-r--r--depends/packages/native_ccache.mk4
-rw-r--r--depends/packages/zeromq.mk4
-rw-r--r--doc/Doxyfile2
-rw-r--r--doc/README.md2
-rw-r--r--doc/README_windows.txt2
-rw-r--r--doc/build-unix.md2
-rw-r--r--doc/release-notes.md268
-rwxr-xr-xqa/pull-tester/rpc-tests.py9
-rw-r--r--qa/rpc-tests/README.md5
-rwxr-xr-xqa/rpc-tests/invalidblockrequest.py6
-rwxr-xr-xqa/rpc-tests/invalidtxrequest.py76
-rwxr-xr-xqa/rpc-tests/maxblocksinflight.py1
-rwxr-xr-xqa/rpc-tests/maxuploadtarget.py1
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py1
-rwxr-xr-xqa/rpc-tests/sendheaders.py3
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py41
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py24
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py2
-rw-r--r--qa/rpc-tests/test_framework/util.py5
-rw-r--r--src/Makefile.am1
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/alert.cpp2
-rw-r--r--src/bloom.cpp77
-rw-r--r--src/bloom.h26
-rw-r--r--src/chainparams.cpp1
-rw-r--r--src/clientversion.h2
-rw-r--r--src/main.cpp184
-rw-r--r--src/main.h11
-rw-r--r--src/mruset.h65
-rw-r--r--src/net.cpp42
-rw-r--r--src/net.h46
-rw-r--r--src/protocol.cpp67
-rw-r--r--src/protocol.h159
-rw-r--r--src/qt/guiutil.cpp3
-rw-r--r--src/qt/locale/bitcoin_en.ts37
-rw-r--r--src/qt/transactiondesc.cpp4
-rw-r--r--src/qt/utilitydialog.cpp14
-rw-r--r--src/rpcnet.cpp22
-rw-r--r--src/rpcrawtransaction.cpp1
-rw-r--r--src/test/DoS_tests.cpp14
-rw-r--r--src/test/mruset_tests.cpp81
-rw-r--r--src/wallet/test/wallet_tests.cpp18
-rw-r--r--src/wallet/wallet.cpp30
-rw-r--r--src/wallet/wallet.h1
54 files changed, 744 insertions, 660 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1d42dea843..53d6527d40 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -95,6 +95,8 @@ Anyone may participate in peer review which is expressed by comments in the pull
- Concept ACK means "I agree in the general principle of this pull request";
- Nit refers to trivial, often non-blocking issues.
+Reviewers should include the commit hash which they reviewed in their comments.
+
Project maintainers reserve the right to weigh the opinions of peer reviewers using common sense judgement and also may weight based on meritocracy: Those that have demonstrated a deeper commitment and understanding towards the project (over time) or have clear domain expertise may naturally have more weight, as one would expect in all walks of life.
Where a patch set affects consensus critical code, the bar will be set much higher in terms of discussion and peer review requirements, keeping in mind that mistakes could be very costly to the wider community. This includes refactoring of consensus critical code.
diff --git a/README.md b/README.md
index 55ab65a681..5bf56947d8 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ License
-------
Bitcoin Core is released under the terms of the MIT license. See [COPYING](COPYING) for more
-information or see http://opensource.org/licenses/MIT.
+information or see https://opensource.org/licenses/MIT.
Development Process
-------------------
diff --git a/configure.ac b/configure.ac
index 63a745393e..9161e2b2c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
-define(_CLIENT_VERSION_MINOR, 11)
+define(_CLIENT_VERSION_MINOR, 12)
define(_CLIENT_VERSION_REVISION, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, false)
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index 0c3c439dd9..52b898b675 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-linux-0.12"
+name: "bitcoin-linux-0.13"
enable_cache: true
suites:
- "trusty"
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 9ac774c8a0..cdb266d75d 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-osx-0.12"
+name: "bitcoin-osx-0.13"
enable_cache: true
suites:
- "trusty"
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 6bb482d45f..51240b2ce0 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-win-0.12"
+name: "bitcoin-win-0.13"
enable_cache: true
suites:
- "trusty"
diff --git a/depends/config.guess b/depends/config.guess
index b3f905370a..fba6e87a0f 100755
--- a/depends/config.guess
+++ b/depends/config.guess
@@ -2,7 +2,7 @@
# Attempt to guess a canonical system name.
# Copyright 1992-2015 Free Software Foundation, Inc.
-timestamp='2015-10-21'
+timestamp='2015-11-19'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -1393,6 +1393,9 @@ EOF
x86_64:VMkernel:*:*)
echo ${UNAME_MACHINE}-unknown-esx
exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
esac
cat >&2 <<EOF
diff --git a/depends/config.sub b/depends/config.sub
index 1acc966a33..ea8747d30f 100755
--- a/depends/config.sub
+++ b/depends/config.sub
@@ -2,7 +2,7 @@
# Configuration validation subroutine script.
# Copyright 1992-2015 Free Software Foundation, Inc.
-timestamp='2015-08-20'
+timestamp='2015-11-22'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -53,8 +53,7 @@ timestamp='2015-08-20'
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
- $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
Canonicalize a configuration name.
@@ -1399,7 +1398,8 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+ | -onefs* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index d27a701344..215c694b6b 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -1,8 +1,8 @@
package=boost
-$(package)_version=1_58_0
-$(package)_download_path=http://sourceforge.net/projects/boost/files/boost/1.58.0
+$(package)_version=1_59_0
+$(package)_download_path=http://sourceforge.net/projects/boost/files/boost/1.59.0
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
-$(package)_sha256_hash=fdfc204fc33ec79c99b9a74944c3e54bd78be4f7f15e260c0e2700a36dc7d3e5
+$(package)_sha256_hash=727a932322d94287b62abb1bd2d41723eec4356a7728909e38adb65ca25241ca
define $(package)_set_vars
$(package)_config_opts_release=variant=release
diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk
index 77bae10c79..3d5a6df974 100644
--- a/depends/packages/miniupnpc.mk
+++ b/depends/packages/miniupnpc.mk
@@ -1,12 +1,12 @@
package=miniupnpc
-$(package)_version=1.9.20151008
+$(package)_version=1.9.20151026
$(package)_download_path=http://miniupnp.free.fr/files
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=e444ac3b587ce82709c4d0cfca1fe71f44f9fc433e9f946b12b9e1bfe667a633
+$(package)_sha256_hash=f3cf9a5a31588a917d4d9237e5bc50f84d00c5aa48e27ed50d9b88dfa6a25d47
define $(package)_set_vars
$(package)_build_opts=CC="$($(package)_cc)"
-$(package)_build_opts_darwin=OS=Darwin
+$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)"
$(package)_build_opts_mingw32=-f Makefile.mingw
$(package)_build_env+=CFLAGS="$($(package)_cflags) $($(package)_cppflags)" AR="$($(package)_ar)"
endef
diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk
index 317674f795..cc76f9a794 100644
--- a/depends/packages/native_ccache.mk
+++ b/depends/packages/native_ccache.mk
@@ -1,8 +1,8 @@
package=native_ccache
-$(package)_version=3.2.3
+$(package)_version=3.2.4
$(package)_download_path=http://samba.org/ftp/ccache
$(package)_file_name=ccache-$($(package)_version).tar.bz2
-$(package)_sha256_hash=b07165d4949d107d17f2f84b90b52953617bf1abbf249d5cc20636f43337c98c
+$(package)_sha256_hash=ffeb967edb549e67da0bd5f44f729a2022de9fdde65dfd80d2a7204d7f75332e
define $(package)_set_vars
$(package)_config_opts=
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index 24e8e5f1c9..7b866e9c0f 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -1,8 +1,8 @@
package=zeromq
-$(package)_version=4.0.4
+$(package)_version=4.0.7
$(package)_download_path=http://download.zeromq.org
$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=1ef71d46e94f33e27dd5a1661ed626cd39be4d2d6967792a275040e34457d399
+$(package)_sha256_hash=e00b2967e074990d0538361cc79084a0a92892df2c6e7585da34e4c61ee47b03
define $(package)_set_vars
$(package)_config_opts=--without-documentation --disable-shared
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 925a33ee89..428fba98e1 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -34,7 +34,7 @@ PROJECT_NAME = Bitcoin
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.11.99
+PROJECT_NUMBER = 0.12.99
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
diff --git a/doc/README.md b/doc/README.md
index f6df28a89b..c0f9ee5220 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -1,4 +1,4 @@
-Bitcoin Core 0.11.99
+Bitcoin Core 0.12.99
=====================
Setup
diff --git a/doc/README_windows.txt b/doc/README_windows.txt
index e4fd9bdf90..2d1c4503c9 100644
--- a/doc/README_windows.txt
+++ b/doc/README_windows.txt
@@ -1,4 +1,4 @@
-Bitcoin Core 0.11.99
+Bitcoin Core 0.12.99
=====================
Intro
diff --git a/doc/build-unix.md b/doc/build-unix.md
index 159a140608..31bbab7f0f 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -61,7 +61,7 @@ Dependency Build Instructions: Ubuntu & Debian
----------------------------------------------
Build requirements:
- sudo apt-get install build-essential libtool autotools-dev autoconf pkg-config libssl-dev libevent-dev bsdmainutils
+ sudo apt-get install build-essential libtool autotools-dev automake pkg-config libssl-dev libevent-dev bsdmainutils
On at least Ubuntu 14.04+ and Debian 7+ there are generic names for the
individual boost development packages, so the following can be used to only
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 96c830d177..8bb842ddb8 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -4,236 +4,11 @@ release-notes at release time)
Notable changes
===============
-SSL support for RPC dropped
-----------------------------
+Example item
+----------------
-SSL support for RPC, previously enabled by the option `rpcssl` has been dropped
-from both the client and the server. This was done in preparation for removing
-the dependency on OpenSSL for the daemon completely.
-Trying to use `rpcssl` will result in an error:
-
- Error: SSL mode for RPC (-rpcssl) is no longer supported.
-
-If you are one of the few people that relies on this feature, a flexible
-migration path is to use `stunnel`. This is an utility that can tunnel
-arbitrary TCP connections inside SSL. On e.g. Ubuntu it can be installed with:
-
- sudo apt-get install stunnel4
-
-Then, to tunnel a SSL connection on 28332 to a RPC server bound on localhost on port 18332 do:
-
- stunnel -d 28332 -r 127.0.0.1:18332 -p stunnel.pem -P ''
-
-It can also be set up system-wide in inetd style.
-
-Another way to re-attain SSL would be to setup a httpd reverse proxy. This solution
-would allow the use of different authentication, loadbalancing, on-the-fly compression and
-caching. A sample config for apache2 could look like:
-
- Listen 443
-
- NameVirtualHost *:443
- <VirtualHost *:443>
-
- SSLEngine On
- SSLCertificateFile /etc/apache2/ssl/server.crt
- SSLCertificateKeyFile /etc/apache2/ssl/server.key
-
- <Location /bitcoinrpc>
- ProxyPass http://127.0.0.1:8332/
- ProxyPassReverse http://127.0.0.1:8332/
- # optional enable digest auth
- # AuthType Digest
- # ...
-
- # optional bypass bitcoind rpc basic auth
- # RequestHeader set Authorization "Basic <hash>"
- # get the <hash> from the shell with: base64 <<< bitcoinrpc:<password>
- </Location>
-
- # Or, balance the load:
- # ProxyPass / balancer://balancer_cluster_name
-
- </VirtualHost>
-
-Random-cookie RPC authentication
----------------------------------
-
-When no `-rpcpassword` is specified, the daemon now uses a special 'cookie'
-file for authentication. This file is generated with random content when the
-daemon starts, and deleted when it exits. Its contents are used as
-authentication token. Read access to this file controls who can access through
-RPC. By default it is stored in the data directory but its location can be
-overridden with the option `-rpccookiefile`.
-
-This is similar to Tor's CookieAuthentication: see
-https://www.torproject.org/docs/tor-manual.html.en
-
-This allows running bitcoind without having to do any manual configuration.
-
-Low-level RPC API changes
---------------------------
-
-- Monetary amounts can be provided as strings. This means that for example the
- argument to sendtoaddress can be "0.0001" instead of 0.0001. This can be an
- advantage if a JSON library insists on using a lossy floating point type for
- numbers, which would be dangerous for monetary amounts.
-
-Option parsing behavior
------------------------
-
-Command line options are now parsed strictly in the order in which they are
-specified. It used to be the case that `-X -noX` ends up, unintuitively, with X
-set, as `-X` had precedence over `-noX`. This is no longer the case. Like for
-other software, the last specified value for an option will hold.
-
-`NODE_BLOOM` service bit
-------------------------
-
-Support for the `NODE_BLOOM` service bit, as described in [BIP
-111](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki), has been
-added to the P2P protocol code.
-
-BIP 111 defines a service bit to allow peers to advertise that they support
-bloom filters (such as used by SPV clients) explicitly. It also bumps the protocol
-version to allow peers to identify old nodes which allow bloom filtering of the
-connection despite lacking the new service bit.
-
-In this version, it is only enforced for peers that send protocol versions
-`>=70011`. For the next major version it is planned that this restriction will be
-removed. It is recommended to update SPV clients to check for the `NODE_BLOOM`
-service bit for nodes that report versions newer than 70011.
-
-Any sequence of pushdatas in OP_RETURN outputs now allowed
-----------------------------------------------------------
-
-Previously OP_RETURN outputs with a payload were only relayed and mined if they
-had a single pushdata. This restriction has been lifted to allow any
-combination of data pushes and numeric constant opcodes (OP_1 to OP_16). The
-limit on OP_RETURN output size is now applied to the entire serialized
-scriptPubKey, 83 bytes by default. (the previous 80 byte default plus three
-bytes overhead)
-
-Merkle branches removed from wallet
------------------------------------
-
-Previously, every wallet transaction stored a Merkle branch to prove its
-presence in blocks. This wasn't being used for more than an expensive
-sanity check. Since 0.12, these are no longer stored. When loading a
-0.12 wallet into an older version, it will automatically rescan to avoid
-failed checks.
-
-BIP65 - CHECKLOCKTIMEVERIFY
----------------------------
-
-Previously it was impossible to create a transaction output that was guaranteed
-to be unspendable until a specific date in the future. CHECKLOCKTIMEVERIFY is a
-new opcode that allows a script to check if a specific block height or time has
-been reached, failing the script otherwise. This enables a wide variety of new
-functionality such as time-locked escrows, secure payment channels, etc.
-
-BIP65 implements CHECKLOCKTIMEVERIFY by introducing block version 4, which adds
-additional restrictions to the NOP2 opcode. The same miner-voting mechanism as
-in BIP34 and BIP66 is used: when 751 out of a sequence of 1001 blocks have
-version number 4 or higher, the new consensus rule becomes active for those
-blocks. When 951 out of a sequence of 1001 blocks have version number 4 or
-higher, it becomes mandatory for all blocks and blocks with versions less than
-4 are rejected.
-
-Bitcoin Core's block templates are now for version 4 blocks only, and any
-mining software relying on its `getblocktemplate` must be updated in parallel
-to use either libblkmaker version 0.4.3 or any version from 0.5.2 onward. If
-you are solo mining, this will affect you the moment you upgrade Bitcoin Core,
-which must be done prior to BIP65 achieving its 951/1001 status. If you are
-mining with the stratum mining protocol: this does not affect you. If you are
-mining with the getblocktemplate protocol to a pool: this will affect you at
-the pool operator's discretion, which must be no later than BIP65 achieving its
-951/1001 status.
-
-Automatically use Tor hidden services
--------------------------------------
-
-Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket
-API, to create and destroy 'ephemeral' hidden services programmatically.
-Bitcoin Core has been updated to make use of this.
-
-This means that if Tor is running (and proper authorization is available),
-Bitcoin Core automatically creates a hidden service to listen on, without
-manual configuration. Bitcoin Core will also use Tor automatically to connect
-to other .onion nodes if the control socket can be successfully opened. This
-will positively affect the number of available .onion nodes and their usage.
-
-This new feature is enabled by default if Bitcoin Core is listening, and
-a connection to Tor can be made. It can be configured with the `-listenonion`,
-`-torcontrol` and `-torpassword` settings. To show verbose debugging
-information, pass `-debug=tor`.
-
-Reduce upload traffic
----------------------
-
-A major part of the outbound traffic is caused by serving historic blocks to
-other nodes in initial block download state.
-
-It is now possible to reduce the total upload traffic via the `-maxuploadtarget`
-parameter. This is *not* a hard limit but a threshold to minimize the outbound
-traffic. When the limit is about to be reached, the uploaded data is cut by not
-serving historic blocks (blocks older than one week).
-Moreover, any SPV peer is disconnected when they request a filtered block.
-
-This option can be specified in MiB per day and is turned off by default
-(`-maxuploadtarget=0`).
-The recommended minimum is 144 * MAX_BLOCK_SIZE (currently 144MB) per day.
-
-Whitelisted peers will never be disconnected, although their traffic counts for
-calculating the target.
-
-A more detailed documentation about keeping traffic low can be found in
-[/doc/reducetraffic.md](/doc/reducetraffic.md).
-
-Signature validation using libsecp256k1
----------------------------------------
-
-ECDSA signatures inside Bitcoin transactions now use validation using
-[https://github.com/bitcoin/secp256k1](libsecp256k1) instead of OpenSSL.
-
-Depending on the platform, this means a significant speedup for raw signature
-validation speed. The advantage is largest on x86_64, where validation is over
-five times faster. In practice, this translates to a raw reindexing and new
-block validation times that are less than half of what it was before.
-
-Libsecp256k1 has undergone very extensive testing and validation.
-
-A side effect of this change is that libconsensus no longer depends on OpenSSL.
-
-Direct headers announcement (BIP 130)
--------------------------------------
-
-Between compatible peers, BIP 130 direct headers announcement is used. This
-means that blocks are advertized by announcing their headers directly, instead
-of just announcing the hash. In a reorganization, all new headers are sent,
-instead of just the new tip. This can often prevent an extra roundtrip before
-the actual block is downloaded.
-
-Negative confirmations and conflict detection
----------------------------------------------
-
-The wallet will now report a negative number for confirmations that indicates
-how deep in the block chain the conflict is found. For example, if a transaction
-A has 5 confirmations and spends the same input as a wallet transaction B, B
-will be reported as having -5 confirmations. If another wallet transaction C
-spends an output from B, it will also be reported as having -5 confirmations.
-To detect conflicts with historical transactions in the chain a one-time
-`-rescan` may be needed.
-
-Unlike earlier versions, unconfirmed but non-conflicting transactions will never
-get a negative confirmation count. They are not treated as spendable unless
-they're coming from ourself (change) and accepted into our local mempool,
-however. The new "trusted" field in the `listtransactions` RPC output
-indicates whether outputs of an unconfirmed transaction are considered
-spendable.
-
-0.12.0 Change log
+0.13.0 Change log
=================
Detailed release notes follow. This overview includes changes that affect
@@ -243,33 +18,6 @@ git merge commit are mentioned.
### RPC and REST
-Asm representations of scriptSig signatures now contain SIGHASH type decodes
-----------------------------------------------------------------------------
-
-The `asm` property of each scriptSig now contains the decoded signature hash
-type for each signature that provides a valid defined hash type.
-
-The following items contain assembly representations of scriptSig signatures
-and are affected by this change:
-
-- RPC `getrawtransaction`
-- RPC `decoderawtransaction`
-- REST `/rest/tx/` (JSON format)
-- REST `/rest/block/` (JSON format when including extended tx details)
-- `bitcoin-tx -json`
-
-For example, the `scriptSig.asm` property of a transaction input that
-previously showed an assembly representation of:
-
- 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001
-
-now shows as:
-
- 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL]
-
-Note that the output of the RPC `decodescript` did not change because it is
-configured specifically to process scriptPubKey and not scriptSig scripts.
-
### Configuration and command-line options
### Block and transaction handling
@@ -288,13 +36,3 @@ configured specifically to process scriptPubKey and not scriptSig scripts.
### Miscellaneous
-- Removed bitrpc.py from contrib
-
-Addition of ZMQ-based Notifications
-==================================
-
-Bitcoind can now (optionally) asynchronously notify clients through a
-ZMQ-based PUB socket of the arrival of new transactions and blocks.
-This feature requires installation of the ZMQ C API library 4.x and
-configuring its use through the command line or configuration file.
-Please see docs/zmq.md for details of operation.
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index df71e44b60..57b4233449 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -62,8 +62,10 @@ for arg in sys.argv[1:]:
#Set env vars
buildDir = BUILDDIR
-os.environ["BITCOIND"] = buildDir + '/src/bitcoind' + EXEEXT
-os.environ["BITCOINCLI"] = buildDir + '/src/bitcoin-cli' + EXEEXT
+if "BITCOIND" not in os.environ:
+ os.environ["BITCOIND"] = buildDir + '/src/bitcoind' + EXEEXT
+if "BITCOINCLI" not in os.environ:
+ os.environ["BITCOINCLI"] = buildDir + '/src/bitcoin-cli' + EXEEXT
#Disable Windows tests by default
if EXEEXT == ".exe" and "-win" not in opts:
@@ -100,6 +102,8 @@ testScripts = [
'sendheaders.py',
'keypool.py',
'prioritise_transaction.py',
+ 'invalidblockrequest.py',
+ 'invalidtxrequest.py',
]
testScriptsExt = [
'bip65-cltv.py',
@@ -116,7 +120,6 @@ testScriptsExt = [
# 'rpcbind_test.py', #temporary, bug in libevent, see #6655
'smartfees.py',
'maxblocksinflight.py',
- 'invalidblockrequest.py',
'p2p-acceptblock.py',
'mempool_packages.py',
'maxuploadtarget.py',
diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md
index 898931936b..651b01f18a 100644
--- a/qa/rpc-tests/README.md
+++ b/qa/rpc-tests/README.md
@@ -47,10 +47,7 @@ implements the test logic.
* ```NodeConn``` is the class used to connect to a bitcoind. If you implement
a callback class that derives from ```NodeConnCB``` and pass that to the
```NodeConn``` object, your code will receive the appropriate callbacks when
-events of interest arrive. NOTE: be sure to call
-```self.create_callback_map()``` in your derived classes' ```__init__```
-function, so that the correct mappings are set up between p2p messages and your
-callback functions.
+events of interest arrive.
* You can pass the same handler to multiple ```NodeConn```'s if you like, or pass
different ones to each -- whatever makes the most sense for your test.
diff --git a/qa/rpc-tests/invalidblockrequest.py b/qa/rpc-tests/invalidblockrequest.py
index 6a7980cd45..a74ecb1288 100755
--- a/qa/rpc-tests/invalidblockrequest.py
+++ b/qa/rpc-tests/invalidblockrequest.py
@@ -6,7 +6,7 @@
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import *
-from test_framework.comptool import TestManager, TestInstance
+from test_framework.comptool import TestManager, TestInstance, RejectResult
from test_framework.mininode import *
from test_framework.blocktools import *
import logging
@@ -97,7 +97,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
assert(block2_orig.vtx != block2.vtx)
self.tip = block2.sha256
- yield TestInstance([[block2, False], [block2_orig, True]])
+ yield TestInstance([[block2, RejectResult(16,'bad-txns-duplicate')], [block2_orig, True]])
height += 1
'''
@@ -112,7 +112,7 @@ class InvalidBlockRequestTest(ComparisonTestFramework):
block3.rehash()
block3.solve()
- yield TestInstance([[block3, False]])
+ yield TestInstance([[block3, RejectResult(16,'bad-cb-amount')]])
if __name__ == '__main__':
diff --git a/qa/rpc-tests/invalidtxrequest.py b/qa/rpc-tests/invalidtxrequest.py
new file mode 100755
index 0000000000..d17b3d0980
--- /dev/null
+++ b/qa/rpc-tests/invalidtxrequest.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python2
+#
+# Distributed under the MIT/X11 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.comptool import TestManager, TestInstance, RejectResult
+from test_framework.mininode import *
+from test_framework.blocktools import *
+import logging
+import copy
+import time
+
+
+'''
+In this test we connect to one node over p2p, and test tx requests.
+'''
+
+# Use the ComparisonTestFramework with 1 node: only use --testbinary.
+class InvalidTxRequestTest(ComparisonTestFramework):
+
+ ''' Can either run this test as 1 node with expected answers, or two and compare them.
+ Change the "outcome" variable from each TestInstance object to only do the comparison. '''
+ def __init__(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ test = TestManager(self, self.options.tmpdir)
+ test.add_all_connections(self.nodes)
+ self.tip = None
+ self.block_time = None
+ NetworkThread().start() # Start up network handling in another thread
+ test.run()
+
+ def get_tests(self):
+ if self.tip is None:
+ self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0)
+ self.block_time = int(time.time())+1
+
+ '''
+ Create a new block with an anyone-can-spend coinbase
+ '''
+ height = 1
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ self.block_time += 1
+ block.solve()
+ # Save the coinbase for later
+ self.block1 = block
+ self.tip = block.sha256
+ height += 1
+ yield TestInstance([[block, True]])
+
+ '''
+ Now we need that block to mature so we can spend the coinbase.
+ '''
+ test = TestInstance(sync_every_block=False)
+ for i in xrange(100):
+ block = create_block(self.tip, create_coinbase(height), self.block_time)
+ block.solve()
+ self.tip = block.sha256
+ self.block_time += 1
+ test.blocks_and_transactions.append([block, True])
+ height += 1
+ yield test
+
+ # chr(100) is OP_NOTIF
+ # Transaction will be rejected with code 16 (REJECT_INVALID)
+ tx1 = create_transaction(self.block1.vtx[0], 0, chr(100), 50*100000000)
+ yield TestInstance([[tx1, RejectResult(16, 'mandatory-script-verify-flag-failed')]])
+
+ # TODO: test further transactions...
+
+if __name__ == '__main__':
+ InvalidTxRequestTest().main()
diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py
index a601147ce8..1a9ae480ab 100755
--- a/qa/rpc-tests/maxblocksinflight.py
+++ b/qa/rpc-tests/maxblocksinflight.py
@@ -34,7 +34,6 @@ class TestManager(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
self.log = logging.getLogger("BlockRelayTest")
- self.create_callback_map()
def add_new_connection(self, connection):
self.connection = connection
diff --git a/qa/rpc-tests/maxuploadtarget.py b/qa/rpc-tests/maxuploadtarget.py
index e714465db1..249663779c 100755
--- a/qa/rpc-tests/maxuploadtarget.py
+++ b/qa/rpc-tests/maxuploadtarget.py
@@ -25,7 +25,6 @@ if uploadtarget has been reached.
class TestNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
index 700deab207..23872d8494 100755
--- a/qa/rpc-tests/p2p-acceptblock.py
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -62,7 +62,6 @@ The test:
class TestNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py
index d7f4292090..e6e26dbce3 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -70,7 +70,6 @@ f. Announce 1 more header that builds on that fork.
class BaseNode(NodeConnCB):
def __init__(self):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.connection = None
self.last_inv = None
self.last_headers = None
@@ -389,7 +388,7 @@ class SendHeadersTest(BitcoinTestFramework):
# Use getblocks/getdata
test_node.send_getblocks(locator = [fork_point])
- assert_equal(test_node.check_last_announcement(inv=new_block_hashes[0:-1]), True)
+ assert_equal(test_node.check_last_announcement(inv=new_block_hashes), True)
test_node.get_data(new_block_hashes)
test_node.wait_for_block(new_block_hashes[-1])
diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py
index e0b3ce040d..badbc0a1fb 100755
--- a/qa/rpc-tests/test_framework/comptool.py
+++ b/qa/rpc-tests/test_framework/comptool.py
@@ -41,17 +41,32 @@ def wait_until(predicate, attempts=float('inf'), timeout=float('inf')):
return False
+class RejectResult(object):
+ '''
+ Outcome that expects rejection of a transaction or block.
+ '''
+ def __init__(self, code, reason=''):
+ self.code = code
+ self.reason = reason
+ def match(self, other):
+ if self.code != other.code:
+ return False
+ return other.reason.startswith(self.reason)
+ def __repr__(self):
+ return '%i:%s' % (self.code,self.reason or '*')
+
class TestNode(NodeConnCB):
def __init__(self, block_store, tx_store):
NodeConnCB.__init__(self)
- self.create_callback_map()
self.conn = None
self.bestblockhash = None
self.block_store = block_store
self.block_request_map = {}
self.tx_store = tx_store
self.tx_request_map = {}
+ self.block_reject_map = {}
+ self.tx_reject_map = {}
# When the pingmap is non-empty we're waiting for
# a response
@@ -95,6 +110,12 @@ class TestNode(NodeConnCB):
except KeyError:
raise AssertionError("Got pong for unknown ping [%s]" % repr(message))
+ def on_reject(self, conn, message):
+ if message.message == 'tx':
+ self.tx_reject_map[message.data] = RejectResult(message.code, message.reason)
+ if message.message == 'block':
+ self.block_reject_map[message.data] = RejectResult(message.code, message.reason)
+
def send_inv(self, obj):
mtype = 2 if isinstance(obj, CBlock) else 1
self.conn.send_message(msg_inv([CInv(mtype, obj.sha256)]))
@@ -244,6 +265,15 @@ class TestManager(object):
if outcome is None:
if c.cb.bestblockhash != self.connections[0].cb.bestblockhash:
return False
+ elif isinstance(outcome, RejectResult): # Check that block was rejected w/ code
+ if c.cb.bestblockhash == blockhash:
+ return False
+ if blockhash not in c.cb.block_reject_map:
+ print 'Block not in reject map: %064x' % (blockhash)
+ return False
+ if not outcome.match(c.cb.block_reject_map[blockhash]):
+ print 'Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash)
+ return False
elif ((c.cb.bestblockhash == blockhash) != outcome):
# print c.cb.bestblockhash, blockhash, outcome
return False
@@ -263,6 +293,15 @@ class TestManager(object):
if c.cb.lastInv != self.connections[0].cb.lastInv:
# print c.rpc.getrawmempool()
return False
+ elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code
+ if txhash in c.cb.lastInv:
+ return False
+ if txhash not in c.cb.tx_reject_map:
+ print 'Tx not in reject map: %064x' % (txhash)
+ return False
+ if not outcome.match(c.cb.tx_reject_map[txhash]):
+ print 'Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash)
+ return False
elif ((txhash in c.cb.lastInv) != outcome):
# print c.rpc.getrawmempool(), c.cb.lastInv
return False
diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py
index 64985d58e2..9d0fb713a1 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -1015,32 +1015,10 @@ class NodeConnCB(object):
return
time.sleep(0.05)
- # Derived classes should call this function once to set the message map
- # which associates the derived classes' functions to incoming messages
- def create_callback_map(self):
- self.cbmap = {
- "version": self.on_version,
- "verack": self.on_verack,
- "addr": self.on_addr,
- "alert": self.on_alert,
- "inv": self.on_inv,
- "getdata": self.on_getdata,
- "getblocks": self.on_getblocks,
- "tx": self.on_tx,
- "block": self.on_block,
- "getaddr": self.on_getaddr,
- "ping": self.on_ping,
- "pong": self.on_pong,
- "headers": self.on_headers,
- "getheaders": self.on_getheaders,
- "reject": self.on_reject,
- "mempool": self.on_mempool
- }
-
def deliver(self, conn, message):
with mininode_lock:
try:
- self.cbmap[message.command](conn, message)
+ getattr(self, 'on_' + message.command)(conn, message)
except:
print "ERROR delivering %s (%s)" % (repr(message),
sys.exc_info()[0])
diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py
index ae2d91ab60..86d2f06df7 100755
--- a/qa/rpc-tests/test_framework/test_framework.py
+++ b/qa/rpc-tests/test_framework/test_framework.py
@@ -120,7 +120,7 @@ class BitcoinTestFramework(object):
if self.options.coveragedir:
enable_coverage(self.options.coveragedir)
- os.environ['PATH'] = self.options.srcdir+":"+os.environ['PATH']
+ os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH']
check_json_precision()
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index b7e90a8a8b..4948680bad 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -107,6 +107,7 @@ def initialize_datadir(dirname, n):
f.write("rpcpassword=rt\n");
f.write("port="+str(p2p_port(n))+"\n");
f.write("rpcport="+str(rpc_port(n))+"\n");
+ f.write("listenonion=0\n");
return datadir
def initialize_chain(test_dir):
@@ -130,7 +131,7 @@ def initialize_chain(test_dir):
# Create cache directories, run bitcoinds:
for i in range(4):
datadir=initialize_datadir("cache", i)
- args = [ os.getenv("BITCOIND", "bitcoind"), "-keypool=1", "-datadir="+datadir, "-discover=0" ]
+ args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ]
if i > 0:
args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
bitcoind_processes[i] = subprocess.Popen(args)
@@ -218,7 +219,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
if binary is None:
binary = os.getenv("BITCOIND", "bitcoind")
# RPC tests still depend on free transactions
- args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest", "-blockprioritysize=50000" ]
+ args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-blockprioritysize=50000" ]
if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args)
devnull = open(os.devnull, "w")
diff --git a/src/Makefile.am b/src/Makefile.am
index bb627a5448..5da1a873de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -117,7 +117,6 @@ BITCOIN_CORE_H = \
memusage.h \
merkleblock.h \
miner.h \
- mruset.h \
net.h \
netbase.h \
noui.h \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 4d0894b711..d89132f806 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -59,7 +59,6 @@ BITCOIN_TESTS =\
test/mempool_tests.cpp \
test/merkle_tests.cpp \
test/miner_tests.cpp \
- test/mruset_tests.cpp \
test/multisig_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
diff --git a/src/alert.cpp b/src/alert.cpp
index 91e54a9178..b705069407 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -138,7 +138,7 @@ bool CAlert::RelayTo(CNode* pnode) const
AppliesToMe() ||
GetAdjustedTime() < nRelayUntil)
{
- pnode->PushMessage("alert", *this);
+ pnode->PushMessage(NetMsgType::ALERT, *this);
return true;
}
}
diff --git a/src/bloom.cpp b/src/bloom.cpp
index de87206592..4bda2bbce4 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -216,30 +216,54 @@ void CBloomFilter::UpdateEmptyFull()
isEmpty = empty;
}
-CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) :
- b1(nElements * 2, fpRate, 0), b2(nElements * 2, fpRate, 0)
+CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate)
{
- // Implemented using two bloom filters of 2 * nElements each.
- // We fill them up, and clear them, staggered, every nElements
- // inserted, so at least one always contains the last nElements
- // inserted.
- nInsertions = 0;
- nBloomSize = nElements * 2;
-
+ double logFpRate = log(fpRate);
+ /* The optimal number of hash functions is log(fpRate) / log(0.5), but
+ * restrict it to the range 1-50. */
+ nHashFuncs = std::max(1, std::min((int)round(logFpRate / log(0.5)), 50));
+ /* In this rolling bloom filter, we'll store between 2 and 3 generations of nElements / 2 entries. */
+ nEntriesPerGeneration = (nElements + 1) / 2;
+ uint32_t nMaxElements = nEntriesPerGeneration * 3;
+ /* The maximum fpRate = pow(1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits), nHashFuncs)
+ * => pow(fpRate, 1.0 / nHashFuncs) = 1.0 - exp(-nHashFuncs * nMaxElements / nFilterBits)
+ * => 1.0 - pow(fpRate, 1.0 / nHashFuncs) = exp(-nHashFuncs * nMaxElements / nFilterBits)
+ * => log(1.0 - pow(fpRate, 1.0 / nHashFuncs)) = -nHashFuncs * nMaxElements / nFilterBits
+ * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - pow(fpRate, 1.0 / nHashFuncs))
+ * => nFilterBits = -nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs))
+ */
+ uint32_t nFilterBits = (uint32_t)ceil(-1.0 * nHashFuncs * nMaxElements / log(1.0 - exp(logFpRate / nHashFuncs)));
+ data.clear();
+ /* We store up to 16 'bits' per data element. */
+ data.resize((nFilterBits + 15) / 16);
reset();
}
+/* Similar to CBloomFilter::Hash */
+inline unsigned int CRollingBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const {
+ return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (data.size() * 16);
+}
+
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
{
- if (nInsertions == 0) {
- b1.clear();
- } else if (nInsertions == nBloomSize / 2) {
- b2.clear();
+ if (nEntriesThisGeneration == nEntriesPerGeneration) {
+ nEntriesThisGeneration = 0;
+ nGeneration++;
+ if (nGeneration == 4) {
+ nGeneration = 1;
+ }
+ /* Wipe old entries that used this generation number. */
+ for (uint32_t p = 0; p < data.size() * 16; p++) {
+ if (get(p) == nGeneration) {
+ put(p, 0);
+ }
+ }
}
- b1.insert(vKey);
- b2.insert(vKey);
- if (++nInsertions == nBloomSize) {
- nInsertions = 0;
+ nEntriesThisGeneration++;
+
+ for (int n = 0; n < nHashFuncs; n++) {
+ uint32_t h = Hash(n, vKey);
+ put(h, nGeneration);
}
}
@@ -251,10 +275,13 @@ void CRollingBloomFilter::insert(const uint256& hash)
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
- if (nInsertions < nBloomSize / 2) {
- return b2.contains(vKey);
+ for (int n = 0; n < nHashFuncs; n++) {
+ uint32_t h = Hash(n, vKey);
+ if (get(h) == 0) {
+ return false;
+ }
}
- return b1.contains(vKey);
+ return true;
}
bool CRollingBloomFilter::contains(const uint256& hash) const
@@ -265,8 +292,10 @@ bool CRollingBloomFilter::contains(const uint256& hash) const
void CRollingBloomFilter::reset()
{
- unsigned int nNewTweak = GetRand(std::numeric_limits<unsigned int>::max());
- b1.reset(nNewTweak);
- b2.reset(nNewTweak);
- nInsertions = 0;
+ nTweak = GetRand(std::numeric_limits<unsigned int>::max());
+ nEntriesThisGeneration = 0;
+ nGeneration = 1;
+ for (std::vector<uint32_t>::iterator it = data.begin(); it != data.end(); it++) {
+ *it = 0;
+ }
}
diff --git a/src/bloom.h b/src/bloom.h
index a4dba8cb4f..98cfbdb833 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -110,8 +110,11 @@ public:
* reset() is provided, which also changes nTweak to decrease the impact of
* false-positives.
*
- * contains(item) will always return true if item was one of the last N things
+ * contains(item) will always return true if item was one of the last N to 1.5*N
* insert()'ed ... but may also return true for items that were not inserted.
+ *
+ * It needs around 1.8 bytes per element per factor 0.1 of false positive rate.
+ * (More accurately: 3/(log(256)*log(2)) * log(1/fpRate) * nElements bytes)
*/
class CRollingBloomFilter
{
@@ -129,10 +132,23 @@ public:
void reset();
private:
- unsigned int nBloomSize;
- unsigned int nInsertions;
- CBloomFilter b1, b2;
-};
+ int nEntriesPerGeneration;
+ int nEntriesThisGeneration;
+ int nGeneration;
+ std::vector<uint32_t> data;
+ unsigned int nTweak;
+ int nHashFuncs;
+
+ unsigned int Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const;
+ inline int get(uint32_t position) const {
+ return (data[(position >> 4) % data.size()] >> (2 * (position & 0xF))) & 0x3;
+ }
+
+ inline void put(uint32_t position, uint32_t val) {
+ uint32_t& cell = data[(position >> 4) % data.size()];
+ cell = (cell & ~(((uint32_t)3) << (2 * (position & 0xF)))) | (val << (2 * (position & 0xF)));
+ }
+};
#endif // BITCOIN_BLOOM_H
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index a46866a2be..abeaaf927c 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -179,7 +179,6 @@ public:
vFixedSeeds.clear();
vSeeds.clear();
- vSeeds.push_back(CDNSSeedData("alexykot.me", "testnet-seed.alexykot.me"));
vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org"));
vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
diff --git a/src/clientversion.h b/src/clientversion.h
index 5a06b310a3..cd947a9761 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -15,7 +15,7 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
-#define CLIENT_VERSION_MINOR 11
+#define CLIENT_VERSION_MINOR 12
#define CLIENT_VERSION_REVISION 99
#define CLIENT_VERSION_BUILD 0
diff --git a/src/main.cpp b/src/main.cpp
index 9363015a5a..a43eef07b5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -181,7 +181,7 @@ namespace {
* million to make it highly unlikely for users to have issues with this
* filter.
*
- * Memory used: 1.7MB
+ * Memory used: 1.3 MB
*/
boost::scoped_ptr<CRollingBloomFilter> recentRejects;
uint256 hashRecentRejectsChainTip;
@@ -4144,14 +4144,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
if (!ReadBlockFromDisk(block, (*mi).second, consensusParams))
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
- pfrom->PushMessage("block", block);
+ pfrom->PushMessage(NetMsgType::BLOCK, block);
else // MSG_FILTERED_BLOCK)
{
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
{
CMerkleBlock merkleBlock(block, *pfrom->pfilter);
- pfrom->PushMessage("merkleblock", merkleBlock);
+ 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
// Note that there is currently no way for a node to request any single transactions we didn't send here -
@@ -4160,8 +4160,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
- if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, pair.second)))
- pfrom->PushMessage("tx", block.vtx[pair.first]);
+ pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]);
}
// else
// no response
@@ -4175,7 +4174,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// wait for other stuff first.
vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash()));
- pfrom->PushMessage("inv", vInv);
+ pfrom->PushMessage(NetMsgType::INV, vInv);
pfrom->hashContinue.SetNull();
}
}
@@ -4198,7 +4197,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(1000);
ss << tx;
- pfrom->PushMessage("tx", ss);
+ pfrom->PushMessage(NetMsgType::TX, ss);
pushed = true;
}
}
@@ -4225,7 +4224,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// do that because they want to know about (and store and rebroadcast and
// risk analyze) the dependencies of transactions relevant to them, without
// having to download the entire memory pool.
- pfrom->PushMessage("notfound", vNotFound);
+ pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound);
}
}
@@ -4242,9 +4241,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!(nLocalServices & NODE_BLOOM) &&
- (strCommand == "filterload" ||
- strCommand == "filteradd" ||
- strCommand == "filterclear"))
+ (strCommand == NetMsgType::FILTERLOAD ||
+ strCommand == NetMsgType::FILTERADD ||
+ strCommand == NetMsgType::FILTERCLEAR))
{
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
Misbehaving(pfrom->GetId(), 100);
@@ -4256,12 +4255,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- if (strCommand == "version")
+ if (strCommand == NetMsgType::VERSION)
{
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
- pfrom->PushMessage("reject", strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message"));
Misbehaving(pfrom->GetId(), 1);
return false;
}
@@ -4275,7 +4274,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
{
// disconnect from peers older than this proto version
LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion);
- pfrom->PushMessage("reject", strCommand, REJECT_OBSOLETE,
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE,
strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION));
pfrom->fDisconnect = true;
return false;
@@ -4320,7 +4319,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
UpdatePreferredDownload(pfrom, State(pfrom->GetId()));
// Change version
- pfrom->PushMessage("verack");
+ pfrom->PushMessage(NetMsgType::VERACK);
pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
if (!pfrom->fInbound)
@@ -4343,7 +4342,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Get recent addresses
if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
{
- pfrom->PushMessage("getaddr");
+ pfrom->PushMessage(NetMsgType::GETADDR);
pfrom->fGetAddr = true;
}
addrman.Good(pfrom->addr);
@@ -4387,7 +4386,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "verack")
+ else if (strCommand == NetMsgType::VERACK)
{
pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
@@ -4402,12 +4401,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// We send this to non-NODE NETWORK peers as well, because even
// non-NODE NETWORK peers can announce blocks (such as pruning
// nodes)
- pfrom->PushMessage("sendheaders");
+ pfrom->PushMessage(NetMsgType::SENDHEADERS);
}
}
- else if (strCommand == "addr")
+ else if (strCommand == NetMsgType::ADDR)
{
vector<CAddress> vAddr;
vRecv >> vAddr;
@@ -4473,14 +4472,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->fDisconnect = true;
}
- else if (strCommand == "sendheaders")
+ else if (strCommand == NetMsgType::SENDHEADERS)
{
LOCK(cs_main);
State(pfrom->GetId())->fPreferHeaders = true;
}
- else if (strCommand == "inv")
+ else if (strCommand == NetMsgType::INV)
{
vector<CInv> vInv;
vRecv >> vInv;
@@ -4521,7 +4520,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// time the block arrives, the header chain leading up to it is already validated. Not
// doing this will result in the received block being rejected as an orphan in case it is
// not a direct successor.
- pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash);
+ pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
CNodeState *nodestate = State(pfrom->GetId());
if (CanDirectFetch(chainparams.GetConsensus()) &&
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
@@ -4551,11 +4550,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
if (!vToFetch.empty())
- pfrom->PushMessage("getdata", vToFetch);
+ pfrom->PushMessage(NetMsgType::GETDATA, vToFetch);
}
- else if (strCommand == "getdata")
+ else if (strCommand == NetMsgType::GETDATA)
{
vector<CInv> vInv;
vRecv >> vInv;
@@ -4576,7 +4575,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "getblocks")
+ else if (strCommand == NetMsgType::GETBLOCKS)
{
CBlockLocator locator;
uint256 hashStop;
@@ -4620,7 +4619,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "getheaders")
+ else if (strCommand == NetMsgType::GETHEADERS)
{
CBlockLocator locator;
uint256 hashStop;
@@ -4665,11 +4664,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
- pfrom->PushMessage("headers", vHeaders);
+ pfrom->PushMessage(NetMsgType::HEADERS, vHeaders);
}
- else if (strCommand == "tx")
+ else if (strCommand == NetMsgType::TX)
{
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistalwaysrelay is off
@@ -4798,7 +4797,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->id,
FormatStateMessage(state));
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
- pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS);
@@ -4807,7 +4806,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "headers" && !fImporting && !fReindex) // Ignore headers received while importing
+ else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
{
std::vector<CBlockHeader> headers;
@@ -4855,7 +4854,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
// from there instead.
LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
- pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexLast), uint256());
+ pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256());
}
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
@@ -4900,7 +4899,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
}
if (vGetData.size() > 0) {
- pfrom->PushMessage("getdata", vGetData);
+ pfrom->PushMessage(NetMsgType::GETDATA, vGetData);
}
}
}
@@ -4908,7 +4907,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CheckBlockIndex(chainparams.GetConsensus());
}
- else if (strCommand == "block" && !fImporting && !fReindex) // Ignore blocks received while importing
+ else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
{
CBlock block;
vRecv >> block;
@@ -4928,7 +4927,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) {
LOCK(cs_main);
@@ -4944,7 +4943,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// to users' AddrMan and later request them by sending getaddr messages.
// Making nodes which are behind NAT and can only make outgoing connections ignore
// the getaddr message mitigates the attack.
- else if ((strCommand == "getaddr") && (pfrom->fInbound))
+ else if ((strCommand == NetMsgType::GETADDR) && (pfrom->fInbound))
{
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = addrman.GetAddr();
@@ -4953,8 +4952,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "mempool")
+ else if (strCommand == NetMsgType::MEMPOOL)
{
+ if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted)
+ {
+ LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ return true;
+ }
LOCK2(cs_main, pfrom->cs_filter);
std::vector<uint256> vtxid;
@@ -4962,23 +4967,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vector<CInv> vInv;
BOOST_FOREACH(uint256& hash, vtxid) {
CInv inv(MSG_TX, hash);
- CTransaction tx;
- bool fInMemPool = mempool.lookup(hash, tx);
- if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
- if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) ||
- (!pfrom->pfilter))
- vInv.push_back(inv);
+ if (pfrom->pfilter) {
+ CTransaction tx;
+ bool fInMemPool = mempool.lookup(hash, tx);
+ if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
+ if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue;
+ }
+ vInv.push_back(inv);
if (vInv.size() == MAX_INV_SZ) {
- pfrom->PushMessage("inv", vInv);
+ pfrom->PushMessage(NetMsgType::INV, vInv);
vInv.clear();
}
}
if (vInv.size() > 0)
- pfrom->PushMessage("inv", vInv);
+ pfrom->PushMessage(NetMsgType::INV, vInv);
}
- else if (strCommand == "ping")
+ else if (strCommand == NetMsgType::PING)
{
if (pfrom->nVersion > BIP0031_VERSION)
{
@@ -4995,12 +5001,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// it, if the remote node sends a ping once per second and this node takes 5
// seconds to respond to each, the 5th ping the remote sends would appear to
// return very quickly.
- pfrom->PushMessage("pong", nonce);
+ pfrom->PushMessage(NetMsgType::PONG, nonce);
}
}
- else if (strCommand == "pong")
+ else if (strCommand == NetMsgType::PONG)
{
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
@@ -5057,7 +5063,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (fAlerts && strCommand == "alert")
+ else if (fAlerts && strCommand == NetMsgType::ALERT)
{
CAlert alert;
vRecv >> alert;
@@ -5088,7 +5094,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "filterload")
+ else if (strCommand == NetMsgType::FILTERLOAD)
{
CBloomFilter filter;
vRecv >> filter;
@@ -5107,7 +5113,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "filteradd")
+ else if (strCommand == NetMsgType::FILTERADD)
{
vector<unsigned char> vData;
vRecv >> vData;
@@ -5127,7 +5133,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "filterclear")
+ else if (strCommand == NetMsgType::FILTERCLEAR)
{
LOCK(pfrom->cs_filter);
delete pfrom->pfilter;
@@ -5136,7 +5142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "reject")
+ else if (strCommand == NetMsgType::REJECT)
{
if (fDebug) {
try {
@@ -5146,7 +5152,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
ostringstream ss;
ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
- if (strMsg == "block" || strMsg == "tx")
+ if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX)
{
uint256 hash;
vRecv >> hash;
@@ -5254,7 +5260,7 @@ bool ProcessMessages(CNode* pfrom)
}
catch (const std::ios_base::failure& e)
{
- pfrom->PushMessage("reject", strCommand, REJECT_MALFORMED, string("error parsing message"));
+ pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message"));
if (strstr(e.what(), "end of data"))
{
// Allow exceptions from under-length message on vRecv
@@ -5293,7 +5299,7 @@ bool ProcessMessages(CNode* pfrom)
}
-bool SendMessages(CNode* pto, bool fSendTrickle)
+bool SendMessages(CNode* pto)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
@@ -5322,11 +5328,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->nPingUsecStart = GetTimeMicros();
if (pto->nVersion > BIP0031_VERSION) {
pto->nPingNonceSent = nonce;
- pto->PushMessage("ping", nonce);
+ pto->PushMessage(NetMsgType::PING, nonce);
} else {
// Peer is too old to support ping command with nonce, pong will never arrive.
pto->nPingNonceSent = 0;
- pto->PushMessage("ping");
+ pto->PushMessage(NetMsgType::PING);
}
}
@@ -5335,28 +5341,17 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
return true;
// Address refresh broadcast
- static int64_t nLastRebroadcast;
- if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- {
- // Periodically clear addrKnown to allow refresh broadcasts
- if (nLastRebroadcast)
- pnode->addrKnown.reset();
-
- // Rebroadcast our address
- AdvertizeLocal(pnode);
- }
- if (!vNodes.empty())
- nLastRebroadcast = GetTime();
+ int64_t nNow = GetTimeMicros();
+ if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ AdvertizeLocal(pto);
+ pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
//
// Message: addr
//
- if (fSendTrickle)
- {
+ if (pto->nNextAddrSend < nNow) {
+ pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
@@ -5368,14 +5363,14 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// receiver rejects addr messages larger than 1000
if (vAddr.size() >= 1000)
{
- pto->PushMessage("addr", vAddr);
+ pto->PushMessage(NetMsgType::ADDR, vAddr);
vAddr.clear();
}
}
}
pto->vAddrToSend.clear();
if (!vAddr.empty())
- pto->PushMessage("addr", vAddr);
+ pto->PushMessage(NetMsgType::ADDR, vAddr);
}
CNodeState &state = *State(pto->GetId());
@@ -5395,7 +5390,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
BOOST_FOREACH(const CBlockReject& reject, state.rejects)
- pto->PushMessage("reject", (string)"block", reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
+ pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock);
state.rejects.clear();
// Start block sync
@@ -5418,7 +5413,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
- pto->PushMessage("getheaders", chainActive.GetLocator(pindexStart), uint256());
+ pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256());
}
}
@@ -5518,7 +5513,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
vHeaders.front().GetHash().ToString(), pto->id);
}
- pto->PushMessage("headers", vHeaders);
+ pto->PushMessage(NetMsgType::HEADERS, vHeaders);
state.pindexBestHeaderSent = pBestIndex;
}
pto->vBlockHashesToAnnounce.clear();
@@ -5530,12 +5525,17 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
vector<CInv> vInv;
vector<CInv> vInvWait;
{
+ bool fSendTrickle = pto->fWhitelisted;
+ if (pto->nNextInvSend < nNow) {
+ fSendTrickle = true;
+ pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL);
+ }
LOCK(pto->cs_inventory);
- vInv.reserve(pto->vInventoryToSend.size());
+ vInv.reserve(std::min<size_t>(1000, pto->vInventoryToSend.size()));
vInvWait.reserve(pto->vInventoryToSend.size());
BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
{
- if (pto->setInventoryKnown.count(inv))
+ if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash))
continue;
// trickle out tx inv to protect privacy
@@ -5556,24 +5556,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
}
- // returns true if wasn't already contained in the set
- if (pto->setInventoryKnown.insert(inv).second)
+ pto->filterInventoryKnown.insert(inv.hash);
+
+ vInv.push_back(inv);
+ if (vInv.size() >= 1000)
{
- vInv.push_back(inv);
- if (vInv.size() >= 1000)
- {
- pto->PushMessage("inv", vInv);
- vInv.clear();
- }
+ pto->PushMessage(NetMsgType::INV, vInv);
+ vInv.clear();
}
}
pto->vInventoryToSend = vInvWait;
}
if (!vInv.empty())
- pto->PushMessage("inv", vInv);
+ pto->PushMessage(NetMsgType::INV, vInv);
// Detect whether we're stalling
- int64_t nNow = GetTimeMicros();
+ nNow = GetTimeMicros();
if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) {
// Stalling only triggers when the block download window cannot move. During normal steady state,
// the download window should be much larger than the to-be-downloaded set of blocks, so disconnection
@@ -5639,7 +5637,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
vGetData.push_back(inv);
if (vGetData.size() >= 1000)
{
- pto->PushMessage("getdata", vGetData);
+ pto->PushMessage(NetMsgType::GETDATA, vGetData);
vGetData.clear();
}
} else {
@@ -5649,7 +5647,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
- pto->PushMessage("getdata", vGetData);
+ pto->PushMessage(NetMsgType::GETDATA, vGetData);
}
return true;
diff --git a/src/main.h b/src/main.h
index d813f01ba7..7ae4893e07 100644
--- a/src/main.h
+++ b/src/main.h
@@ -87,6 +87,14 @@ static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
+/** Average delay between local address broadcasts in seconds. */
+static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60;
+/** Average delay between peer address broadcasts in seconds. */
+static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30;
+/** Average delay between trickled inventory broadcasts in seconds.
+ * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */
+static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5;
+
static const unsigned int DEFAULT_LIMITFREERELAY = 15;
static const bool DEFAULT_RELAYPRIORITY = true;
@@ -197,9 +205,8 @@ bool ProcessMessages(CNode* pfrom);
* Send queued protocol messages to be sent to a give node.
*
* @param[in] pto The node which we are sending messages to.
- * @param[in] fSendTrickle When true send the trickled data, otherwise trickle the data until true.
*/
-bool SendMessages(CNode* pto, bool fSendTrickle);
+bool SendMessages(CNode* pto);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Try to detect Partition (network isolation) attacks against us */
diff --git a/src/mruset.h b/src/mruset.h
deleted file mode 100644
index 398aa173bf..0000000000
--- a/src/mruset.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012-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_MRUSET_H
-#define BITCOIN_MRUSET_H
-
-#include <set>
-#include <vector>
-#include <utility>
-
-/** STL-like set container that only keeps the most recent N elements. */
-template <typename T>
-class mruset
-{
-public:
- typedef T key_type;
- typedef T value_type;
- typedef typename std::set<T>::iterator iterator;
- typedef typename std::set<T>::const_iterator const_iterator;
- typedef typename std::set<T>::size_type size_type;
-
-protected:
- std::set<T> set;
- std::vector<iterator> order;
- size_type first_used;
- size_type first_unused;
- const size_type nMaxSize;
-
-public:
- mruset(size_type nMaxSizeIn = 1) : nMaxSize(nMaxSizeIn) { clear(); }
- iterator begin() const { return set.begin(); }
- iterator end() const { return set.end(); }
- size_type size() const { return set.size(); }
- bool empty() const { return set.empty(); }
- iterator find(const key_type& k) const { return set.find(k); }
- size_type count(const key_type& k) const { return set.count(k); }
- void clear()
- {
- set.clear();
- order.assign(nMaxSize, set.end());
- first_used = 0;
- first_unused = 0;
- }
- bool inline friend operator==(const mruset<T>& a, const mruset<T>& b) { return a.set == b.set; }
- bool inline friend operator==(const mruset<T>& a, const std::set<T>& b) { return a.set == b; }
- bool inline friend operator<(const mruset<T>& a, const mruset<T>& b) { return a.set < b.set; }
- std::pair<iterator, bool> insert(const key_type& x)
- {
- std::pair<iterator, bool> ret = set.insert(x);
- if (ret.second) {
- if (set.size() == nMaxSize + 1) {
- set.erase(order[first_used]);
- order[first_used] = set.end();
- if (++first_used == nMaxSize) first_used = 0;
- }
- order[first_unused] = ret.first;
- if (++first_unused == nMaxSize) first_unused = 0;
- }
- return ret;
- }
- size_type max_size() const { return nMaxSize; }
-};
-
-#endif // BITCOIN_MRUSET_H
diff --git a/src/net.cpp b/src/net.cpp
index e5659efc01..e0d96a2dc8 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -36,6 +36,8 @@
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
+#include <math.h>
+
// Dump addresses to peers.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
@@ -67,6 +69,8 @@ namespace {
};
}
+const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
+
//
// Global state variables
//
@@ -459,7 +463,7 @@ void CNode::PushVersion()
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, 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);
- PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
+ PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, strSubVersion, nBestHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY));
}
@@ -627,7 +631,9 @@ void CNode::copyStats(CNodeStats &stats)
X(fInbound);
X(nStartingHeight);
X(nSendBytes);
+ X(mapSendBytesPerMsgCmd);
X(nRecvBytes);
+ X(mapRecvBytesPerMsgCmd);
X(fWhitelisted);
// It is common for nodes with good ping times to suddenly become lagged,
@@ -682,6 +688,15 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
nBytes -= handled;
if (msg.complete()) {
+
+ //store received bytes per message command
+ //to prevent a memory DOS, only allow valid commands
+ mapMsgCmdSize::iterator i = mapRecvBytesPerMsgCmd.find(msg.hdr.pchCommand);
+ if (i == mapRecvBytesPerMsgCmd.end())
+ i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER);
+ assert(i != mapRecvBytesPerMsgCmd.end());
+ i->second += msg.hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
+
msg.nTime = GetTimeMicros();
messageHandlerCondition.notify_one();
}
@@ -1720,11 +1735,6 @@ void ThreadMessageHandler()
}
}
- // Poll the connected nodes for messages
- CNode* pnodeTrickle = NULL;
- if (!vNodesCopy.empty())
- pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
-
bool fSleep = true;
BOOST_FOREACH(CNode* pnode, vNodesCopy)
@@ -1755,7 +1765,7 @@ void ThreadMessageHandler()
{
TRY_LOCK(pnode->cs_vSend, lockSend);
if (lockSend)
- g_signals.SendMessages(pnode, pnode == pnodeTrickle || pnode->fWhitelisted);
+ g_signals.SendMessages(pnode);
}
boost::this_thread::interruption_point();
}
@@ -2342,7 +2352,7 @@ unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", DEFAULT_MAX
CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addrKnown(5000, 0.001),
- setInventoryKnown(SendBufferSize() / 1000)
+ filterInventoryKnown(50000, 0.000001)
{
nServices = 0;
hSocket = hSocketIn;
@@ -2369,7 +2379,11 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nSendOffset = 0;
hashContinue = uint256();
nStartingHeight = -1;
+ filterInventoryKnown.reset();
fGetAddr = false;
+ nNextLocalAddrSend = 0;
+ nNextAddrSend = 0;
+ nNextInvSend = 0;
fRelayTxes = false;
pfilter = new CBloomFilter();
nPingNonceSent = 0;
@@ -2377,6 +2391,9 @@ CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNa
nPingUsecTime = 0;
fPingQueued = false;
nMinPingUsecTime = std::numeric_limits<int64_t>::max();
+ BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
+ mapRecvBytesPerMsgCmd[msg] = 0;
+ mapRecvBytesPerMsgCmd[NET_MESSAGE_COMMAND_OTHER] = 0;
{
LOCK(cs_nLastNodeId);
@@ -2456,7 +2473,7 @@ void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
LogPrint("net", "(aborted)\n");
}
-void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
+void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend)
{
// The -*messagestest options are intentionally not documented in the help message,
// since they are only used during development to debug the networking code and are
@@ -2479,6 +2496,9 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
+ //log total amount of bytes per command
+ mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE;
+
// Set the checksum
uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
unsigned int nChecksum = 0;
@@ -2614,3 +2634,7 @@ void DumpBanlist()
LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
banmap.size(), GetTimeMillis() - nStart);
}
+
+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);
+}
diff --git a/src/net.h b/src/net.h
index a5a5c770d6..bc64571aeb 100644
--- a/src/net.h
+++ b/src/net.h
@@ -9,7 +9,6 @@
#include "bloom.h"
#include "compat.h"
#include "limitedmap.h"
-#include "mruset.h"
#include "netbase.h"
#include "protocol.h"
#include "random.h"
@@ -114,7 +113,7 @@ struct CNodeSignals
{
boost::signals2::signal<int ()> GetHeight;
boost::signals2::signal<bool (CNode*), CombinerAll> ProcessMessages;
- boost::signals2::signal<bool (CNode*, bool), CombinerAll> SendMessages;
+ boost::signals2::signal<bool (CNode*), CombinerAll> SendMessages;
boost::signals2::signal<void (NodeId, const CNode*)> InitializeNode;
boost::signals2::signal<void (NodeId)> FinalizeNode;
};
@@ -183,6 +182,7 @@ struct LocalServiceInfo {
extern CCriticalSection cs_mapLocalHost;
extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost;
+typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
class CNodeStats
{
@@ -200,7 +200,9 @@ public:
bool fInbound;
int nStartingHeight;
uint64_t nSendBytes;
+ mapMsgCmdSize mapSendBytesPerMsgCmd;
uint64_t nRecvBytes;
+ mapMsgCmdSize mapRecvBytesPerMsgCmd;
bool fWhitelisted;
double dPingTime;
double dPingWait;
@@ -374,6 +376,9 @@ protected:
static std::vector<CSubNet> vWhitelistedRange;
static CCriticalSection cs_vWhitelistedRange;
+ mapMsgCmdSize mapSendBytesPerMsgCmd;
+ mapMsgCmdSize mapRecvBytesPerMsgCmd;
+
// Basic fuzz-testing
void Fuzz(int nChance); // modifies ssSend
@@ -386,13 +391,16 @@ public:
CRollingBloomFilter addrKnown;
bool fGetAddr;
std::set<uint256> setKnown;
+ int64_t nNextAddrSend;
+ int64_t nNextLocalAddrSend;
// inventory based relay
- mruset<CInv> setInventoryKnown;
+ CRollingBloomFilter filterInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
std::set<uint256> setAskFor;
std::multimap<int64_t, CInv> mapAskFor;
+ int64_t nNextInvSend;
// Used for headers announcements - unfiltered blocks to relay
// Also protected by cs_inventory
std::vector<uint256> vBlockHashesToAnnounce;
@@ -497,7 +505,7 @@ public:
{
{
LOCK(cs_inventory);
- setInventoryKnown.insert(inv);
+ filterInventoryKnown.insert(inv.hash);
}
}
@@ -505,8 +513,9 @@ public:
{
{
LOCK(cs_inventory);
- if (!setInventoryKnown.count(inv))
- vInventoryToSend.push_back(inv);
+ if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash))
+ return;
+ vInventoryToSend.push_back(inv);
}
}
@@ -525,7 +534,7 @@ public:
void AbortMessage() UNLOCK_FUNCTION(cs_vSend);
// TODO: Document the precondition of this function. Is cs_vSend locked?
- void EndMessage() UNLOCK_FUNCTION(cs_vSend);
+ void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend);
void PushVersion();
@@ -535,7 +544,7 @@ public:
try
{
BeginMessage(pszCommand);
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -551,7 +560,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -567,7 +576,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -583,7 +592,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -599,7 +608,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -615,7 +624,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -631,7 +640,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -647,7 +656,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -663,7 +672,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -679,7 +688,7 @@ public:
{
BeginMessage(pszCommand);
ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9;
- EndMessage();
+ EndMessage(pszCommand);
}
catch (...)
{
@@ -785,4 +794,7 @@ public:
void DumpBanlist();
+/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
+int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds);
+
#endif // BITCOIN_NET_H
diff --git a/src/protocol.cpp b/src/protocol.cpp
index dd855aa33a..5d3ae87de8 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -12,13 +12,67 @@
# include <arpa/inet.h>
#endif
+namespace NetMsgType {
+const char *VERSION="version";
+const char *VERACK="verack";
+const char *ADDR="addr";
+const char *INV="inv";
+const char *GETDATA="getdata";
+const char *MERKLEBLOCK="merkleblock";
+const char *GETBLOCKS="getblocks";
+const char *GETHEADERS="getheaders";
+const char *TX="tx";
+const char *HEADERS="headers";
+const char *BLOCK="block";
+const char *GETADDR="getaddr";
+const char *MEMPOOL="mempool";
+const char *PING="ping";
+const char *PONG="pong";
+const char *ALERT="alert";
+const char *NOTFOUND="notfound";
+const char *FILTERLOAD="filterload";
+const char *FILTERADD="filteradd";
+const char *FILTERCLEAR="filterclear";
+const char *REJECT="reject";
+const char *SENDHEADERS="sendheaders";
+};
+
static const char* ppszTypeName[] =
{
- "ERROR",
- "tx",
- "block",
- "filtered block"
+ "ERROR", // Should never occur
+ NetMsgType::TX,
+ NetMsgType::BLOCK,
+ "filtered block" // Should never occur
+};
+
+/** All known message types. Keep this in the same order as the list of
+ * messages above and in protocol.h.
+ */
+const static std::string allNetMessageTypes[] = {
+ NetMsgType::VERSION,
+ NetMsgType::VERACK,
+ NetMsgType::ADDR,
+ NetMsgType::INV,
+ NetMsgType::GETDATA,
+ NetMsgType::MERKLEBLOCK,
+ NetMsgType::GETBLOCKS,
+ NetMsgType::GETHEADERS,
+ NetMsgType::TX,
+ NetMsgType::HEADERS,
+ NetMsgType::BLOCK,
+ NetMsgType::GETADDR,
+ NetMsgType::MEMPOOL,
+ NetMsgType::PING,
+ NetMsgType::PONG,
+ NetMsgType::ALERT,
+ NetMsgType::NOTFOUND,
+ NetMsgType::FILTERLOAD,
+ NetMsgType::FILTERADD,
+ NetMsgType::FILTERCLEAR,
+ NetMsgType::REJECT,
+ NetMsgType::SENDHEADERS
};
+const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
CMessageHeader::CMessageHeader(const MessageStartChars& pchMessageStartIn)
{
@@ -140,3 +194,8 @@ std::string CInv::ToString() const
{
return strprintf("%s %s", GetCommand(), hash.ToString());
}
+
+const std::vector<std::string> &getAllNetMessageTypes()
+{
+ return allNetMessageTypesVec;
+}
diff --git a/src/protocol.h b/src/protocol.h
index 50aeaf44ba..b84c78baca 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -65,6 +65,165 @@ public:
unsigned int nChecksum;
};
+/**
+ * Bitcoin protocol message types. When adding new message types, don't forget
+ * to update allNetMessageTypes in protocol.cpp.
+ */
+namespace NetMsgType {
+
+/**
+ * The version message provides information about the transmitting node to the
+ * receiving node at the beginning of a connection.
+ * @see https://bitcoin.org/en/developer-reference#version
+ */
+extern const char *VERSION;
+/**
+ * The verack message acknowledges a previously-received version message,
+ * informing the connecting node that it can begin to send other messages.
+ * @see https://bitcoin.org/en/developer-reference#verack
+ */
+extern const char *VERACK;
+/**
+ * The addr (IP address) message relays connection information for peers on the
+ * network.
+ * @see https://bitcoin.org/en/developer-reference#addr
+ */
+extern const char *ADDR;
+/**
+ * The inv message (inventory message) transmits one or more inventories of
+ * objects known to the transmitting peer.
+ * @see https://bitcoin.org/en/developer-reference#inv
+ */
+extern const char *INV;
+/**
+ * The getdata message requests one or more data objects from another node.
+ * @see https://bitcoin.org/en/developer-reference#getdata
+ */
+extern const char *GETDATA;
+/**
+ * The merkleblock message is a reply to a getdata message which requested a
+ * block using the inventory type MSG_MERKLEBLOCK.
+ * @since protocol version 70001 as described by BIP37.
+ * @see https://bitcoin.org/en/developer-reference#merkleblock
+ */
+extern const char *MERKLEBLOCK;
+/**
+ * The getblocks message requests an inv message that provides block header
+ * hashes starting from a particular point in the block chain.
+ * @see https://bitcoin.org/en/developer-reference#getblocks
+ */
+extern const char *GETBLOCKS;
+/**
+ * The getheaders message requests a headers message that provides block
+ * headers starting from a particular point in the block chain.
+ * @since protocol version 31800.
+ * @see https://bitcoin.org/en/developer-reference#getheaders
+ */
+extern const char *GETHEADERS;
+/**
+ * The tx message transmits a single transaction.
+ * @see https://bitcoin.org/en/developer-reference#tx
+ */
+extern const char *TX;
+/**
+ * The headers message sends one or more block headers to a node which
+ * previously requested certain headers with a getheaders message.
+ * @since protocol version 31800.
+ * @see https://bitcoin.org/en/developer-reference#headers
+ */
+extern const char *HEADERS;
+/**
+ * The block message transmits a single serialized block.
+ * @see https://bitcoin.org/en/developer-reference#block
+ */
+extern const char *BLOCK;
+/**
+ * The getaddr message requests an addr message from the receiving node,
+ * preferably one with lots of IP addresses of other receiving nodes.
+ * @see https://bitcoin.org/en/developer-reference#getaddr
+ */
+extern const char *GETADDR;
+/**
+ * The mempool message requests the TXIDs of transactions that the receiving
+ * node has verified as valid but which have not yet appeared in a block.
+ * @since protocol version 60002.
+ * @see https://bitcoin.org/en/developer-reference#mempool
+ */
+extern const char *MEMPOOL;
+/**
+ * The ping message is sent periodically to help confirm that the receiving
+ * peer is still connected.
+ * @see https://bitcoin.org/en/developer-reference#ping
+ */
+extern const char *PING;
+/**
+ * The pong message replies to a ping message, proving to the pinging node that
+ * the ponging node is still alive.
+ * @since protocol version 60001 as described by BIP31.
+ * @see https://bitcoin.org/en/developer-reference#pong
+ */
+extern const char *PONG;
+/**
+ * The alert message warns nodes of problems that may affect them or the rest
+ * of the network.
+ * @since protocol version 311.
+ * @see https://bitcoin.org/en/developer-reference#alert
+ */
+extern const char *ALERT;
+/**
+ * The notfound message is a reply to a getdata message which requested an
+ * object the receiving node does not have available for relay.
+ * @ince protocol version 70001.
+ * @see https://bitcoin.org/en/developer-reference#notfound
+ */
+extern const char *NOTFOUND;
+/**
+ * The filterload message tells the receiving peer to filter all relayed
+ * transactions and requested merkle blocks through the provided filter.
+ * @since protocol version 70001 as described by BIP37.
+ * Only available with service bit NODE_BLOOM since protocol version
+ * 70011 as described by BIP111.
+ * @see https://bitcoin.org/en/developer-reference#filterload
+ */
+extern const char *FILTERLOAD;
+/**
+ * The filteradd message tells the receiving peer to add a single element to a
+ * previously-set bloom filter, such as a new public key.
+ * @since protocol version 70001 as described by BIP37.
+ * Only available with service bit NODE_BLOOM since protocol version
+ * 70011 as described by BIP111.
+ * @see https://bitcoin.org/en/developer-reference#filteradd
+ */
+extern const char *FILTERADD;
+/**
+ * The filterclear message tells the receiving peer to remove a previously-set
+ * bloom filter.
+ * @since protocol version 70001 as described by BIP37.
+ * Only available with service bit NODE_BLOOM since protocol version
+ * 70011 as described by BIP111.
+ * @see https://bitcoin.org/en/developer-reference#filterclear
+ */
+extern const char *FILTERCLEAR;
+/**
+ * The reject message informs the receiving node that one of its previous
+ * messages has been rejected.
+ * @since protocol version 70002 as described by BIP61.
+ * @see https://bitcoin.org/en/developer-reference#reject
+ */
+extern const char *REJECT;
+/**
+ * Indicates that a node prefers to receive new block announcements via a
+ * "headers" message rather than an "inv".
+ * @since protocol version 70012 as described by BIP130.
+ * @see https://bitcoin.org/en/developer-reference#sendheaders
+ */
+extern const char *SENDHEADERS;
+
+};
+
+/* Get a vector of all valid message types (see above) */
+const std::vector<std::string> &getAllNetMessageTypes();
+
/** nServices flags */
enum {
// NODE_NETWORK means that the node is capable of serving the block chain. It is currently
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 6dce9370d7..43cfba63d6 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -898,6 +898,9 @@ QString formatServicesStr(quint64 mask)
case NODE_GETUTXO:
strList.append("GETUTXO");
break;
+ case NODE_BLOOM:
+ strList.append("BLOOM");
+ break;
default:
strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check));
}
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 0c5529955f..e709f8515b 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -1121,6 +1121,41 @@
<source>command-line options</source>
<translation type="unfinished">command-line options</translation>
</message>
+ <message>
+ <location line="+9"/>
+ <source>UI Options:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Choose data directory on startup (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Set language, for example &quot;de_DE&quot; (default: system locale)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Start minimized</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Set SSL root certificates for payment request (default: -system-)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Show splash screen on startup (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Reset all settings changes made over the GUI</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>Intro</name>
@@ -2888,7 +2923,7 @@
<context>
<name>ShutdownWindow</name>
<message>
- <location filename="../utilitydialog.cpp" line="+96"/>
+ <location filename="../utilitydialog.cpp" line="+78"/>
<source>Bitcoin Core is shutting down...</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 801c6c62d2..920ff06351 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -35,9 +35,11 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < 0)
- return tr("conflicted");
+ return tr("conflicted with a transaction with %1 confirmations").arg(-nDepth);
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return tr("%1/offline").arg(nDepth);
+ else if (nDepth == 0)
+ return tr("0/unconfirmed, %1").arg((wtx.InMempool() ? tr("in memory pool") : tr("not in memory pool")));
else if (nDepth < 6)
return tr("%1/unconfirmed").arg(nDepth);
else
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index f609289749..81b597e2eb 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -75,16 +75,16 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
std::string strUsage = HelpMessage(HMM_BITCOIN_QT);
const bool showDebug = GetBoolArg("-help-debug", false);
- strUsage += HelpMessageGroup(_("UI Options:"));
+ strUsage += HelpMessageGroup(tr("UI Options:").toStdString());
if (showDebug) {
strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", strprintf("Allow self signed root certificates (default: %u)", DEFAULT_SELFSIGNED_ROOTCERTS));
}
- strUsage += HelpMessageOpt("-choosedatadir", strprintf(_("Choose data directory on startup (default: %u)"), DEFAULT_CHOOSE_DATADIR));
- strUsage += HelpMessageOpt("-lang=<lang>", _("Set language, for example \"de_DE\" (default: system locale)"));
- strUsage += HelpMessageOpt("-min", _("Start minimized"));
- strUsage += HelpMessageOpt("-rootcertificates=<file>", _("Set SSL root certificates for payment request (default: -system-)"));
- strUsage += HelpMessageOpt("-splash", strprintf(_("Show splash screen on startup (default: %u)"), DEFAULT_SPLASHSCREEN));
- strUsage += HelpMessageOpt("-resetguisettings", _("Reset all settings changes made over the GUI"));
+ strUsage += HelpMessageOpt("-choosedatadir", strprintf(tr("Choose data directory on startup (default: %u)").toStdString(), DEFAULT_CHOOSE_DATADIR));
+ strUsage += HelpMessageOpt("-lang=<lang>", tr("Set language, for example \"de_DE\" (default: system locale)").toStdString());
+ strUsage += HelpMessageOpt("-min", tr("Start minimized").toStdString());
+ strUsage += HelpMessageOpt("-rootcertificates=<file>", tr("Set SSL root certificates for payment request (default: -system-)").toStdString());
+ strUsage += HelpMessageOpt("-splash", strprintf(tr("Show splash screen on startup (default: %u)").toStdString(), DEFAULT_SPLASHSCREEN));
+ strUsage += HelpMessageOpt("-resetguisettings", tr("Reset all settings changes made over the GUI").toStdString());
if (showDebug) {
strUsage += HelpMessageOpt("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM));
}
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 2578848891..0ce108b06e 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -111,6 +111,14 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
" ]\n"
+ " \"bytessent_per_msg\": {\n"
+ " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " ...\n"
+ " }\n"
+ " \"bytesrecv_per_msg\": {\n"
+ " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " ...\n"
+ " }\n"
" }\n"
" ,...\n"
"]\n"
@@ -165,6 +173,20 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
}
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
+ UniValue sendPerMsgCmd(UniValue::VOBJ);
+ BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapSendBytesPerMsgCmd) {
+ if (i.second > 0)
+ sendPerMsgCmd.push_back(Pair(i.first, i.second));
+ }
+ obj.push_back(Pair("bytessent_per_msg", sendPerMsgCmd));
+
+ UniValue recvPerMsgCmd(UniValue::VOBJ);
+ BOOST_FOREACH(const mapMsgCmdSize::value_type &i, stats.mapRecvBytesPerMsgCmd) {
+ if (i.second > 0)
+ recvPerMsgCmd.push_back(Pair(i.first, i.second));
+ }
+ obj.push_back(Pair("bytesrecv_per_msg", recvPerMsgCmd));
+
ret.push_back(obj);
}
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 1f2d77aef0..4947ad1f70 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -353,7 +353,6 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
if (params[0].isNull() || params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index da296a0461..51d296502e 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(CNode::IsBanned(addr1));
BOOST_CHECK(!CNode::IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
@@ -57,11 +57,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
CNode dummyNode2(INVALID_SOCKET, addr2, "", true);
dummyNode2.nVersion = 1;
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, false);
+ SendMessages(&dummyNode2);
BOOST_CHECK(!CNode::IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(CNode::IsBanned(addr1)); // ... but 1 still should be
Misbehaving(dummyNode2.GetId(), 50);
- SendMessages(&dummyNode2, false);
+ SendMessages(&dummyNode2);
BOOST_CHECK(CNode::IsBanned(addr2));
}
@@ -73,13 +73,13 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
CNode dummyNode1(INVALID_SOCKET, addr1, "", true);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100);
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(!CNode::IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 10);
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(!CNode::IsBanned(addr1));
Misbehaving(dummyNode1.GetId(), 1);
- SendMessages(&dummyNode1, false);
+ SendMessages(&dummyNode1);
BOOST_CHECK(CNode::IsBanned(addr1));
mapArgs.erase("-banscore");
}
@@ -95,7 +95,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
dummyNode.nVersion = 1;
Misbehaving(dummyNode.GetId(), 100);
- SendMessages(&dummyNode, false);
+ SendMessages(&dummyNode);
BOOST_CHECK(CNode::IsBanned(addr));
SetMockTime(nStartTime+60*60);
diff --git a/src/test/mruset_tests.cpp b/src/test/mruset_tests.cpp
deleted file mode 100644
index 2b68f8899e..0000000000
--- a/src/test/mruset_tests.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2012-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.
-
-#include "mruset.h"
-
-#include "random.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
-
-#include <set>
-
-#include <boost/test/unit_test.hpp>
-
-#define NUM_TESTS 16
-#define MAX_SIZE 100
-
-using namespace std;
-
-BOOST_FIXTURE_TEST_SUITE(mruset_tests, BasicTestingSetup)
-
-BOOST_AUTO_TEST_CASE(mruset_test)
-{
- // The mruset being tested.
- mruset<int> mru(5000);
-
- // Run the test 10 times.
- for (int test = 0; test < 10; test++) {
- // Reset mru.
- mru.clear();
-
- // A deque + set to simulate the mruset.
- std::deque<int> rep;
- std::set<int> all;
-
- // Insert 10000 random integers below 15000.
- for (int j=0; j<10000; j++) {
- int add = GetRandInt(15000);
- mru.insert(add);
-
- // Add the number to rep/all as well.
- if (all.count(add) == 0) {
- all.insert(add);
- rep.push_back(add);
- if (all.size() == 5001) {
- all.erase(rep.front());
- rep.pop_front();
- }
- }
-
- // Do a full comparison between mru and the simulated mru every 1000 and every 5001 elements.
- if (j % 1000 == 0 || j % 5001 == 0) {
- mruset<int> mru2 = mru; // Also try making a copy
-
- // Check that all elements that should be in there, are in there.
- BOOST_FOREACH(int x, rep) {
- BOOST_CHECK(mru.count(x));
- BOOST_CHECK(mru2.count(x));
- }
-
- // Check that all elements that are in there, should be in there.
- BOOST_FOREACH(int x, mru) {
- BOOST_CHECK(all.count(x));
- }
-
- // Check that all elements that are in there, should be in there.
- BOOST_FOREACH(int x, mru2) {
- BOOST_CHECK(all.count(x));
- }
-
- for (int t = 0; t < 10; t++) {
- int r = GetRandInt(15000);
- BOOST_CHECK(all.count(r) == mru.count(r));
- BOOST_CHECK(all.count(r) == mru2.count(r));
- }
- }
- }
- }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 8b9292bd14..5e8ccd90ab 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -328,4 +328,22 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
}
+BOOST_AUTO_TEST_CASE(pruning_in_ApproximateBestSet)
+{
+ CoinSet setCoinsRet;
+ CAmount nValueRet;
+
+ LOCK(wallet.cs_wallet);
+
+ empty_wallet();
+ for (int i = 0; i < 12; i++)
+ {
+ add_coin(10*CENT);
+ }
+ add_coin(100*CENT);
+ add_coin(100*CENT);
+ BOOST_CHECK(wallet.SelectCoinsMinConf(221*CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 230*CENT);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d23d54e678..2cbb89e5a8 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1034,7 +1034,8 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived,
// In either case, we need to get the destination address
CTxDestination address;
- if (!ExtractDestination(txout.scriptPubKey, address))
+
+ if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
{
LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString());
@@ -1359,6 +1360,15 @@ CAmount CWalletTx::GetChange() const
return nChangeCached;
}
+bool CWalletTx::InMempool() const
+{
+ LOCK(mempool.cs);
+ if (mempool.exists(GetHash())) {
+ return true;
+ }
+ return false;
+}
+
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
@@ -1373,12 +1383,8 @@ bool CWalletTx::IsTrusted() const
return false;
// Don't trust unconfirmed transactions from us unless they are in the mempool.
- {
- LOCK(mempool.cs);
- if (!mempool.exists(GetHash())) {
- return false;
- }
- }
+ if (!InMempool())
+ return false;
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH(const CTxIn& txin, vin)
@@ -1632,6 +1638,16 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
}
}
}
+
+ //Reduces the approximate best subset by removing any inputs that are smaller than the surplus of nTotal beyond nTargetValue.
+ for (unsigned int i = 0; i < vValue.size(); i++)
+ {
+ if (vfBest[i] && (nBest - vValue[i].first) >= nTargetValue )
+ {
+ vfBest[i] = false;
+ nBest -= vValue[i].first;
+ }
+ }
}
bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins,
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 859788893c..7354ff19c7 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -384,6 +384,7 @@ public:
// True if only scriptSigs are different
bool IsEquivalentTo(const CWalletTx& tx) const;
+ bool InMempool() const;
bool IsTrusted() const;
bool WriteToDisk(CWalletDB *pwalletdb);