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.py10
-rw-r--r--qa/rpc-tests/README.md5
-rwxr-xr-xqa/rpc-tests/bip65-cltv-p2p.py4
-rwxr-xr-xqa/rpc-tests/decodescript.py4
-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/mempool_limit.py67
-rwxr-xr-xqa/rpc-tests/mempool_packages.py24
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py1
-rwxr-xr-xqa/rpc-tests/p2p-fullblocktest.py157
-rwxr-xr-xqa/rpc-tests/prioritise_transaction.py91
-rwxr-xr-xqa/rpc-tests/replace-by-fee.py80
-rwxr-xr-xqa/rpc-tests/sendheaders.py3
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py41
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py25
-rw-r--r--qa/rpc-tests/test_framework/script.py8
-rwxr-xr-xqa/rpc-tests/test_framework/test_framework.py2
-rw-r--r--qa/rpc-tests/test_framework/util.py51
-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.cpp245
-rw-r--r--src/main.h13
-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/bitcoinunits.cpp7
-rw-r--r--src/qt/bitcoinunits.h1
-rw-r--r--src/qt/coincontroldialog.cpp10
-rw-r--r--src/qt/guiutil.cpp11
-rw-r--r--src/qt/locale/bitcoin_en.ts2
-rw-r--r--src/qt/receiverequestdialog.cpp2
-rw-r--r--src/qt/transactiondesc.cpp4
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/rpcblockchain.cpp4
-rw-r--r--src/rpcnet.cpp22
-rw-r--r--src/rpcrawtransaction.cpp1
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script.h4
-rw-r--r--src/test/DoS_tests.cpp14
-rw-r--r--src/test/data/script_invalid.json6
-rw-r--r--src/test/data/script_valid.json6
-rw-r--r--src/test/data/tx_invalid.json32
-rw-r--r--src/test/data/tx_valid.json20
-rw-r--r--src/test/mruset_tests.cpp81
-rw-r--r--src/test/script_tests.cpp8
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txmempool.cpp53
-rw-r--r--src/txmempool.h43
-rw-r--r--src/wallet/test/wallet_tests.cpp18
-rw-r--r--src/wallet/wallet.cpp30
-rw-r--r--src/wallet/wallet.h1
77 files changed, 1248 insertions, 863 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 80571fb05b..ee852ff138 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 8064804b90..7e40803a07 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 1475cd7eb2..c8fbe32eee 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..801b684e6b 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,20 @@ 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.
+Asm script outputs now contain OP_CHECKLOCKTIMEVERIFY in place of OP_NOP2
+-------------------------------------------------------------------------
-The following items contain assembly representations of scriptSig signatures
-and are affected by this change:
+OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP
+65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki)
-- RPC `getrawtransaction`
+The following outputs are affected by this change:
+- RPC `getrawtransaction` (in verbose mode)
- RPC `decoderawtransaction`
+- RPC `decodescript`
- 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 +50,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..44d7d71759 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:
@@ -83,6 +85,7 @@ testScripts = [
'rest.py',
'mempool_spendcoinbase.py',
'mempool_reorg.py',
+ 'mempool_limit.py',
'httpbasics.py',
'multi_rpc.py',
'zapwallettxes.py',
@@ -100,6 +103,8 @@ testScripts = [
'sendheaders.py',
'keypool.py',
'prioritise_transaction.py',
+ 'invalidblockrequest.py',
+ 'invalidtxrequest.py',
]
testScriptsExt = [
'bip65-cltv.py',
@@ -116,7 +121,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/bip65-cltv-p2p.py b/qa/rpc-tests/bip65-cltv-p2p.py
index 9ca5c69f16..5bb41df1ad 100755
--- a/qa/rpc-tests/bip65-cltv-p2p.py
+++ b/qa/rpc-tests/bip65-cltv-p2p.py
@@ -9,7 +9,7 @@ from test_framework.util import *
from test_framework.mininode import CTransaction, NetworkThread
from test_framework.blocktools import create_coinbase, create_block
from test_framework.comptool import TestInstance, TestManager
-from test_framework.script import CScript, OP_1NEGATE, OP_NOP2, OP_DROP
+from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP
from binascii import hexlify, unhexlify
import cStringIO
import time
@@ -19,7 +19,7 @@ def cltv_invalidate(tx):
Prepends -1 CLTV DROP in the scriptSig itself.
'''
- tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_NOP2, OP_DROP] +
+ tx.vin[0].scriptSig = CScript([OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP] +
list(CScript(tx.vin[0].scriptSig)))
'''
diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py
index 4bca623380..490808d49d 100755
--- a/qa/rpc-tests/decodescript.py
+++ b/qa/rpc-tests/decodescript.py
@@ -102,13 +102,13 @@ class DecodeScriptTest(BitcoinTestFramework):
# OP_IF
# <receiver-pubkey> OP_CHECKSIGVERIFY
# OP_ELSE
- # <lock-until> OP_NOP2 OP_DROP
+ # <lock-until> OP_CHECKLOCKTIMEVERIFY OP_DROP
# OP_ENDIF
# <sender-pubkey> OP_CHECKSIG
#
# lock until block 500,000
rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac')
- assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
+ assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
def decoderawtransaction_asm_sighashtype(self):
"""Tests decoding scripts via RPC command "decoderawtransaction".
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/mempool_limit.py b/qa/rpc-tests/mempool_limit.py
new file mode 100755
index 0000000000..48a2ea294a
--- /dev/null
+++ b/qa/rpc-tests/mempool_limit.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python2
+# Copyright (c) 2014-2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+# Test mempool limiting together/eviction with the wallet
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+class MempoolLimitTest(BitcoinTestFramework):
+
+ def __init__(self):
+ # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create
+ # So we have big transactions (and therefore can't fit very many into each block)
+ # create one script_pubkey
+ script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes
+ for i in xrange (512):
+ script_pubkey = script_pubkey + "01"
+ # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change
+ self.txouts = "81"
+ for k in xrange(128):
+ # add txout value
+ self.txouts = self.txouts + "0000000000000000"
+ # add length of script_pubkey
+ self.txouts = self.txouts + "fd0402"
+ # add script_pubkey
+ self.txouts = self.txouts + script_pubkey
+
+ def setup_network(self):
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"]))
+ self.is_network_split = False
+ self.sync_all()
+ self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
+
+ def setup_chain(self):
+ print("Initializing test directory "+self.options.tmpdir)
+ initialize_chain_clean(self.options.tmpdir, 2)
+
+ def run_test(self):
+ txids = []
+ utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90)
+
+ #create a mempool tx that will be evicted
+ us0 = utxos.pop()
+ inputs = [{ "txid" : us0["txid"], "vout" : us0["vout"]}]
+ outputs = {self.nodes[0].getnewaddress() : 0.0001}
+ tx = self.nodes[0].createrawtransaction(inputs, outputs)
+ txF = self.nodes[0].fundrawtransaction(tx)
+ txFS = self.nodes[0].signrawtransaction(txF['hex'])
+ txid = self.nodes[0].sendrawtransaction(txFS['hex'])
+ self.nodes[0].lockunspent(True, [us0])
+
+ relayfee = self.nodes[0].getnetworkinfo()['relayfee']
+ base_fee = relayfee*100
+ for i in xrange (4):
+ txids.append([])
+ txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee)
+
+ # by now, the tx should be evicted, check confirmation state
+ assert(txid not in self.nodes[0].getrawmempool())
+ txdata = self.nodes[0].gettransaction(txid);
+ assert(txdata['confirmations'] == 0) #confirmation should still be 0
+
+if __name__ == '__main__':
+ MempoolLimitTest().main()
diff --git a/qa/rpc-tests/mempool_packages.py b/qa/rpc-tests/mempool_packages.py
index 34b316a6a3..063308d394 100755
--- a/qa/rpc-tests/mempool_packages.py
+++ b/qa/rpc-tests/mempool_packages.py
@@ -64,17 +64,41 @@ class MempoolPackagesTest(BitcoinTestFramework):
for x in reversed(chain):
assert_equal(mempool[x]['descendantcount'], descendant_count)
descendant_fees += mempool[x]['fee']
+ assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee'])
assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees)
descendant_size += mempool[x]['size']
assert_equal(mempool[x]['descendantsize'], descendant_size)
descendant_count += 1
+ # Check that descendant modified fees includes fee deltas from
+ # prioritisetransaction
+ self.nodes[0].prioritisetransaction(chain[-1], 0, 1000)
+ mempool = self.nodes[0].getrawmempool(True)
+
+ descendant_fees = 0
+ for x in reversed(chain):
+ descendant_fees += mempool[x]['fee']
+ assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees+1000)
+
# Adding one more transaction on to the chain should fail.
try:
self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1)
except JSONRPCException as e:
print "too-long-ancestor-chain successfully rejected"
+ # Check that prioritising a tx before it's added to the mempool works
+ self.nodes[0].generate(1)
+ self.nodes[0].prioritisetransaction(chain[-1], 0, 2000)
+ self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
+ mempool = self.nodes[0].getrawmempool(True)
+
+ descendant_fees = 0
+ for x in reversed(chain):
+ descendant_fees += mempool[x]['fee']
+ if (x == chain[-1]):
+ assert_equal(mempool[x]['modifiedfee'], mempool[x]['fee']+satoshi_round(0.00002))
+ assert_equal(mempool[x]['descendantfees'], SATOSHIS*descendant_fees+2000)
+
# TODO: check that node1's mempool is as expected
# TODO: test ancestor size limits
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/p2p-fullblocktest.py b/qa/rpc-tests/p2p-fullblocktest.py
index 9555940cec..a6525e6793 100755
--- a/qa/rpc-tests/p2p-fullblocktest.py
+++ b/qa/rpc-tests/p2p-fullblocktest.py
@@ -7,7 +7,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
@@ -15,7 +15,7 @@ import copy
import time
import numbers
from test_framework.key import CECKey
-from test_framework.script import CScript, CScriptOp, SignatureHash, SIGHASH_ALL, OP_TRUE
+from test_framework.script import CScript, CScriptOp, SignatureHash, SIGHASH_ALL, OP_TRUE, OP_FALSE
class PreviousSpendableOutput(object):
def __init__(self, tx = CTransaction(), n = -1):
@@ -122,13 +122,29 @@ class FullBlockTest(ComparisonTestFramework):
return TestInstance([[self.tip, True]])
# returns a test case that asserts that the current tip was rejected
- def rejected():
- return TestInstance([[self.tip, False]])
+ def rejected(reject = None):
+ if reject is None:
+ return TestInstance([[self.tip, False]])
+ else:
+ return TestInstance([[self.tip, reject]])
# move the tip back to a previous block
def tip(number):
self.tip = self.blocks[number]
+ # add transactions to a block produced by next_block
+ def update_block(block_number, new_transactions):
+ block = self.blocks[block_number]
+ old_hash = block.sha256
+ self.add_transactions_to_block(block, new_transactions)
+ block.solve()
+ # Update the internal state just like in next_block
+ self.tip = block
+ self.block_heights[block.sha256] = self.block_heights[old_hash]
+ del self.block_heights[old_hash]
+ self.blocks[block_number] = block
+ return block
+
# creates a new block and advances the tip to that block
block = self.next_block
@@ -141,14 +157,15 @@ class FullBlockTest(ComparisonTestFramework):
# Now we need that block to mature so we can spend the coinbase.
test = TestInstance(sync_every_block=False)
- for i in range(100):
+ for i in range(99):
block(1000 + i)
test.blocks_and_transactions.append([self.tip, True])
save_spendable_output()
yield test
- # Start by bulding a couple of blocks on top (which output is spent is in parentheses):
+ # Start by building a couple of blocks on top (which output is spent is
+ # in parentheses):
# genesis -> b1 (0) -> b2 (1)
out0 = get_spendable_output()
block(1, spend=out0)
@@ -156,8 +173,7 @@ class FullBlockTest(ComparisonTestFramework):
yield accepted()
out1 = get_spendable_output()
- block(2, spend=out1)
- # Inv again, then deliver twice (shouldn't break anything).
+ b2 = block(2, spend=out1)
yield accepted()
@@ -168,8 +184,8 @@ class FullBlockTest(ComparisonTestFramework):
#
# Nothing should happen at this point. We saw b2 first so it takes priority.
tip(1)
- block(3, spend=out1)
- # Deliver twice (should still not break anything)
+ b3 = block(3, spend=out1)
+ txout_b3 = PreviousSpendableOutput(b3.vtx[1], 1)
yield rejected()
@@ -214,7 +230,7 @@ class FullBlockTest(ComparisonTestFramework):
# \-> b3 (1) -> b4 (2)
tip(6)
block(9, spend=out4, additional_coinbase_value=1)
- yield rejected()
+ yield rejected(RejectResult(16, 'bad-cb-amount'))
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
@@ -226,7 +242,7 @@ class FullBlockTest(ComparisonTestFramework):
yield rejected()
block(11, spend=out4, additional_coinbase_value=1)
- yield rejected()
+ yield rejected(RejectResult(16, 'bad-cb-amount'))
# Try again, but with a valid fork first
@@ -252,6 +268,10 @@ class FullBlockTest(ComparisonTestFramework):
yield TestInstance([[b12, True, b13.sha256]]) # New tip should be b13.
+ # Add a block with MAX_BLOCK_SIGOPS and one with one more sigop
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6)
+ # \-> b3 (1) -> b4 (2)
# Test that a block with a lot of checksigs is okay
lots_of_checksigs = CScript([OP_CHECKSIG] * (1000000 / 50 - 1))
@@ -264,8 +284,121 @@ class FullBlockTest(ComparisonTestFramework):
out6 = get_spendable_output()
too_many_checksigs = CScript([OP_CHECKSIG] * (1000000 / 50))
block(16, spend=out6, script=too_many_checksigs)
+ yield rejected(RejectResult(16, 'bad-blk-sigops'))
+
+
+ # Attempt to spend a transaction created on a different fork
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (b3.vtx[1])
+ # \-> b3 (1) -> b4 (2)
+ tip(15)
+ block(17, spend=txout_b3)
+ yield rejected(RejectResult(16, 'bad-txns-inputs-missingorspent'))
+
+ # Attempt to spend a transaction created on a different fork (on a fork this time)
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5)
+ # \-> b18 (b3.vtx[1]) -> b19 (6)
+ # \-> b3 (1) -> b4 (2)
+ tip(13)
+ block(18, spend=txout_b3)
+ yield rejected()
+
+ block(19, spend=out6)
yield rejected()
+ # Attempt to spend a coinbase at depth too low
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7)
+ # \-> b3 (1) -> b4 (2)
+ tip(15)
+ out7 = get_spendable_output()
+ block(20, spend=out7)
+ yield rejected(RejectResult(16, 'bad-txns-premature-spend-of-coinbase'))
+
+ # Attempt to spend a coinbase at depth too low (on a fork this time)
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5)
+ # \-> b21 (6) -> b22 (5)
+ # \-> b3 (1) -> b4 (2)
+ tip(13)
+ block(21, spend=out6)
+ yield rejected()
+
+ block(22, spend=out5)
+ yield rejected()
+
+ # Create a block on either side of MAX_BLOCK_SIZE and make sure its accepted/rejected
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6)
+ # \-> b24 (6) -> b25 (7)
+ # \-> b3 (1) -> b4 (2)
+ tip(15)
+ b23 = block(23, spend=out6)
+ old_hash = b23.sha256
+ tx = CTransaction()
+ script_length = MAX_BLOCK_SIZE - len(b23.serialize()) - 69
+ script_output = CScript([chr(0)*script_length])
+ tx.vout.append(CTxOut(0, script_output))
+ tx.vin.append(CTxIn(COutPoint(b23.vtx[1].sha256, 1)))
+ b23 = update_block(23, [tx])
+ # Make sure the math above worked out to produce a max-sized block
+ assert_equal(len(b23.serialize()), MAX_BLOCK_SIZE)
+ yield accepted()
+
+ # Make the next block one byte bigger and check that it fails
+ tip(15)
+ b24 = block(24, spend=out6)
+ script_length = MAX_BLOCK_SIZE - len(b24.serialize()) - 69
+ script_output = CScript([chr(0)*(script_length+1)])
+ tx.vout = [CTxOut(0, script_output)]
+ b24 = update_block(24, [tx])
+ assert_equal(len(b24.serialize()), MAX_BLOCK_SIZE+1)
+ yield rejected(RejectResult(16, 'bad-blk-length'))
+
+ b25 = block(25, spend=out7)
+ yield rejected()
+
+ # Create blocks with a coinbase input script size out of range
+ # genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
+ # \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7)
+ # \-> ... (6) -> ... (7)
+ # \-> b3 (1) -> b4 (2)
+ tip(15)
+ b26 = block(26, spend=out6)
+ b26.vtx[0].vin[0].scriptSig = chr(0)
+ b26.vtx[0].rehash()
+ # update_block causes the merkle root to get updated, even with no new
+ # transactions, and updates the required state.
+ b26 = update_block(26, [])
+ yield rejected(RejectResult(16, 'bad-cb-length'))
+
+ # Extend the b26 chain to make sure bitcoind isn't accepting b26
+ b27 = block(27, spend=out7)
+ yield rejected()
+
+ # Now try a too-large-coinbase script
+ tip(15)
+ b28 = block(28, spend=out6)
+ b28.vtx[0].vin[0].scriptSig = chr(0)*101
+ b28.vtx[0].rehash()
+ b28 = update_block(28, [])
+ yield rejected(RejectResult(16, 'bad-cb-length'))
+
+ # Extend the b28 chain to make sure bitcoind isn't accepted b28
+ b29 = block(29, spend=out7)
+ # TODO: Should get a reject message back with "bad-prevblk", except
+ # there's a bug that prevents this from being detected. Just note
+ # failure for now, and add the reject result later.
+ yield rejected()
+
+ # b30 has a max-sized coinbase scriptSig.
+ tip(23)
+ b30 = block(30)
+ b30.vtx[0].vin[0].scriptSig = chr(0)*100
+ b30.vtx[0].rehash()
+ b30 = update_block(30, [])
+ yield accepted()
if __name__ == '__main__':
diff --git a/qa/rpc-tests/prioritise_transaction.py b/qa/rpc-tests/prioritise_transaction.py
index f376ceee5e..c58ac58863 100755
--- a/qa/rpc-tests/prioritise_transaction.py
+++ b/qa/rpc-tests/prioritise_transaction.py
@@ -42,62 +42,15 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"]))
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee']
- def create_confirmed_utxos(self, count):
- self.nodes[0].generate(int(0.5*count)+101)
- utxos = self.nodes[0].listunspent()
- iterations = count - len(utxos)
- addr1 = self.nodes[0].getnewaddress()
- addr2 = self.nodes[0].getnewaddress()
- if iterations <= 0:
- return utxos
- for i in xrange(iterations):
- t = utxos.pop()
- fee = self.relayfee
- inputs = []
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
- outputs = {}
- send_value = t['amount'] - fee
- outputs[addr1] = satoshi_round(send_value/2)
- outputs[addr2] = satoshi_round(send_value/2)
- raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
- signed_tx = self.nodes[0].signrawtransaction(raw_tx)["hex"]
- txid = self.nodes[0].sendrawtransaction(signed_tx)
-
- while (self.nodes[0].getmempoolinfo()['size'] > 0):
- self.nodes[0].generate(1)
-
- utxos = self.nodes[0].listunspent()
- assert(len(utxos) >= count)
- return utxos
-
- def create_lots_of_big_transactions(self, utxos, fee):
- addr = self.nodes[0].getnewaddress()
- txids = []
- for i in xrange(len(utxos)):
- t = utxos.pop()
- inputs = []
- inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
- outputs = {}
- send_value = t['amount'] - fee
- outputs[addr] = satoshi_round(send_value)
- rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
- newtx = rawtx[0:92]
- newtx = newtx + self.txouts
- newtx = newtx + rawtx[94:]
- signresult = self.nodes[0].signrawtransaction(newtx, None, None, "NONE")
- txid = self.nodes[0].sendrawtransaction(signresult["hex"], True)
- txids.append(txid)
- return txids
-
def run_test(self):
- utxos = self.create_confirmed_utxos(90)
+ utxos = create_confirmed_utxos(self.relayfee, self.nodes[0], 90)
base_fee = self.relayfee*100 # our transactions are smaller than 100kb
txids = []
# Create 3 batches of transactions at 3 different fee rate levels
for i in xrange(3):
txids.append([])
- txids[i] = self.create_lots_of_big_transactions(utxos[30*i:30*i+30], (i+1)*base_fee)
+ txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[30*i:30*i+30], (i+1)*base_fee)
# add a fee delta to something in the cheapest bucket and make sure it gets mined
# also check that a different entry in the cheapest bucket is NOT mined (lower
@@ -143,5 +96,45 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
if (x != high_fee_tx):
assert(x not in mempool)
+ # Create a free, low priority transaction. Should be rejected.
+ utxo_list = self.nodes[0].listunspent()
+ assert(len(utxo_list) > 0)
+ utxo = utxo_list[0]
+
+ inputs = []
+ outputs = {}
+ inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]})
+ outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
+ raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
+ tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
+ txid = self.nodes[0].sendrawtransaction(tx_hex)
+
+ # A tx that spends an in-mempool tx has 0 priority, so we can use it to
+ # test the effect of using prioritise transaction for mempool acceptance
+ inputs = []
+ inputs.append({"txid": txid, "vout": 0})
+ outputs = {}
+ outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
+ raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs)
+ tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"]
+ tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"]
+
+ try:
+ self.nodes[0].sendrawtransaction(tx2_hex)
+ except JSONRPCException as exp:
+ assert_equal(exp.error['code'], -26) # insufficient fee
+ assert(tx2_id not in self.nodes[0].getrawmempool())
+ else:
+ assert(False)
+
+ # This is a less than 1000-byte transaction, so just set the fee
+ # to be the minimum for a 1000 byte transaction and check that it is
+ # accepted.
+ self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN))
+
+ print "Assert that prioritised free transaction is accepted to mempool"
+ assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id)
+ assert(tx2_id in self.nodes[0].getrawmempool())
+
if __name__ == '__main__':
PrioritiseTransactionTest().main()
diff --git a/qa/rpc-tests/replace-by-fee.py b/qa/rpc-tests/replace-by-fee.py
index 6e9e0b304c..734db33b51 100755
--- a/qa/rpc-tests/replace-by-fee.py
+++ b/qa/rpc-tests/replace-by-fee.py
@@ -63,8 +63,14 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
# If requested, ensure txouts are confirmed.
if confirmed:
- while len(node.getrawmempool()):
+ mempool_size = len(node.getrawmempool())
+ while mempool_size > 0:
node.generate(1)
+ new_size = len(node.getrawmempool())
+ # Error out if we have something stuck in the mempool, as this
+ # would likely be a bug.
+ assert(new_size < mempool_size)
+ mempool_size = new_size
return COutPoint(int(txid, 16), 0)
@@ -72,7 +78,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
def setup_network(self):
self.nodes = []
- self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000",
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug",
"-relaypriority=0", "-whitelist=127.0.0.1",
"-limitancestorcount=50",
"-limitancestorsize=101",
@@ -108,6 +114,9 @@ class ReplaceByFeeTest(BitcoinTestFramework):
print "Running test opt-in..."
self.test_opt_in()
+ print "Running test prioritised transactions..."
+ self.test_prioritised_transactions()
+
print "Passed\n"
def test_simple_doublespend(self):
@@ -513,5 +522,72 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# but make sure it is accepted anyway
self.nodes[0].sendrawtransaction(tx3c_hex, True)
+ def test_prioritised_transactions(self):
+ # Ensure that fee deltas used via prioritisetransaction are
+ # correctly used by replacement logic
+
+ # 1. Check that feeperkb uses modified fees
+ tx0_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
+
+ tx1a = CTransaction()
+ tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
+ tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
+ tx1a_hex = txToHex(tx1a)
+ tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+
+ # Higher fee, but the actual fee per KB is much lower.
+ tx1b = CTransaction()
+ tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
+ tx1b.vout = [CTxOut(0.001*COIN, CScript([b'a'*740000]))]
+ tx1b_hex = txToHex(tx1b)
+
+ # Verify tx1b cannot replace tx1a.
+ try:
+ tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
+ except JSONRPCException as exp:
+ assert_equal(exp.error['code'], -26)
+ else:
+ assert(False)
+
+ # Use prioritisetransaction to set tx1a's fee to 0.
+ self.nodes[0].prioritisetransaction(tx1a_txid, 0, int(-0.1*COIN))
+
+ # Now tx1b should be able to replace tx1a
+ tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
+
+ assert(tx1b_txid in self.nodes[0].getrawmempool())
+
+ # 2. Check that absolute fee checks use modified fee.
+ tx1_outpoint = make_utxo(self.nodes[0], 1.1*COIN)
+
+ tx2a = CTransaction()
+ tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
+ tx2a.vout = [CTxOut(1*COIN, CScript([b'a']))]
+ tx2a_hex = txToHex(tx2a)
+ tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True)
+
+ # Lower fee, but we'll prioritise it
+ tx2b = CTransaction()
+ tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
+ tx2b.vout = [CTxOut(1.01*COIN, CScript([b'a']))]
+ tx2b.rehash()
+ tx2b_hex = txToHex(tx2b)
+
+ # Verify tx2b cannot replace tx2a.
+ try:
+ tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
+ except JSONRPCException as exp:
+ assert_equal(exp.error['code'], -26)
+ else:
+ assert(False)
+
+ # Now prioritise tx2b to have a higher modified fee
+ self.nodes[0].prioritisetransaction(tx2b.hash, 0, int(0.1*COIN))
+
+ # tx2b should now be accepted
+ tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
+
+ assert(tx2b_txid in self.nodes[0].getrawmempool())
+
if __name__ == '__main__':
ReplaceByFeeTest().main()
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..8e49b56565 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -36,6 +36,7 @@ MY_VERSION = 60001 # past bip-31 for ping/pong
MY_SUBVERSION = "/python-mininode-tester:0.0.1/"
MAX_INV_SZ = 50000
+MAX_BLOCK_SIZE = 1000000
# Keep our own socket map for asyncore, so that we can track disconnects
# ourselves (to workaround an issue with closing an asyncore socket when
@@ -1015,32 +1016,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/script.py b/qa/rpc-tests/test_framework/script.py
index 0a78cf6fb1..0088876028 100644
--- a/qa/rpc-tests/test_framework/script.py
+++ b/qa/rpc-tests/test_framework/script.py
@@ -226,7 +226,7 @@ OP_CHECKMULTISIGVERIFY = CScriptOp(0xaf)
# expansion
OP_NOP1 = CScriptOp(0xb0)
-OP_NOP2 = CScriptOp(0xb1)
+OP_CHECKLOCKTIMEVERIFY = CScriptOp(0xb1)
OP_NOP3 = CScriptOp(0xb2)
OP_NOP4 = CScriptOp(0xb3)
OP_NOP5 = CScriptOp(0xb4)
@@ -353,7 +353,7 @@ VALID_OPCODES = {
OP_CHECKMULTISIGVERIFY,
OP_NOP1,
- OP_NOP2,
+ OP_CHECKLOCKTIMEVERIFY,
OP_NOP3,
OP_NOP4,
OP_NOP5,
@@ -472,7 +472,7 @@ OPCODE_NAMES.update({
OP_CHECKMULTISIG : 'OP_CHECKMULTISIG',
OP_CHECKMULTISIGVERIFY : 'OP_CHECKMULTISIGVERIFY',
OP_NOP1 : 'OP_NOP1',
- OP_NOP2 : 'OP_NOP2',
+ OP_CHECKLOCKTIMEVERIFY : 'OP_CHECKLOCKTIMEVERIFY',
OP_NOP3 : 'OP_NOP3',
OP_NOP4 : 'OP_NOP4',
OP_NOP5 : 'OP_NOP5',
@@ -591,7 +591,7 @@ OPCODES_BY_NAME = {
'OP_CHECKMULTISIG' : OP_CHECKMULTISIG,
'OP_CHECKMULTISIGVERIFY' : OP_CHECKMULTISIGVERIFY,
'OP_NOP1' : OP_NOP1,
- 'OP_NOP2' : OP_NOP2,
+ 'OP_CHECKLOCKTIMEVERIFY' : OP_CHECKLOCKTIMEVERIFY,
'OP_NOP3' : OP_NOP3,
'OP_NOP4' : OP_NOP4,
'OP_NOP5' : OP_NOP5,
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..dd39406036 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")
@@ -408,3 +409,49 @@ def assert_raises(exc, fun, *args, **kwds):
def satoshi_round(amount):
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
+
+def create_confirmed_utxos(fee, node, count):
+ node.generate(int(0.5*count)+101)
+ utxos = node.listunspent()
+ iterations = count - len(utxos)
+ addr1 = node.getnewaddress()
+ addr2 = node.getnewaddress()
+ if iterations <= 0:
+ return utxos
+ for i in xrange(iterations):
+ t = utxos.pop()
+ inputs = []
+ inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
+ outputs = {}
+ send_value = t['amount'] - fee
+ outputs[addr1] = satoshi_round(send_value/2)
+ outputs[addr2] = satoshi_round(send_value/2)
+ raw_tx = node.createrawtransaction(inputs, outputs)
+ signed_tx = node.signrawtransaction(raw_tx)["hex"]
+ txid = node.sendrawtransaction(signed_tx)
+
+ while (node.getmempoolinfo()['size'] > 0):
+ node.generate(1)
+
+ utxos = node.listunspent()
+ assert(len(utxos) >= count)
+ return utxos
+
+def create_lots_of_big_transactions(node, txouts, utxos, fee):
+ addr = node.getnewaddress()
+ txids = []
+ for i in xrange(len(utxos)):
+ t = utxos.pop()
+ inputs = []
+ inputs.append({ "txid" : t["txid"], "vout" : t["vout"]})
+ outputs = {}
+ send_value = t['amount'] - fee
+ outputs[addr] = satoshi_round(send_value)
+ rawtx = node.createrawtransaction(inputs, outputs)
+ newtx = rawtx[0:92]
+ newtx = newtx + txouts
+ newtx = newtx + rawtx[94:]
+ signresult = node.signrawtransaction(newtx, None, None, "NONE")
+ txid = node.sendrawtransaction(signresult["hex"], True)
+ txids.append(txid)
+ return txids
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 cb3f8f39f8..0766b1458b 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;
@@ -800,32 +800,6 @@ void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) {
pcoinsTip->Uncache(removed);
}
-CAmount GetMinRelayFee(const CTransaction& tx, const CTxMemPool& pool, unsigned int nBytes, bool fAllowFree)
-{
- uint256 hash = tx.GetHash();
- double dPriorityDelta = 0;
- CAmount nFeeDelta = 0;
- pool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
- if (dPriorityDelta > 0 || nFeeDelta > 0)
- return 0;
-
- CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes);
-
- if (fAllowFree)
- {
- // There is a free transaction area in blocks created by most miners,
- // * If we are relaying we allow transactions up to DEFAULT_BLOCK_PRIORITY_SIZE - 1000
- // to be considered to fall into this category. We don't want to encourage sending
- // multiple transactions instead of one big transaction to avoid fees.
- if (nBytes < (DEFAULT_BLOCK_PRIORITY_SIZE - 1000))
- nMinFee = 0;
- }
-
- if (!MoneyRange(nMinFee))
- nMinFee = MAX_MONEY;
- return nMinFee;
-}
-
/** Convert CValidationState to a human-readable message for logging */
std::string FormatStateMessage(const CValidationState &state)
{
@@ -968,6 +942,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
+ // nModifiedFees includes any fee deltas from PrioritiseTransaction
+ CAmount nModifiedFees = nFees;
+ double nPriorityDummy = 0;
+ pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
+
CAmount inChainInputValue;
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
@@ -985,16 +964,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps);
unsigned int nSize = entry.GetTxSize();
- // Don't accept it if it can't get into a block
- CAmount txMinFee = GetMinRelayFee(tx, pool, nSize, true);
- if (fLimitFree && nFees < txMinFee)
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
- strprintf("%d < %d", nFees, txMinFee));
-
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
- if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
+ if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
- } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
+ } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
@@ -1002,7 +975,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// Continuously rate-limit free (really, very-low-fee) transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
+ if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
@@ -1067,7 +1040,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
LOCK(pool.cs);
if (setConflicts.size())
{
- CFeeRate newFeeRate(nFees, nSize);
+ CFeeRate newFeeRate(nModifiedFees, nSize);
set<uint256> setConflictsParents;
const int maxDescendantsToVisit = 100;
CTxMemPool::setEntries setIterConflicting;
@@ -1110,7 +1083,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// ignored when deciding whether or not to replace, we do
// require the replacement to pay more overall fees too,
// mitigating most cases.
- CFeeRate oldFeeRate(mi->GetFee(), mi->GetTxSize());
+ CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
if (newFeeRate <= oldFeeRate)
{
return state.DoS(0,
@@ -1138,7 +1111,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
pool.CalculateDescendants(it, allConflicting);
}
BOOST_FOREACH(CTxMemPool::txiter it, allConflicting) {
- nConflictingFees += it->GetFee();
+ nConflictingFees += it->GetModifiedFee();
nConflictingSize += it->GetTxSize();
}
} else {
@@ -1171,16 +1144,16 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
// The replacement must pay greater fees than the transactions it
// replaces - if we did the bandwidth used by those conflicting
// transactions would not be paid for.
- if (nFees < nConflictingFees)
+ if (nModifiedFees < nConflictingFees)
{
return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s",
- hash.ToString(), FormatMoney(nFees), FormatMoney(nConflictingFees)),
+ hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)),
REJECT_INSUFFICIENTFEE, "insufficient fee");
}
// Finally in addition to paying more fees than the conflicts the
// new transaction must pay for its own bandwidth.
- CAmount nDeltaFees = nFees - nConflictingFees;
+ CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::minRelayTxFee.GetFee(nSize))
{
return state.DoS(0,
@@ -1218,7 +1191,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
LogPrint("mempool", "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
hash.ToString(),
- FormatMoney(nFees - nConflictingFees),
+ FormatMoney(nModifiedFees - nConflictingFees),
(int)nSize - (int)nConflictingSize);
}
pool.RemoveStaged(allConflicting);
@@ -1680,9 +1653,9 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
- CScriptCheck check(*coins, tx, i,
+ CScriptCheck check2(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
- if (check())
+ if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
@@ -4171,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 -
@@ -4187,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
@@ -4202,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();
}
}
@@ -4225,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;
}
}
@@ -4252,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);
}
}
@@ -4269,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);
@@ -4283,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;
}
@@ -4302,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;
@@ -4347,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)
@@ -4370,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);
@@ -4414,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));
@@ -4429,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;
@@ -4500,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;
@@ -4548,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) {
@@ -4578,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;
@@ -4603,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;
@@ -4647,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;
@@ -4692,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
@@ -4825,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);
@@ -4834,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;
@@ -4882,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());
@@ -4927,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);
}
}
}
@@ -4935,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;
@@ -4955,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);
@@ -4971,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();
@@ -4980,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;
@@ -4989,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)
{
@@ -5022,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;
@@ -5084,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;
@@ -5115,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;
@@ -5134,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;
@@ -5154,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;
@@ -5163,7 +5142,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "reject")
+ else if (strCommand == NetMsgType::REJECT)
{
if (fDebug) {
try {
@@ -5173,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;
@@ -5281,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
@@ -5320,7 +5299,7 @@ bool ProcessMessages(CNode* pfrom)
}
-bool SendMessages(CNode* pto, bool fSendTrickle)
+bool SendMessages(CNode* pto)
{
const Consensus::Params& consensusParams = Params().GetConsensus();
{
@@ -5349,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);
}
}
@@ -5362,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)
@@ -5395,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());
@@ -5422,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
@@ -5445,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());
}
}
@@ -5545,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();
@@ -5557,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
@@ -5583,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
@@ -5666,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 {
@@ -5676,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 19623f4d96..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 */
@@ -293,8 +300,6 @@ struct CDiskTxPos : public CDiskBlockPos
};
-CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
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/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 425b45d918..9c86cb71d4 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -111,13 +111,6 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator
}
-// TODO: Review all remaining calls to BitcoinUnits::formatWithUnit to
-// TODO: determine whether the output is used in a plain text context
-// TODO: or an HTML context (and replace with
-// TODO: BtcoinUnits::formatHtmlWithUnit in the latter case). Hopefully
-// TODO: there aren't instances where the result could be used in
-// TODO: either context.
-
// NOTE: Using formatWithUnit in an HTML context risks wrapping
// quantities at the thousands separator. More subtly, it also results
// in a standard space rather than a thin space, due to a bug in Qt's
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 1871c33a78..f9f67c9f11 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -88,6 +88,7 @@ public:
static QString format(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
//! Format as string (with unit)
static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
+ //! Format as HTML string (with unit)
static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard);
//! Parse string to coin amount
static bool parse(int unit, const QString &value, CAmount *val_out);
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 0f42243047..e2e8601402 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -130,7 +130,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget
ui->treeWidget->setColumnWidth(COLUMN_DATE, 110);
ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100);
ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100);
- ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but don't show it
+ ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it
ui->treeWidget->setColumnHidden(COLUMN_PRIORITY_INT64, true); // store priority int64 in this column, but don't show it
@@ -411,7 +411,7 @@ void CoinControlDialog::viewItemChanged(QTreeWidgetItem* item, int column)
// todo: this is a temporary qt5 fix: when clicking a parent node in tree mode, the parent node
// including all children are partially selected. But the parent node should be fully selected
// as well as the children. Children should never be partially selected in the first place.
- // Please remove this ugly fix, once the bug is solved upstream.
+ // Should be fixed in Qt5.4 and above. https://bugreports.qt.io/browse/QTBUG-43473
#if QT_VERSION >= 0x050000
else if (column == COLUMN_CHECKBOX && item->childCount() > 0)
{
@@ -637,14 +637,14 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// tool tips
QString toolTip1 = tr("This label turns red if the transaction size is greater than 1000 bytes.") + "<br /><br />";
- toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
+ toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000))) + "<br /><br />";
toolTip1 += tr("Can vary +/- 1 byte per input.");
QString toolTip2 = tr("Transactions with higher priority are more likely to get included into a block.") + "<br /><br />";
toolTip2 += tr("This label turns red if the priority is smaller than \"medium\".") + "<br /><br />";
- toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
+ toolTip2 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatHtmlWithUnit(nDisplayUnit, CWallet::GetRequiredFee(1000)));
- QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than %1.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, ::minRelayTxFee.GetFee(546)));
+ QString toolTip3 = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
double dFeeVary;
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 6dce9370d7..34675b53dc 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -62,6 +62,10 @@
#include <QUrlQuery>
#endif
+#if QT_VERSION >= 0x50200
+#include <QFontDatabase>
+#endif
+
#if BOOST_FILESYSTEM_VERSION >= 3
static boost::filesystem::detail::utf8_codecvt_facet utf8;
#endif
@@ -90,6 +94,9 @@ QString dateTimeStr(qint64 nTime)
QFont fixedPitchFont()
{
+#if QT_VERSION >= 0x50200
+ return QFontDatabase::systemFont(QFontDatabase::FixedFont);
+#else
QFont font("Monospace");
#if QT_VERSION >= 0x040800
font.setStyleHint(QFont::Monospace);
@@ -97,6 +104,7 @@ QFont fixedPitchFont()
font.setStyleHint(QFont::TypeWriter);
#endif
return font;
+#endif
}
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
@@ -898,6 +906,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 e709f8515b..00411741f1 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -1153,7 +1153,7 @@
</message>
<message>
<location line="+1"/>
- <source>Reset all settings changes made over the GUI</source>
+ <source>Reset all settings changed in the GUI</source>
<translation type="unfinished"></translation>
</message>
</context>
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 0c4a20cf92..75108e0a10 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -144,7 +144,7 @@ void ReceiveRequestDialog::update()
html += "<a href=\""+uri+"\">" + GUIUtil::HtmlEscape(uri) + "</a><br>";
html += "<b>"+tr("Address")+"</b>: " + GUIUtil::HtmlEscape(info.address) + "<br>";
if(info.amount)
- html += "<b>"+tr("Amount")+"</b>: " + BitcoinUnits::formatWithUnit(model->getDisplayUnit(), info.amount) + "<br>";
+ html += "<b>"+tr("Amount")+"</b>: " + BitcoinUnits::formatHtmlWithUnit(model->getDisplayUnit(), info.amount) + "<br>";
if(!info.label.isEmpty())
html += "<b>"+tr("Label")+"</b>: " + GUIUtil::HtmlEscape(info.label) + "<br>";
if(!info.message.isEmpty())
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 81b597e2eb..088578b7a9 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -84,7 +84,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
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());
+ strUsage += HelpMessageOpt("-resetguisettings", tr("Reset all settings changed in 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/rpcblockchain.cpp b/src/rpcblockchain.cpp
index ee04636ce8..73e6f8029b 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -197,7 +197,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
info.push_back(Pair("descendantcount", e.GetCountWithDescendants()));
info.push_back(Pair("descendantsize", e.GetSizeWithDescendants()));
- info.push_back(Pair("descendantfees", e.GetFeesWithDescendants()));
+ info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants()));
const CTransaction& tx = e.GetTx();
set<string> setDepends;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
@@ -255,7 +255,7 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
" \"currentpriority\" : n, (numeric) transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
" \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
- " \"descendantfees\" : n, (numeric) fees of in-mempool descendants (including this one)\n"
+ " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n"
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/script/script.cpp b/src/script/script.cpp
index 9c77ed9fc1..a7ba57e65b 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -131,7 +131,7 @@ const char* GetOpName(opcodetype opcode)
// expanson
case OP_NOP1 : return "OP_NOP1";
- case OP_NOP2 : return "OP_NOP2";
+ case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
case OP_NOP3 : return "OP_NOP3";
case OP_NOP4 : return "OP_NOP4";
case OP_NOP5 : return "OP_NOP5";
diff --git a/src/script/script.h b/src/script/script.h
index 3650957fc9..7a37b66ccf 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -162,8 +162,8 @@ enum opcodetype
// expansion
OP_NOP1 = 0xb0,
- OP_NOP2 = 0xb1,
- OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
+ OP_CHECKLOCKTIMEVERIFY = 0xb1,
+ OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
OP_NOP3 = 0xb2,
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
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/data/script_invalid.json b/src/test/data/script_invalid.json
index 7afa2abf49..7ce7e0879c 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -160,12 +160,12 @@
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"],
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"],
-["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"],
-["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"],
+["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"],
+["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"],
["Ensure 100% coverage of discouraged NOPS"],
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
-["1", "NOP2", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
+["1", "CHECKLOCKTIMEVERIFY", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP3", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS"],
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index a4e15faeaf..e5f0d17b04 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -232,8 +232,8 @@
["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC"],
-["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"],
-["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"],
+["1","NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"],
+["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"],
["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "Discourage NOPx flag allows OP_NOP"],
@@ -442,7 +442,7 @@
["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"],
["NOP", "NOP1 1", "P2SH,STRICTENC"],
-["NOP", "NOP2 1", "P2SH,STRICTENC"],
+["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC"],
["NOP", "NOP3 1", "P2SH,STRICTENC"],
["NOP", "NOP4 1", "P2SH,STRICTENC"],
["NOP", "NOP5 1", "P2SH,STRICTENC"],
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index cc059e814f..9025841949 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -127,66 +127,66 @@
["CHECKLOCKTIMEVERIFY tests"],
["By-height locks, with argument just beyond tx nLockTime"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument missing"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blockheight nLockTime=0"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument negative with by-blocktime nLockTime=500,000,000"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Input locked"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"] ,
["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument/tx height/time mismatch, both versions"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["Argument 2^32 with nLockTime=2^32-1"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["Same, but with nLockTime=2^31-1"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 0dfef73ae5..76d29bcf26 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -190,35 +190,35 @@
["CHECKLOCKTIMEVERIFY tests"],
["By-height locks, with argument == 0 and == tx nLockTime"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["Any non-maxint nSequence is fine"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["The argument can be calculated rather than created directly by a PUSHDATA"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD CHECKLOCKTIMEVERIFY 1"]],
"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD CHECKLOCKTIMEVERIFY 1"]],
"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
["5 byte non-minimally-encoded arguments are valid"],
-[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 CHECKLOCKTIMEVERIFY 1"]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
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/test/script_tests.cpp b/src/test/script_tests.cpp
index 0059e4a998..9eff6d0c63 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -985,10 +985,10 @@ BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts)
BOOST_AUTO_TEST_CASE(script_GetScriptAsm)
{
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_NOP2, true));
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_NOP2));
- BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2, true));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2));
+ BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY));
string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090");
string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2");
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 8eccc81e30..4ebcb9b667 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -618,7 +618,7 @@ void TorController::disconnected_cb(TorControlConnection& conn)
if (!reconnect)
return;
- LogPrint("tor", "tor: Disconnected from Tor control port %s, trying to reconnect\n", target);
+ LogPrint("tor", "tor: Not connected to Tor control port %s, trying to reconnect\n", target);
// Single-shot timer for reconnect. Use exponential backoff.
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index fea5da8029..c72a1e8c19 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -33,7 +33,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
nCountWithDescendants = 1;
nSizeWithDescendants = nTxSize;
- nFeesWithDescendants = nFee;
+ nModFeesWithDescendants = nFee;
CAmount nValueIn = tx.GetValueOut()+nFee;
assert(inChainInputValue <= nValueIn);
@@ -57,6 +57,7 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{
+ nModFeesWithDescendants += newFeeDelta - feeDelta;
feeDelta = newFeeDelta;
}
@@ -114,7 +115,7 @@ bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit
BOOST_FOREACH(txiter cit, setAllDescendants) {
if (!setExclude.count(cit->GetTx().GetHash())) {
modifySize += cit->GetTxSize();
- modifyFee += cit->GetFee();
+ modifyFee += cit->GetModifiedFee();
modifyCount++;
cachedDescendants[updateIt].insert(cit);
}
@@ -244,7 +245,7 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors
}
const int64_t updateCount = (add ? 1 : -1);
const int64_t updateSize = updateCount * it->GetTxSize();
- const CAmount updateFee = updateCount * it->GetFee();
+ const CAmount updateFee = updateCount * it->GetModifiedFee();
BOOST_FOREACH(txiter ancestorIt, setAncestors) {
mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
}
@@ -304,7 +305,7 @@ void CTxMemPoolEntry::SetDirty()
{
nCountWithDescendants = 0;
nSizeWithDescendants = nTxSize;
- nFeesWithDescendants = nFee;
+ nModFeesWithDescendants = GetModifiedFee();
}
void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
@@ -312,8 +313,7 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
if (!IsDirty()) {
nSizeWithDescendants += modifySize;
assert(int64_t(nSizeWithDescendants) > 0);
- nFeesWithDescendants += modifyFee;
- assert(nFeesWithDescendants >= 0);
+ nModFeesWithDescendants += modifyFee;
nCountWithDescendants += modifyCount;
assert(int64_t(nCountWithDescendants) > 0);
}
@@ -372,6 +372,17 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
mapLinks.insert(make_pair(newit, TxLinks()));
+ // Update transaction for any feeDelta created by PrioritiseTransaction
+ // TODO: refactor so that the fee delta is calculated before inserting
+ // into mapTx.
+ std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
+ if (pos != mapDeltas.end()) {
+ const std::pair<double, CAmount> &deltas = pos->second;
+ if (deltas.second) {
+ mapTx.modify(newit, update_fee_delta(deltas.second));
+ }
+ }
+
// Update cachedInnerUsage to include contained transaction's usage.
// (When we update the entry for in-mempool parents, memory usage will be
// further updated.)
@@ -399,15 +410,6 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
}
UpdateAncestorsOf(true, newit, setAncestors);
- // Update transaction's score for any feeDelta created by PrioritiseTransaction
- std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash);
- if (pos != mapDeltas.end()) {
- const std::pair<double, CAmount> &deltas = pos->second;
- if (deltas.second) {
- mapTx.modify(newit, update_fee_delta(deltas.second));
- }
- }
-
nTransactionsUpdated++;
totalTxSize += entry.GetTxSize();
minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
@@ -644,27 +646,24 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
CTxMemPool::setEntries setChildrenCheck;
std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
int64_t childSizes = 0;
- CAmount childFees = 0;
+ CAmount childModFee = 0;
for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) {
txiter childit = mapTx.find(iter->second.ptx->GetHash());
assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
if (setChildrenCheck.insert(childit).second) {
childSizes += childit->GetTxSize();
- childFees += childit->GetFee();
+ childModFee += childit->GetModifiedFee();
}
}
assert(setChildrenCheck == GetMemPoolChildren(it));
- // Also check to make sure size/fees is greater than sum with immediate children.
+ // Also check to make sure size is greater than sum with immediate children.
// just a sanity check, not definitive that this calc is correct...
- // also check that the size is less than the size of the entire mempool.
if (!it->IsDirty()) {
assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
- assert(it->GetFeesWithDescendants() >= childFees + it->GetFee());
} else {
assert(it->GetSizeWithDescendants() == it->GetTxSize());
- assert(it->GetFeesWithDescendants() == it->GetFee());
+ assert(it->GetModFeesWithDescendants() == it->GetModifiedFee());
}
- assert(it->GetFeesWithDescendants() >= 0);
if (fDependsWait)
waitingOnDependants.push_back(&(*it));
@@ -788,6 +787,14 @@ void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash,
txiter it = mapTx.find(hash);
if (it != mapTx.end()) {
mapTx.modify(it, update_fee_delta(deltas.second));
+ // Now update all ancestors' modified fees with descendants
+ setEntries setAncestors;
+ uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+ std::string dummy;
+ CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false);
+ BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0));
+ }
}
}
LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta));
@@ -956,7 +963,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
// "minimum reasonable fee rate" (ie some value under which we consider txn
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
- CFeeRate removed(it->GetFeesWithDescendants(), it->GetSizeWithDescendants());
+ CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
removed += minReasonableRelayFee;
trackPackageRemoved(removed);
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
diff --git a/src/txmempool.h b/src/txmempool.h
index 9203171868..4b726cc902 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -44,12 +44,12 @@ class CTxMemPool;
* ("descendant" transactions).
*
* When a new entry is added to the mempool, we update the descendant state
- * (nCountWithDescendants, nSizeWithDescendants, and nFeesWithDescendants) for
+ * (nCountWithDescendants, nSizeWithDescendants, and nModFeesWithDescendants) for
* all ancestors of the newly added transaction.
*
* If updating the descendant state is skipped, we can mark the entry as
- * "dirty", and set nSizeWithDescendants/nFeesWithDescendants to equal nTxSize/
- * nTxFee. (This can potentially happen during a reorg, where we limit the
+ * "dirty", and set nSizeWithDescendants/nModFeesWithDescendants to equal nTxSize/
+ * nFee+feeDelta. (This can potentially happen during a reorg, where we limit the
* amount of work we're willing to do to avoid consuming too much CPU.)
*
*/
@@ -74,11 +74,11 @@ private:
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
// descendants as well. if nCountWithDescendants is 0, treat this entry as
- // dirty, and nSizeWithDescendants and nFeesWithDescendants will not be
+ // dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be
// correct.
uint64_t nCountWithDescendants; //! number of descendant transactions
uint64_t nSizeWithDescendants; //! ... and size
- CAmount nFeesWithDescendants; //! ... and total fees (all including us)
+ CAmount nModFeesWithDescendants; //! ... and total fees (all including us)
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
@@ -104,7 +104,8 @@ public:
// Adjusts the descendant state, if this entry is not dirty.
void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
- // Updates the fee delta used for mining priority score
+ // Updates the fee delta used for mining priority score, and the
+ // modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
/** We can set the entry to be dirty if doing the full calculation of in-
@@ -116,7 +117,7 @@ public:
uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
- CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; }
+ CAmount GetModFeesWithDescendants() const { return nModFeesWithDescendants; }
bool GetSpendsCoinbase() const { return spendsCoinbase; }
};
@@ -163,27 +164,27 @@ struct mempoolentry_txid
}
};
-/** \class CompareTxMemPoolEntryByFee
+/** \class CompareTxMemPoolEntryByDescendantScore
*
- * Sort an entry by max(feerate of entry's tx, feerate with all descendants).
+ * Sort an entry by max(score/size of entry's tx, score/size with all descendants).
*/
-class CompareTxMemPoolEntryByFee
+class CompareTxMemPoolEntryByDescendantScore
{
public:
bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
{
- bool fUseADescendants = UseDescendantFeeRate(a);
- bool fUseBDescendants = UseDescendantFeeRate(b);
+ bool fUseADescendants = UseDescendantScore(a);
+ bool fUseBDescendants = UseDescendantScore(b);
- double aFees = fUseADescendants ? a.GetFeesWithDescendants() : a.GetFee();
+ double aModFee = fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee();
double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize();
- double bFees = fUseBDescendants ? b.GetFeesWithDescendants() : b.GetFee();
+ double bModFee = fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee();
double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize();
// Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
- double f1 = aFees * bSize;
- double f2 = aSize * bFees;
+ double f1 = aModFee * bSize;
+ double f2 = aSize * bModFee;
if (f1 == f2) {
return a.GetTime() >= b.GetTime();
@@ -191,11 +192,11 @@ public:
return f1 < f2;
}
- // Calculate which feerate to use for an entry (avoiding division).
- bool UseDescendantFeeRate(const CTxMemPoolEntry &a)
+ // Calculate which score to use for an entry (avoiding division).
+ bool UseDescendantScore(const CTxMemPoolEntry &a)
{
- double f1 = (double)a.GetFee() * a.GetSizeWithDescendants();
- double f2 = (double)a.GetFeesWithDescendants() * a.GetTxSize();
+ double f1 = (double)a.GetModifiedFee() * a.GetSizeWithDescendants();
+ double f2 = (double)a.GetModFeesWithDescendants() * a.GetTxSize();
return f2 > f1;
}
};
@@ -350,7 +351,7 @@ public:
// sorted by fee rate
boost::multi_index::ordered_non_unique<
boost::multi_index::identity<CTxMemPoolEntry>,
- CompareTxMemPoolEntryByFee
+ CompareTxMemPoolEntryByDescendantScore
>,
// sorted by entry time
boost::multi_index::ordered_non_unique<
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);