diff --git a/.gitignore b/.gitignore index 502122a5c541..ced4068c9d19 100644 --- a/.gitignore +++ b/.gitignore @@ -62,7 +62,6 @@ libconftest.dylib* *.o *.o-* *.patch -.dash *.a *.pb.cc *.pb.h diff --git a/.travis.yml b/.travis.yml index 7152686c8ab3..19837a348dfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,6 +94,7 @@ script: - mkdir build && cd build - ../configure $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( cat config.log && false) - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) + - make distdir - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - if [ "$RUN_TESTS" = "true" ]; then travis_wait 30 make $MAKEJOBS check VERBOSE=1; fi - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi diff --git a/Makefile.am b/Makefile.am index 5f09428f2ba6..2761beb9f931 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,8 +43,7 @@ DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md) DIST_CONTRIB = $(top_srcdir)/contrib/dash-cli.bash-completion \ $(top_srcdir)/contrib/dash-tx.bash-completion \ $(top_srcdir)/contrib/dashd.bash-completion \ - $(top_srcdir)/contrib/init \ - $(top_srcdir)/contrib/rpm + $(top_srcdir)/contrib/init BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \ $(top_srcdir)/contrib/devtools/security-check.py @@ -112,9 +111,16 @@ osx_volname: echo $(OSX_VOLNAME) >$@ if BUILD_DARWIN -$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) +$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING) $(OSX_BACKGROUND_IMAGE) $(PYTHON) $(OSX_DEPLOY_SCRIPT) $(OSX_APP) -add-qt-tr $(OSX_QT_TRANSLATIONS) -translations-dir=$(QT_TRANSLATION_DIR) -dmg -fancy $(OSX_FANCY_PLIST) -verbose 2 -volname $(OSX_VOLNAME) +$(OSX_BACKGROUND_IMAGE).png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) + sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 36 -p 36 -o $@ +$(OSX_BACKGROUND_IMAGE)@2x.png: contrib/macdeploy/$(OSX_BACKGROUND_SVG) + sed 's/PACKAGE_NAME/$(PACKAGE_NAME)/' < "$<" | $(RSVG_CONVERT) -f png -d 72 -p 72 -o $@ +$(OSX_BACKGROUND_IMAGE): $(OSX_BACKGROUND_IMAGE).png $(OSX_BACKGROUND_IMAGE)@2x.png + tiffutil -cathidpicheck $^ -out $@ + deploydir: $(OSX_DMG) else APP_DIST_DIR=$(top_builddir)/dist diff --git a/configure.ac b/configure.ac index db01dab08dc6..40607a5535db 100644 --- a/configure.ac +++ b/configure.ac @@ -320,6 +320,7 @@ case $host in fi fi + AC_PATH_PROGS([RSVG_CONVERT], [rsvg-convert rsvg],rsvg-convert) AC_CHECK_PROG([BREW],brew, brew) if test x$BREW = xbrew; then dnl These Homebrew packages may be keg-only, meaning that they won't be found @@ -415,6 +416,8 @@ if test x$use_lcov = xyes; then AC_MSG_ERROR("lcov testing requested but genhtml not found") fi LCOV="$LCOV --gcov-tool=$GCOV" + AX_CHECK_LINK_FLAG([[--coverage]], [LDFLAGS="$LDFLAGS --coverage"], + [AC_MSG_ERROR("lcov testing requested but --coverage linker flag does not work")]) AX_CHECK_COMPILE_FLAG([--coverage],[CXXFLAGS="$CXXFLAGS --coverage"], [AC_MSG_ERROR("lcov testing requested but --coverage flag does not work")]) fi @@ -833,6 +836,13 @@ else fi fi +save_CXXFLAGS="${CXXFLAGS}" +CXXFLAGS="${CXXFLAGS} ${CRYPTO_CFLAGS} ${SSL_CFLAGS}" +AC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT +#include +]) +CXXFLAGS="${save_CXXFLAGS}" + dnl univalue check need_bundled_univalue=yes diff --git a/contrib/debian/examples/dash.conf b/contrib/debian/examples/dash.conf index 12580a2ecd05..2d4f7a66fe8e 100644 --- a/contrib/debian/examples/dash.conf +++ b/contrib/debian/examples/dash.conf @@ -67,9 +67,30 @@ # This option can be specified multiple times (default: bind to all interfaces) #rpcbind= -# You must set rpcuser and rpcpassword to secure the JSON-RPC api +# If no rpcpassword is set, rpc cookie auth is sought. The default `-rpccookiefile` name +# is .cookie and found in the `-datadir` being used for dashd. This option is typically used +# when the server and client are run as the same user. +# +# If not, you must set rpcuser and rpcpassword to secure the JSON-RPC api. The first +# method(DEPRECATED) is to set this pair for the server and client: #rpcuser=Ulysseys #rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593 +# +# The second method `rpcauth` can be added to server startup argument. It is set at intialization time +# using the output from the script in share/rpcuser/rpcuser.py after providing a username: +# +# ./share/rpcuser/rpcuser.py alice +# String to be appended to dash.conf: +# rpcauth=alice:f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae +# Your password: +# DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E= +# +# On client-side, you add the normal user/password pair to send commands: +#rpcuser=alice +#rpcpassword=DONT_USE_THIS_YOU_WILL_GET_ROBBED_8ak1gI25KFTvjovL3gAM967mies3E= +# +# You can even add multiple entries of these to the server conf file, and client can use any of them: +# rpcauth=bob:b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99 # How many seconds Dash Core will wait for a complete RPC HTTP request. # after the HTTP connection is established. diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md index 3570f65e6278..de15aa42ca3c 100644 --- a/contrib/linearize/README.md +++ b/contrib/linearize/README.md @@ -1,5 +1,6 @@ # Linearize -Construct a linear, no-fork, best version of the blockchain. +Construct a linear, no-fork, best version of the Dash blockchain. The scripts +run using Python 3 but are compatible with Python 2. ## Step 0: Install dash_hash @@ -10,27 +11,42 @@ https://github.com/dashpay/dash_hash $ ./linearize-hashes.py linearize.cfg > hashlist.txt Required configuration file settings for linearize-hashes: -* RPC: rpcuser, rpcpassword +* RPC: `rpcuser`, `rpcpassword` Optional config file setting for linearize-hashes: -* RPC: host, port -* Block chain: min_height, max_height +* RPC: `host` (Default: `127.0.0.1`) +* RPC: `port` (Default: `9998`) +* Blockchain: `min_height`, `max_height` +* `rev_hash_bytes`: If true, the written block hash list will be +byte-reversed. (In other words, the hash returned by getblockhash will have its +bytes reversed.) False by default. Intended for generation of +standalone hash lists but safe to use with linearize-data.py, which will output +the same data no matter which byte format is chosen. + +The `linearize-hashes` script requires a connection, local or remote, to a +JSON-RPC server. Running `dashd` or `dash-qt -server` will be sufficient. ## Step 2: Copy local block data $ ./linearize-data.py linearize.cfg Required configuration file settings: -* "input": bitcoind blocks/ directory containing blkNNNNN.dat -* "hashlist": text file containing list of block hashes, linearized-hashes.py -output. -* "output_file" for bootstrap.dat or "output" for output directory for linearized blocks/blkNNNNN.dat output +* `output_file`: The file that will contain the final blockchain. + or +* `output`: Output directory for linearized `blocks/blkNNNNN.dat` output. Optional config file setting for linearize-data: -* "netmagic": network magic number (default is 'cee2caff', testnet) -* "genesis": genesis block hash (default is '00000bafbc94add76cb75e2ec92894837288a481e5c005f6563d91623bf8bc2c', testnet) -* "max_out_sz": maximum output file size (default 100 \* 1000 \* 1000) -* "split_timestamp": Split files when a new month is first seen, in addition to -reaching a maximum file size. -* "file_timestamp": Set each file's last-modified time to that of the -most recent block in that file. +* `file_timestamp`: Set each file's last-modified time to that of the most +recent block in that file. +* `genesis`: The hash of the genesis block in the blockchain. (default is '00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6', mainnet) +* `input`: dashd blocks/ directory containing blkNNNNN.dat +* `hashlist`: text file containing list of block hashes created by +linearize-hashes.py. +* `max_out_sz`: Maximum size for files created by the `output_file` option. +(Default: `1000*1000*1000 bytes`) +* `netmagic`: Network magic number. (default is 'bf0c6bbd', mainnet) +* `rev_hash_bytes`: If true, the block hash list written by linearize-hashes.py +will be byte-reversed when read by linearize-data.py. See the linearize-hashes +entry for more information. +* `split_timestamp`: Split blockchain files when a new month is first seen, in +addition to reaching a maximum file size (`max_out_sz`). diff --git a/contrib/linearize/example-linearize.cfg b/contrib/linearize/example-linearize.cfg index 09a66dc74e6d..d8fe8a55f2ff 100644 --- a/contrib/linearize/example-linearize.cfg +++ b/contrib/linearize/example-linearize.cfg @@ -13,8 +13,10 @@ netmagic=bf0c6bbd input=/home/example/.dashcore/blocks output_file=/home/example/Downloads/bootstrap.dat hashlist=hashlist.txt -split_year=1 genesis=00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6 # Maxmimum size in bytes of out-of-order blocks cache in memory out_of_order_cache_sz = 10000000 + +# Do we want the reverse the hash bytes coming from getblockhash? +rev_hash_bytes = False diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py index d57c59904d7d..3b7351f67953 100755 --- a/contrib/linearize/linearize-data.py +++ b/contrib/linearize/linearize-data.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # linearize-data.py: Construct a linear, no-fork version of the chain. # @@ -8,24 +8,34 @@ # from __future__ import print_function, division +try: # Python 3 + import http.client as httplib +except ImportError: # Python 2 + import httplib import json import struct import re import os import os.path import base64 -import httplib import sys import hashlib import dash_hash import datetime import time from collections import namedtuple +from binascii import hexlify, unhexlify settings = {} +##### Switch endian-ness ##### +def hex_switchEndian(s): + """ Switches the endianness of a hex string (in pairs of hex chars) """ + pairList = [s[i:i+2].encode() for i in range(0, len(s), 2)] + return b''.join(pairList[::-1]).decode() + def uint32(x): - return x & 0xffffffffL + return x & 0xffffffff def bytereverse(x): return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) | @@ -36,14 +46,14 @@ def bufreverse(in_buf): for i in range(0, len(in_buf), 4): word = struct.unpack('@I', in_buf[i:i+4])[0] out_words.append(struct.pack('@I', bytereverse(word))) - return ''.join(out_words) + return b''.join(out_words) def wordreverse(in_buf): out_words = [] for i in range(0, len(in_buf), 4): out_words.append(in_buf[i:i+4]) out_words.reverse() - return ''.join(out_words) + return b''.join(out_words) def calc_hdr_hash(blk_hdr): #hash1 = hashlib.sha256() @@ -62,7 +72,7 @@ def calc_hash_str(blk_hdr): hash = calc_hdr_hash(blk_hdr) hash = bufreverse(hash) hash = wordreverse(hash) - hash_str = hash.encode('hex') + hash_str = hexlify(hash).decode('utf-8') return hash_str def get_blk_dt(blk_hdr): @@ -72,17 +82,21 @@ def get_blk_dt(blk_hdr): dt_ym = datetime.datetime(dt.year, dt.month, 1) return (dt_ym, nTime) +# When getting the list of block hashes, undo any byte reversals. def get_block_hashes(settings): blkindex = [] f = open(settings['hashlist'], "r") for line in f: line = line.rstrip() + if settings['rev_hash_bytes'] == 'true': + line = hex_switchEndian(line) blkindex.append(line) print("Read " + str(len(blkindex)) + " hashes") return blkindex +# The block map shouldn't give or receive byte-reversed hashes. def mkblockmap(blkindex): blkmap = {} for height,hash in enumerate(blkindex): @@ -210,7 +224,7 @@ def run(self): inMagic = inhdr[:4] if (inMagic != self.settings['netmagic']): - print("Invalid magic: " + inMagic.encode('hex')) + print("Invalid magic: " + hexlify(inMagic).decode('utf-8')) return inLenLE = inhdr[4:] su = struct.unpack(" + +This is a new minor version release, including various bugfixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at github: + + + +To receive security and update notifications, please subscribe to: + + + +Compatibility +============== + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +an OS initially released in 2001. This means that not even critical security +updates will be released anymore. Without security updates, using a bitcoin +wallet on a XP machine is irresponsible at least. + +In addition to that, with 0.12.x there have been varied reports of Bitcoin Core +randomly crashing on Windows XP. It is [not clear](https://github.com/bitcoin/bitcoin/issues/7681#issuecomment-217439891) +what the source of these crashes is, but it is likely that upstream +libraries such as Qt are no longer being tested on XP. + +We do not have time nor resources to provide support for an OS that is +end-of-life. From 0.13.0 on, Windows XP is no longer supported. Users are +suggested to upgrade to a newer version of Windows, or install an alternative OS +that is supported. + +No attempt is made to prevent installing or running the software on Windows XP, +you can still do so at your own risk, but do not expect it to work: do not +report issues about Windows XP to the issue tracker. + +From 0.13.1 onwards OS X 10.7 is no longer supported. 0.13.0 was intended to work on 10.7+, +but severe issues with the libc++ version on 10.7.x keep it from running reliably. +0.13.1 now requires 10.8+, and will communicate that to 10.7 users, rather than crashing unexpectedly. + +Notable changes +=============== + +Change to wallet handling of mempool rejection +----------------------------------------------- + +When a newly created transaction failed to enter the mempool due to +the limits on chains of unconfirmed transactions the sending RPC +calls would return an error. The transaction would still be queued +in the wallet and, once some of the parent transactions were +confirmed, broadcast after the software was restarted. + +This behavior has been changed to return success and to reattempt +mempool insertion at the same time transaction rebroadcast is +attempted, avoiding a need for a restart. + +Transactions in the wallet which cannot be accepted into the mempool +can be abandoned with the previously existing abandontransaction RPC +(or in the GUI via a context menu on the transaction). + + +0.13.2 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### Consensus +- #9293 `e591c10` [0.13 Backport #9053] IBD using chainwork instead of height and not using header timestamp (gmaxwell) +- #9053 `5b93eee` IBD using chainwork instead of height and not using header timestamps (gmaxwell) + +### RPC and other APIs +- #8845 `1d048b9` Don't return the address of a P2SH of a P2SH (jnewbery) +- #9041 `87fbced` keypoololdest denote Unix epoch, not GMT (s-matthew-english) +- #9122 `f82c81b` fix getnettotals RPC description about timemillis (visvirial) +- #9042 `5bcb05d` [rpc] ParseHash: Fail when length is not 64 (MarcoFalke) +- #9194 `f26dab7` Add option to return non-segwit serialization via rpc (instagibbs) +- #9347 `b711390` [0.13.2] wallet/rpc backports (MarcoFalke) +- #9292 `c365556` Complain when unknown rpcserialversion is specified (sipa) +- #9322 `49a612f` [qa] Don't set unknown rpcserialversion (MarcoFalke) + +### Block and transaction handling +- #8357 `ce0d817` [mempool] Fix relaypriority calculation error (maiiz) +- #9267 `0a4aa87` [0.13 backport #9239] Disable fee estimates for a confirm target of 1 block (morcos) +- #9196 `0c09d9f` Send tip change notification from invalidateblock (ryanofsky) + +### P2P protocol and network code +- #8995 `9ef3875` Add missing cs_main lock to ::GETBLOCKTXN processing (TheBlueMatt) +- #9234 `94531b5` torcontrol: Explicitly request RSA1024 private key (laanwj) +- #8637 `2cad5db` Compact Block Tweaks (rebase of #8235) (sipa) +- #9058 `286e548` Fixes for p2p-compactblocks.py test timeouts on travis (#8842) (ryanofsky) +- #8865 `4c71fc4` Decouple peer-processing-logic from block-connection-logic (TheBlueMatt) +- #9117 `6fe3981` net: don't send feefilter messages before the version handshake is complete (theuni) +- #9188 `ca1fd75` Make orphan parent fetching ask for witnesses (gmaxwell) +- #9052 `3a3bcbf` Use RelevantServices instead of node_network in AttemptToEvict (gmaxwell) +- #9048 `9460771` [0.13 backport #9026] Fix handling of invalid compact blocks (sdaftuar) +- #9357 `03b6f62` [0.13 backport #9352] Attempt reconstruction from all compact block announcements (sdaftuar) +- #9189 `b96a8f7` Always add default_witness_commitment with GBT client support (sipa) +- #9253 `28d0f22` Fix calculation of number of bound sockets to use (TheBlueMatt) +- #9199 `da5a16b` Always drop the least preferred HB peer when adding a new one (gmaxwell) + +### Build system +- #9169 `d1b4da9` build: fix qt5.7 build under macOS (theuni) +- #9326 `a0f7ece` Update for OpenSSL 1.1 API (gmaxwell) +- #9224 `396c405` Prevent FD_SETSIZE error building on OpenBSD (ivdsangen) + +### GUI +- #8972 `6f86b53` Make warnings label selectable (jonasschnelli) (MarcoFalke) +- #9185 `6d70a73` Fix coincontrol sort issue (jonasschnelli) +- #9094 `5f3a12c` Use correct conversion function for boost::path datadir (laanwj) +- #8908 `4a974b2` Update bitcoin-qt.desktop (s-matthew-english) +- #9190 `dc46b10` Plug many memory leaks (laanwj) + +### Wallet +- #9290 `35174a0` Make RelayWalletTransaction attempt to AcceptToMemoryPool (gmaxwell) +- #9295 `43bcfca` Bugfix: Fundrawtransaction: don't terminate when keypool is empty (jonasschnelli) +- #9302 `f5d606e` Return txid even if ATMP fails for new transaction (sipa) +- #9262 `fe39f26` Prefer coins that have fewer ancestors, sanity check txn before ATMP (instagibbs) + +### Tests and QA +- #9159 `eca9b46` Wait for specific block announcement in p2p-compactblocks (ryanofsky) +- #9186 `dccdc3a` Fix use-after-free in scheduler tests (laanwj) +- #9168 `3107280` Add assert_raises_message to check specific error message (mrbandrews) +- #9191 `29435db` 0.13.2 Backports (MarcoFalke) +- #9077 `1d4c884` Increase wallet-dump RPC timeout (ryanofsky) +- #9098 `ecd7db5` Handle zombies and cluttered tmpdirs (MarcoFalke) +- #8927 `387ec9d` Add script tests for FindAndDelete in pre-segwit and segwit scripts (jl2012) +- #9200 `eebc699` bench: Fix subtle counting issue when rescaling iteration count (laanwj) + +### Miscellaneous +- #8838 `094848b` Calculate size and weight of block correctly in CreateNewBlock() (jnewbery) +- #8920 `40169dc` Set minimum required Boost to 1.47.0 (fanquake) +- #9251 `a710a43` Improvement of documentation of command line parameter 'whitelist' (wodry) +- #8932 `106da69` Allow bitcoin-tx to create v2 transactions (btcdrak) +- #8929 `12428b4` add software-properties-common (sigwo) +- #9120 `08d1c90` bug: Missed one "return false" in recent refactoring in #9067 (UdjinM6) +- #9067 `f85ee01` Fix exit codes (UdjinM6) +- #9340 `fb987b3` [0.13] Update secp256k1 subtree (MarcoFalke) +- #9229 `b172377` Remove calls to getaddrinfo_a (TheBlueMatt) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Alex Morcos +- BtcDrak +- Cory Fields +- fanquake +- Gregory Maxwell +- Gregory Sanders +- instagibbs +- Ivo van der Sangen +- jnewbery +- Johnson Lau +- Jonas Schnelli +- Luke Dashjr +- maiiz +- MarcoFalke +- Masahiko Hyuga +- Matt Corallo +- matthias +- mrbandrews +- Pavel Janík +- Pieter Wuille +- randy-waterhouse +- Russell Yanofsky +- S. Matthew English +- Steven +- Suhas Daftuar +- UdjinM6 +- Wladimir J. van der Laan +- wodry + +As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py index 75703ca42b35..9745289080da 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/qa/pull-tester/rpc-tests.py @@ -159,6 +159,8 @@ 'preciousblock.py', 'importprunedfunds.py', 'signmessages.py', + 'import-rescan.py', + 'rpcnamedargs.py', ] if ENABLE_ZMQ: testScripts.append('zmq_test.py') diff --git a/qa/rpc-tests/import-rescan.py b/qa/rpc-tests/import-rescan.py new file mode 100755 index 000000000000..2e4f290f5baf --- /dev/null +++ b/qa/rpc-tests/import-rescan.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal) +from decimal import Decimal + +import collections +import enum +import itertools +import functools + +Call = enum.Enum("Call", "single multi") +Data = enum.Enum("Data", "address pub priv") +ImportNode = collections.namedtuple("ImportNode", "rescan") + + +def call_import_rpc(call, data, address, scriptPubKey, pubkey, key, label, node, rescan): + """Helper that calls a wallet import RPC on a bitcoin node.""" + watchonly = data != Data.priv + if call == Call.single: + if data == Data.address: + response = node.importaddress(address, label, rescan) + elif data == Data.pub: + response = node.importpubkey(pubkey, label, rescan) + elif data == Data.priv: + response = node.importprivkey(key, label, rescan) + assert_equal(response, None) + elif call == Call.multi: + response = node.importmulti([{ + "scriptPubKey": { + "address": address + }, + "pubkeys": [pubkey] if data == Data.pub else [], + "keys": [key] if data == Data.priv else [], + "label": label, + "watchonly": watchonly + }], {"rescan": rescan}) + assert_equal(response, [{"success": True}]) + return watchonly + + +# List of RPCs that import a wallet key or address in various ways. +IMPORT_RPCS = [functools.partial(call_import_rpc, call, data) for call, data in itertools.product(Call, Data)] + +# List of bitcoind nodes that will import keys. +IMPORT_NODES = [ + ImportNode(rescan=True), + ImportNode(rescan=False), +] + + +class ImportRescanTest(BitcoinTestFramework): + def __init__(self): + super().__init__() + self.num_nodes = 1 + len(IMPORT_NODES) + + def setup_network(self): + extra_args = [["-debug=1"] for _ in range(self.num_nodes)] + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + for i in range(1, self.num_nodes): + connect_nodes(self.nodes[i], 0) + + def run_test(self): + # Create one transaction on node 0 with a unique amount and label for + # each possible type of wallet import RPC. + import_rpc_variants = [] + for i, import_rpc in enumerate(IMPORT_RPCS): + label = "label{}".format(i) + addr = self.nodes[0].validateaddress(self.nodes[0].getnewaddress(label)) + key = self.nodes[0].dumpprivkey(addr["address"]) + amount = 24.9375 - i * .0625 + txid = self.nodes[0].sendtoaddress(addr["address"], amount) + import_rpc = functools.partial(import_rpc, addr["address"], addr["scriptPubKey"], addr["pubkey"], key, + label) + import_rpc_variants.append((import_rpc, label, amount, txid, addr)) + + self.nodes[0].generate(1) + assert_equal(self.nodes[0].getrawmempool(), []) + sync_blocks(self.nodes) + + # For each importing node and variation of wallet import RPC, invoke + # the RPC and check the results from getbalance and listtransactions. + for node, import_node in zip(self.nodes[1:], IMPORT_NODES): + for import_rpc, label, amount, txid, addr in import_rpc_variants: + watchonly = import_rpc(node, import_node.rescan) + + balance = node.getbalance(label, 0, False, True) + if import_node.rescan: + assert_equal(balance, amount) + else: + assert_equal(balance, 0) + + txs = node.listtransactions(label, 10000, 0, True) + if import_node.rescan: + assert_equal(len(txs), 1) + assert_equal(txs[0]["account"], label) + assert_equal(txs[0]["address"], addr["address"]) + assert_equal(txs[0]["amount"], amount) + assert_equal(txs[0]["category"], "receive") + assert_equal(txs[0]["label"], label) + assert_equal(txs[0]["txid"], txid) + assert_equal(txs[0]["confirmations"], 1) + assert_equal("trusted" not in txs[0], True) + if watchonly: + assert_equal(txs[0]["involvesWatchonly"], True) + else: + assert_equal("involvesWatchonly" not in txs[0], True) + else: + assert_equal(len(txs), 0) + + # Create spends for all the imported addresses. + spend_txids = [] + fee = self.nodes[0].getnetworkinfo()["relayfee"] + for import_rpc, label, amount, txid, addr in import_rpc_variants: + raw_tx = self.nodes[0].getrawtransaction(txid) + decoded_tx = self.nodes[0].decoderawtransaction(raw_tx) + input_vout = next(out["n"] for out in decoded_tx["vout"] + if out["scriptPubKey"]["addresses"] == [addr["address"]]) + inputs = [{"txid": txid, "vout": input_vout}] + outputs = {self.nodes[0].getnewaddress(): Decimal(amount) - fee} + raw_spend_tx = self.nodes[0].createrawtransaction(inputs, outputs) + signed_spend_tx = self.nodes[0].signrawtransaction(raw_spend_tx) + spend_txid = self.nodes[0].sendrawtransaction(signed_spend_tx["hex"]) + spend_txids.append(spend_txid) + + self.nodes[0].generate(1) + assert_equal(self.nodes[0].getrawmempool(), []) + sync_blocks(self.nodes) + + # Check the results from getbalance and listtransactions after the spends. + for node, import_node in zip(self.nodes[1:], IMPORT_NODES): + txs = node.listtransactions("*", 10000, 0, True) + for (import_rpc, label, amount, txid, addr), spend_txid in zip(import_rpc_variants, spend_txids): + balance = node.getbalance(label, 0, False, True) + spend_tx = [tx for tx in txs if tx["txid"] == spend_txid] + if import_node.rescan: + assert_equal(balance, amount) + assert_equal(len(spend_tx), 1) + assert_equal(spend_tx[0]["account"], "") + assert_equal(spend_tx[0]["amount"] + spend_tx[0]["fee"], -amount) + assert_equal(spend_tx[0]["category"], "send") + assert_equal("label" not in spend_tx[0], True) + assert_equal(spend_tx[0]["confirmations"], 1) + assert_equal("trusted" not in spend_tx[0], True) + assert_equal("involvesWatchonly" not in txs[0], True) + else: + assert_equal(balance, 0) + assert_equal(spend_tx, []) + + +if __name__ == "__main__": + ImportRescanTest().main() diff --git a/qa/rpc-tests/rpcnamedargs.py b/qa/rpc-tests/rpcnamedargs.py new file mode 100755 index 000000000000..0484204668ed --- /dev/null +++ b/qa/rpc-tests/rpcnamedargs.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from decimal import Decimal + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.authproxy import JSONRPCException +from test_framework.util import ( + assert_equal, + assert_raises_jsonrpc, + assert_is_hex_string, + assert_is_hash_string, + start_nodes, + connect_nodes_bi, +) + + +class NamedArgumentTest(BitcoinTestFramework): + """ + Test named arguments on RPC calls. + """ + + def __init__(self): + super().__init__() + self.setup_clean_chain = False + self.num_nodes = 1 + + def setup_network(self, split=False): + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir) + self.is_network_split = False + self.sync_all() + + def run_test(self): + node = self.nodes[0] + h = node.help(command='getinfo') + assert(h.startswith('getinfo\n')) + + assert_raises_jsonrpc(-8, node.help, random='getinfo') + + h = node.getblockhash(height=0) + node.getblock(blockhash=h) + + assert_equal(node.echo(), []) + assert_equal(node.echo(arg0=0,arg9=9), [0] + [None]*8 + [9]) + assert_equal(node.echo(arg1=1), [None, 1]) + assert_equal(node.echo(arg9=None), [None]*10) + assert_equal(node.echo(arg0=0,arg3=3,arg9=9), [0] + [None]*2 + [3] + [None]*5 + [9]) + +if __name__ == '__main__': + NamedArgumentTest().main() diff --git a/qa/rpc-tests/test_framework/authproxy.py b/qa/rpc-tests/test_framework/authproxy.py index 9bee1962e203..09ed61129923 100644 --- a/qa/rpc-tests/test_framework/authproxy.py +++ b/qa/rpc-tests/test_framework/authproxy.py @@ -138,14 +138,16 @@ def _request(self, method, path, postdata): self.__conn.request(method, path, postdata, headers) return self._get_response() - def __call__(self, *args): + def __call__(self, *args, **argsn): AuthServiceProxy.__id_count += 1 log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name, json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) + if args and argsn: + raise ValueError('Cannot handle both named and positional arguments') postdata = json.dumps({'version': '1.1', 'method': self._service_name, - 'params': args, + 'params': args or argsn, 'id': AuthServiceProxy.__id_count}, default=EncodeDecimal, ensure_ascii=self.ensure_ascii) response = self._request('POST', self.__url.path, postdata.encode('utf-8')) if response['error'] is not None: diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index a091881727bc..77f8c75db61b 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -570,6 +570,18 @@ def assert_raises_message(exc, message, fun, *args, **kwds): else: raise AssertionError("No exception raised") +def assert_raises_jsonrpc(code, fun, *args, **kwds): + '''Check for specific JSONRPC exception code''' + try: + fun(*args, **kwds) + except JSONRPCException as e: + if e.error["code"] != code: + raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"]) + except Exception as e: + raise AssertionError("Unexpected exception raised: "+type(e).__name__) + else: + raise AssertionError("No exception raised") + def assert_is_hex_string(string): try: int(string, 16) diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 936e5c04b5a7..c5dffc34cee9 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -331,10 +331,12 @@ def run_test (self): # disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463 # '-salvagewallet', ] + chainlimit = 6 for m in maintenance: print("check " + m) stop_nodes(self.nodes) - self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3) + # set lower ancestor limit for later + self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3) while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]: # reindex will leave rpc warm up "early"; Wait for it to finish time.sleep(0.1) @@ -347,5 +349,57 @@ def run_test (self): assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) + # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== + + # Get all non-zero utxos together + chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] + singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True) + self.nodes[0].generate(1) + node0_balance = self.nodes[0].getbalance() + # Split into two chains + rawtx = self.nodes[0].createrawtransaction([{"txid":singletxid, "vout":0}], {chain_addrs[0]:node0_balance/2-Decimal('0.01'), chain_addrs[1]:node0_balance/2-Decimal('0.01')}) + signedtx = self.nodes[0].signrawtransaction(rawtx) + singletxid = self.nodes[0].sendrawtransaction(signedtx["hex"]) + txids = [singletxid, singletxid] + self.nodes[0].generate(1) + + # Make a long chain of unconfirmed payments without hitting mempool limit + # Each tx we make leaves only one output of change on a chain 1 longer + # Since the amount to send is always much less than the outputs, we only ever need one output + # So we should be able to generate exactly chainlimit txs for each original output + sending_addr = self.nodes[1].getnewaddress() + txid_list = [] + for i in range(chainlimit*2): + txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) + assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit*2) + assert_equal(len(txid_list), chainlimit*2) + + # Without walletrejectlongchains, we will still generate a txid + # The tx will be stored in the wallet but not accepted to the mempool + extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) + assert(extra_txid not in self.nodes[0].getrawmempool()) + assert(extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()]) + self.nodes[0].abandontransaction(extra_txid) + total_txs = len(self.nodes[0].listtransactions("*",99999)) + + # Try with walletrejectlongchains + # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf + stop_node(self.nodes[0],0) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)]) + + # wait for loadmempool + timeout = 10 + while (timeout > 0 and len(self.nodes[0].getrawmempool()) < chainlimit*2): + time.sleep(0.5) + timeout -= 0.5 + assert_equal(len(self.nodes[0].getrawmempool()), chainlimit*2) + + node0_balance = self.nodes[0].getbalance() + # With walletrejectlongchains we will not create the tx and store it in our wallet. + assert_raises_message(JSONRPCException, "mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) + + # Verify nothing new in wallet + assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999))) + if __name__ == '__main__': WalletTest().main() diff --git a/src/Makefile.am b/src/Makefile.am index 03ea731ea5ae..44d6c06040de 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,6 +104,7 @@ BITCOIN_CORE_H = \ consensus/consensus.h \ core_io.h \ core_memusage.h \ + cuckoocache.h \ privatesend.h \ privatesend-client.h \ privatesend-server.h \ @@ -165,6 +166,7 @@ BITCOIN_CORE_H = \ support/allocators/secure.h \ support/allocators/zeroafterfree.h \ support/cleanse.h \ + support/events.h \ support/lockedpool.h \ sync.h \ threadsafety.h \ @@ -187,6 +189,7 @@ BITCOIN_CORE_H = \ wallet/rpcwallet.h \ wallet/wallet.h \ wallet/walletdb.h \ + warnings.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h\ zmq/zmqnotificationinterface.h \ @@ -392,6 +395,7 @@ libbitcoin_common_a_SOURCES = \ scheduler.cpp \ script/sign.cpp \ script/standard.cpp \ + warnings.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 2cdd43115b8c..20203a0cd06b 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -519,7 +519,7 @@ RES_CSS = \ qt/res/css/light-hires.css \ qt/res/css/trad.css -RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png) +RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png) BITCOIN_RC = qt/res/dash-qt-res.rc @@ -583,7 +583,7 @@ $(srcdir)/qt/dashstrings.cpp: $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) PACKAGE_NAME="$(PACKAGE_NAME)" COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" COPYRIGHT_HOLDERS_SUBSTITUTION="$(COPYRIGHT_HOLDERS_SUBSTITUTION)" $(PYTHON) ../share/qt/extract_strings_qt.py $^ -translate: $(srcdir)/qt/dashstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(srcdir)/qt/dash.cpp $(BITCOIN_QT_H) $(BITCOIN_MM) +translate: $(srcdir)/qt/dashstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/dash.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) $^ -locations relative -no-obsolete -ts $(srcdir)/qt/locale/dash_en.ts diff --git a/src/Makefile.test.include b/src/Makefile.test.include index ebcd2b4d96b5..6b0e4fef4932 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -59,6 +59,7 @@ BITCOIN_TESTS =\ test/coins_tests.cpp \ test/compress_tests.cpp \ test/crypto_tests.cpp \ + test/cuckoocache_tests.cpp \ test/DoS_tests.cpp \ test/getarg_tests.cpp \ test/governance_validators_tests.cpp \ @@ -77,6 +78,7 @@ BITCOIN_TESTS =\ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ test/prevector_tests.cpp \ + test/raii_event_tests.cpp \ test/ratecheck_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ @@ -117,7 +119,7 @@ endif test_test_dash_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_dash_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) test_test_dash_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ - $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) + $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) test_test_dash_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) if ENABLE_WALLET test_test_dash_LDADD += $(LIBBITCOIN_WALLET) diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index af3d152c9a4c..8f9432e11c90 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -9,9 +9,7 @@ #include #include -using namespace benchmark; - -std::map BenchRunner::benchmarks; +std::map benchmark::BenchRunner::benchmarks; static double gettimedouble(void) { struct timeval tv; @@ -19,29 +17,29 @@ static double gettimedouble(void) { return tv.tv_usec * 0.000001 + tv.tv_sec; } -BenchRunner::BenchRunner(std::string name, BenchFunction func) +benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func) { benchmarks.insert(std::make_pair(name, func)); } void -BenchRunner::RunAll(double elapsedTimeForOne) +benchmark::BenchRunner::RunAll(double elapsedTimeForOne) { perf_init(); std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "," << "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n"; - for (std::map::iterator it = benchmarks.begin(); + for (std::map::iterator it = benchmarks.begin(); it != benchmarks.end(); ++it) { State state(it->first, elapsedTimeForOne); - BenchFunction& func = it->second; + benchmark::BenchFunction& func = it->second; func(state); } perf_fini(); } -bool State::KeepRunning() +bool benchmark::State::KeepRunning() { if (count & countMask) { ++count; diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 32690fe484be..9db6492e51dc 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -8,9 +8,7 @@ #include #include -using namespace std; - -static void addCoin(const CAmount& nValue, const CWallet& wallet, vector& vCoins) +static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector& vCoins) { int nInput = 0; @@ -36,7 +34,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, vector vCoins; + std::vector vCoins; LOCK(wallet.cs_wallet); while (state.KeepRunning()) { @@ -50,9 +48,9 @@ static void CoinSelection(benchmark::State& state) addCoin(1000 * COIN, wallet, vCoins); addCoin(3 * COIN, wallet, vCoins); - set > setCoinsRet; + std::set > setCoinsRet; CAmount nValueRet; - bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet); + bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet); assert(success); assert(nValueRet == 1003 * COIN); assert(setCoinsRet.size() == 2); diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 855e61cec010..6ff2e3195b1d 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -18,7 +18,7 @@ static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool) unsigned int sigOpCost = 4; LockPoints lp; pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry( - tx, nFee, nTime, dPriority, nHeight, pool.HasNoInputsOf(tx), + MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight, tx.GetValueOut(), spendsCoinbase, sigOpCost, lp)); } diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index 553d9786499d..fab27a4b1157 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -117,7 +117,7 @@ void SelectBaseParams(const std::string& chain) std::string ChainNameFromCommandLine() { bool fRegTest = GetBoolArg("-regtest", false); - bool fDevNet = mapArgs.count("-devnet") != 0; + bool fDevNet = IsArgSet("-devnet"); bool fTestNet = GetBoolArg("-testnet", false); int nameParamsCount = (fRegTest ? 1 : 0) + (fDevNet ? 1 : 0) + (fTestNet ? 1 : 0); @@ -136,7 +136,7 @@ std::string ChainNameFromCommandLine() std::string GetDevNetName() { // This function should never be called for non-devnets - assert(mapArgs.count("-devnet")); + assert(IsArgSet("-devnet")); std::string devNetName = GetArg("-devnet", ""); return "devnet" + (devNetName.empty() ? "" : "-" + devNetName); } diff --git a/src/cuckoocache.h b/src/cuckoocache.h new file mode 100644 index 000000000000..efd6a820b5ce --- /dev/null +++ b/src/cuckoocache.h @@ -0,0 +1,457 @@ +// Copyright (c) 2016 Jeremy Rubin +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef _BITCOIN_CUCKOOCACHE_H_ +#define _BITCOIN_CUCKOOCACHE_H_ + +#include +#include +#include +#include +#include +#include +#include + + +/** namespace CuckooCache provides high performance cache primitives + * + * Summary: + * + * 1) bit_packed_atomic_flags is bit-packed atomic flags for garbage collection + * + * 2) cache is a cache which is performant in memory usage and lookup speed. It + * is lockfree for erase operations. Elements are lazily erased on the next + * insert. + */ +namespace CuckooCache +{ +/** bit_packed_atomic_flags implements a container for garbage collection flags + * that is only thread unsafe on calls to setup. This class bit-packs collection + * flags for memory efficiency. + * + * All operations are std::memory_order_relaxed so external mechanisms must + * ensure that writes and reads are properly synchronized. + * + * On setup(n), all bits up to n are marked as collected. + * + * Under the hood, because it is an 8-bit type, it makes sense to use a multiple + * of 8 for setup, but it will be safe if that is not the case as well. + * + */ +class bit_packed_atomic_flags +{ + std::unique_ptr[]> mem; + +public: + /** No default constructor as there must be some size */ + bit_packed_atomic_flags() = delete; + + /** + * bit_packed_atomic_flags constructor creates memory to sufficiently + * keep track of garbage collection information for size entries. + * + * @param size the number of elements to allocate space for + * + * @post bit_set, bit_unset, and bit_is_set function properly forall x. x < + * size + * @post All calls to bit_is_set (without subsequent bit_unset) will return + * true. + */ + bit_packed_atomic_flags(uint32_t size) + { + // pad out the size if needed + size = (size + 7) / 8; + mem.reset(new std::atomic[size]); + for (uint32_t i = 0; i < size; ++i) + mem[i].store(0xFF); + }; + + /** setup marks all entries and ensures that bit_packed_atomic_flags can store + * at least size entries + * + * @param b the number of elements to allocate space for + * @post bit_set, bit_unset, and bit_is_set function properly forall x. x < + * b + * @post All calls to bit_is_set (without subsequent bit_unset) will return + * true. + */ + inline void setup(uint32_t b) + { + bit_packed_atomic_flags d(b); + std::swap(mem, d.mem); + } + + /** bit_set sets an entry as discardable. + * + * @param s the index of the entry to bit_set. + * @post immediately subsequent call (assuming proper external memory + * ordering) to bit_is_set(s) == true. + * + */ + inline void bit_set(uint32_t s) + { + mem[s >> 3].fetch_or(1 << (s & 7), std::memory_order_relaxed); + } + + /** bit_unset marks an entry as something that should not be overwritten + * + * @param s the index of the entry to bit_unset. + * @post immediately subsequent call (assuming proper external memory + * ordering) to bit_is_set(s) == false. + */ + inline void bit_unset(uint32_t s) + { + mem[s >> 3].fetch_and(~(1 << (s & 7)), std::memory_order_relaxed); + } + + /** bit_is_set queries the table for discardability at s + * + * @param s the index of the entry to read. + * @returns if the bit at index s was set. + * */ + inline bool bit_is_set(uint32_t s) const + { + return (1 << (s & 7)) & mem[s >> 3].load(std::memory_order_relaxed); + } +}; + +/** cache implements a cache with properties similar to a cuckoo-set + * + * The cache is able to hold up to (~(uint32_t)0) - 1 elements. + * + * Read Operations: + * - contains(*, false) + * + * Read+Erase Operations: + * - contains(*, true) + * + * Erase Operations: + * - allow_erase() + * + * Write Operations: + * - setup() + * - setup_bytes() + * - insert() + * - please_keep() + * + * Synchronization Free Operations: + * - invalid() + * - compute_hashes() + * + * User Must Guarantee: + * + * 1) Write Requires synchronized access (e.g., a lock) + * 2) Read Requires no concurrent Write, synchronized with the last insert. + * 3) Erase requires no concurrent Write, synchronized with last insert. + * 4) An Erase caller must release all memory before allowing a new Writer. + * + * + * Note on function names: + * - The name "allow_erase" is used because the real discard happens later. + * - The name "please_keep" is used because elements may be erased anyways on insert. + * + * @tparam Element should be a movable and copyable type + * @tparam Hash should be a function/callable which takes a template parameter + * hash_select and an Element and extracts a hash from it. Should return + * high-entropy hashes for `Hash h; h<0>(e) ... h<7>(e)`. + */ +template +class cache +{ +private: + /** table stores all the elements */ + std::vector table; + + /** size stores the total available slots in the hash table */ + uint32_t size; + + /** The bit_packed_atomic_flags array is marked mutable because we want + * garbage collection to be allowed to occur from const methods */ + mutable bit_packed_atomic_flags collection_flags; + + /** epoch_flags tracks how recently an element was inserted into + * the cache. true denotes recent, false denotes not-recent. See insert() + * method for full semantics. + */ + mutable std::vector epoch_flags; + + /** epoch_heuristic_counter is used to determine when a epoch might be aged + * & an expensive scan should be done. epoch_heuristic_counter is + * decremented on insert and reset to the new number of inserts which would + * cause the epoch to reach epoch_size when it reaches zero. + */ + uint32_t epoch_heuristic_counter; + + /** epoch_size is set to be the number of elements supposed to be in a + * epoch. When the number of non-erased elements in a epoch + * exceeds epoch_size, a new epoch should be started and all + * current entries demoted. epoch_size is set to be 45% of size because + * we want to keep load around 90%, and we support 3 epochs at once -- + * one "dead" which has been erased, one "dying" which has been marked to be + * erased next, and one "living" which new inserts add to. + */ + uint32_t epoch_size; + + /** hash_mask should be set to appropriately mask out a hash such that every + * masked hash is [0,size), eg, if floor(log2(size)) == 20, then hash_mask + * should be (1<<20)-1 + */ + uint32_t hash_mask; + + /** depth_limit determines how many elements insert should try to replace. + * Should be set to log2(n)*/ + uint8_t depth_limit; + + /** hash_function is a const instance of the hash function. It cannot be + * static or initialized at call time as it may have internal state (such as + * a nonce). + * */ + const Hash hash_function; + + /** compute_hashes is convenience for not having to write out this + * expression everywhere we use the hash values of an Element. + * + * @param e the element whose hashes will be returned + * @returns std::array of deterministic hashes derived from e + */ + inline std::array compute_hashes(const Element& e) const + { + return {{hash_function.template operator()<0>(e) & hash_mask, + hash_function.template operator()<1>(e) & hash_mask, + hash_function.template operator()<2>(e) & hash_mask, + hash_function.template operator()<3>(e) & hash_mask, + hash_function.template operator()<4>(e) & hash_mask, + hash_function.template operator()<5>(e) & hash_mask, + hash_function.template operator()<6>(e) & hash_mask, + hash_function.template operator()<7>(e) & hash_mask}}; + } + + /* end + * @returns a constexpr index that can never be inserted to */ + constexpr uint32_t invalid() const + { + return ~(uint32_t)0; + } + + /** allow_erase marks the element at index n as discardable. Threadsafe + * without any concurrent insert. + * @param n the index to allow erasure of + */ + inline void allow_erase(uint32_t n) const + { + collection_flags.bit_set(n); + } + + /** please_keep marks the element at index n as an entry that should be kept. + * Threadsafe without any concurrent insert. + * @param n the index to prioritize keeping + */ + inline void please_keep(uint32_t n) const + { + collection_flags.bit_unset(n); + } + + /** epoch_check handles the changing of epochs for elements stored in the + * cache. epoch_check should be run before every insert. + * + * First, epoch_check decrements and checks the cheap heuristic, and then does + * a more expensive scan if the cheap heuristic runs out. If the expensive + * scan suceeds, the epochs are aged and old elements are allow_erased. The + * cheap heuristic is reset to retrigger after the worst case growth of the + * current epoch's elements would exceed the epoch_size. + */ + void epoch_check() + { + if (epoch_heuristic_counter != 0) { + --epoch_heuristic_counter; + return; + } + // count the number of elements from the latest epoch which + // have not been erased. + uint32_t epoch_unused_count = 0; + for (uint32_t i = 0; i < size; ++i) + epoch_unused_count += epoch_flags[i] && + !collection_flags.bit_is_set(i); + // If there are more non-deleted entries in the current epoch than the + // epoch size, then allow_erase on all elements in the old epoch (marked + // false) and move all elements in the current epoch to the old epoch + // but do not call allow_erase on their indices. + if (epoch_unused_count >= epoch_size) { + for (uint32_t i = 0; i < size; ++i) + if (epoch_flags[i]) + epoch_flags[i] = false; + else + allow_erase(i); + epoch_heuristic_counter = epoch_size; + } else + // reset the epoch_heuristic_counter to next do a scan when worst + // case behavior (no intermittent erases) would exceed epoch size, + // with a reasonable minimum scan size. + // Ordinarily, we would have to sanity check std::min(epoch_size, + // epoch_unused_count), but we already know that `epoch_unused_count + // < epoch_size` in this branch + epoch_heuristic_counter = std::max(1u, std::max(epoch_size / 16, + epoch_size - epoch_unused_count)); + } + +public: + /** You must always construct a cache with some elements via a subsequent + * call to setup or setup_bytes, otherwise operations may segfault. + */ + cache() : table(), size(), collection_flags(0), epoch_flags(), + epoch_heuristic_counter(), epoch_size(), depth_limit(0), hash_function() + { + } + + /** setup initializes the container to store no more than new_size + * elements. setup rounds down to a power of two size. + * + * setup should only be called once. + * + * @param new_size the desired number of elements to store + * @returns the maximum number of elements storable + **/ + uint32_t setup(uint32_t new_size) + { + // depth_limit must be at least one otherwise errors can occur. + depth_limit = static_cast(std::log2(static_cast(std::max((uint32_t)2, new_size)))); + size = 1 << depth_limit; + hash_mask = size-1; + table.resize(size); + collection_flags.setup(size); + epoch_flags.resize(size); + // Set to 45% as described above + epoch_size = std::max((uint32_t)1, (45 * size) / 100); + // Initially set to wait for a whole epoch + epoch_heuristic_counter = epoch_size; + return size; + } + + /** setup_bytes is a convenience function which accounts for internal memory + * usage when deciding how many elements to store. It isn't perfect because + * it doesn't account for any overhead (struct size, MallocUsage, collection + * and epoch flags). This was done to simplify selecting a power of two + * size. In the expected use case, an extra two bits per entry should be + * negligible compared to the size of the elements. + * + * @param bytes the approximate number of bytes to use for this data + * structure. + * @returns the maximum number of elements storable (see setup() + * documentation for more detail) + */ + uint32_t setup_bytes(size_t bytes) + { + return setup(bytes/sizeof(Element)); + } + + /** insert loops at most depth_limit times trying to insert a hash + * at various locations in the table via a variant of the Cuckoo Algorithm + * with eight hash locations. + * + * It drops the last tried element if it runs out of depth before + * encountering an open slot. + * + * Thus + * + * insert(x); + * return contains(x, false); + * + * is not guaranteed to return true. + * + * @param e the element to insert + * @post one of the following: All previously inserted elements and e are + * now in the table, one previously inserted element is evicted from the + * table, the entry attempted to be inserted is evicted. + * + */ + inline void insert(Element e) + { + epoch_check(); + uint32_t last_loc = invalid(); + bool last_epoch = true; + std::array locs = compute_hashes(e); + // Make sure we have not already inserted this element + // If we have, make sure that it does not get deleted + for (uint32_t loc : locs) + if (table[loc] == e) { + please_keep(loc); + epoch_flags[loc] = last_epoch; + return; + } + for (uint8_t depth = 0; depth < depth_limit; ++depth) { + // First try to insert to an empty slot, if one exists + for (uint32_t loc : locs) { + if (!collection_flags.bit_is_set(loc)) + continue; + table[loc] = std::move(e); + please_keep(loc); + epoch_flags[loc] = last_epoch; + return; + } + /** Swap with the element at the location that was + * not the last one looked at. Example: + * + * 1) On first iteration, last_loc == invalid(), find returns last, so + * last_loc defaults to locs[0]. + * 2) On further iterations, where last_loc == locs[k], last_loc will + * go to locs[k+1 % 8], i.e., next of the 8 indicies wrapping around + * to 0 if needed. + * + * This prevents moving the element we just put in. + * + * The swap is not a move -- we must switch onto the evicted element + * for the next iteration. + */ + last_loc = locs[(1 + (std::find(locs.begin(), locs.end(), last_loc) - locs.begin())) & 7]; + std::swap(table[last_loc], e); + // Can't std::swap a std::vector::reference and a bool&. + bool epoch = last_epoch; + last_epoch = epoch_flags[last_loc]; + epoch_flags[last_loc] = epoch; + + // Recompute the locs -- unfortunately happens one too many times! + locs = compute_hashes(e); + } + } + + /* contains iterates through the hash locations for a given element + * and checks to see if it is present. + * + * contains does not check garbage collected state (in other words, + * garbage is only collected when the space is needed), so: + * + * insert(x); + * if (contains(x, true)) + * return contains(x, false); + * else + * return true; + * + * executed on a single thread will always return true! + * + * This is a great property for re-org performance for example. + * + * contains returns a bool set true if the element was found. + * + * @param e the element to check + * @param erase + * + * @post if erase is true and the element is found, then the garbage collect + * flag is set + * @returns true if the element is found, false otherwise + */ + inline bool contains(const Element& e, const bool erase) const + { + std::array locs = compute_hashes(e); + for (uint32_t loc : locs) + if (table[loc] == e) { + if (erase) + allow_erase(loc); + return true; + } + return false; + } +}; +} // namespace CuckooCache + +#endif diff --git a/src/dash-cli.cpp b/src/dash-cli.cpp index cd6fe4f160b2..d453c45c432c 100644 --- a/src/dash-cli.cpp +++ b/src/dash-cli.cpp @@ -18,15 +18,15 @@ #include #include -#include -#include #include #include +#include "support/events.h" #include static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; +static const bool DEFAULT_NAMED=false; static const int CONTINUE_EXECUTION=-1; std::string HelpMessageCli() @@ -37,6 +37,7 @@ std::string HelpMessageCli() strUsage += HelpMessageOpt("-conf=", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME)); strUsage += HelpMessageOpt("-datadir=", _("Specify data directory")); AppendParamsHelpMessages(strUsage); + strUsage += HelpMessageOpt("-named", strprintf(_("Pass named instead of positional arguments (default: %s)"), DEFAULT_NAMED)); strUsage += HelpMessageOpt("-rpcconnect=", strprintf(_("Send commands to node running on (default: %s)"), DEFAULT_RPCCONNECT)); strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Connect to JSON-RPC on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start")); @@ -77,11 +78,12 @@ static int AppInitRPC(int argc, char* argv[]) // Parameters // ParseParameters(argc, argv); - if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) { + if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) { std::string strUsage = strprintf(_("%s RPC client version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n"; - if (!mapArgs.count("-version")) { + if (!IsArgSet("-version")) { strUsage += "\n" + _("Usage:") + "\n" + " dash-cli [options] [params] " + strprintf(_("Send command to %s"), _(PACKAGE_NAME)) + "\n" + + " dash-cli [options] -named [name=value] ... " + strprintf(_("Send command to %s (with named arguments)"), _(PACKAGE_NAME)) + "\n" + " dash-cli [options] help " + _("List commands") + "\n" + " dash-cli [options] help " + _("Get help for a command") + "\n"; @@ -95,19 +97,19 @@ static int AppInitRPC(int argc, char* argv[]) } return EXIT_SUCCESS; } - bool datadirFromCmdLine = mapArgs.count("-datadir") != 0; + bool datadirFromCmdLine = IsArgSet("-datadir"); if (datadirFromCmdLine && !boost::filesystem::is_directory(GetDataDir(false))) { - fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str()); + fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str()); return EXIT_FAILURE; } try { - ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME), mapArgs, mapMultiArgs); + ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)); } catch (const std::exception& e) { fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return EXIT_FAILURE; } if (!datadirFromCmdLine && !boost::filesystem::is_directory(GetDataDir(false))) { - fprintf(stderr, "Error: Specified data directory \"%s\" from config file does not exist.\n", mapArgs["-datadir"].c_str()); + fprintf(stderr, "Error: Specified data directory \"%s\" from config file does not exist.\n", GetArg("-datadir", "").c_str()); return EXIT_FAILURE; } // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause) @@ -196,28 +198,24 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); int port = GetArg("-rpcport", BaseParams().RPCPort()); - // Create event base - struct event_base *base = event_base_new(); // TODO RAII - if (!base) - throw std::runtime_error("cannot create event_base"); + // Obtain event base + raii_event_base base = obtain_event_base(); // Synchronously look up hostname - struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII - if (evcon == NULL) - throw std::runtime_error("create connection failed"); - evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); + raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port); + evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); HTTPReply response; - struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII + raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response); if (req == NULL) throw std::runtime_error("create http request failed"); #if LIBEVENT_VERSION_NUMBER >= 0x02010300 - evhttp_request_set_error_cb(req, http_error_cb); + evhttp_request_set_error_cb(req.get(), http_error_cb); #endif // Get credentials std::string strRPCUserColonPass; - if (mapArgs["-rpcpassword"] == "") { + if (GetArg("-rpcpassword", "") == "") { // Try fall back to cookie-based authentication if no password is provided if (!GetAuthCookie(&strRPCUserColonPass)) { throw std::runtime_error(strprintf( @@ -226,10 +224,10 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) } } else { - strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", ""); } - struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req); + struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get()); assert(output_headers); evhttp_add_header(output_headers, "Host", host.c_str()); evhttp_add_header(output_headers, "Connection", "close"); @@ -237,20 +235,17 @@ UniValue CallRPC(const std::string& strMethod, const UniValue& params) // Attach request data std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n"; - struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req); + struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get()); assert(output_buffer); evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); - int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/"); + int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/"); + req.release(); // ownership moved to evcon in above call if (r != 0) { - evhttp_connection_free(evcon); - event_base_free(base); throw CConnectionFailed("send http request failed"); } - event_base_dispatch(base); - evhttp_connection_free(evcon); - event_base_free(base); + event_base_dispatch(base.get()); if (response.status == 0) throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error)); @@ -292,7 +287,14 @@ int CommandLineRPC(int argc, char *argv[]) if (args.size() < 1) throw std::runtime_error("too few parameters (need at least command)"); std::string strMethod = args[0]; - UniValue params = RPCConvertValues(strMethod, std::vector(args.begin()+1, args.end())); + args.erase(args.begin()); // Remove trailing method name from arguments vector + + UniValue params; + if(GetBoolArg("-named", DEFAULT_NAMED)) { + params = RPCConvertNamedValues(strMethod, args); + } else { + params = RPCConvertValues(strMethod, args); + } // Execute and handle connection failures with -rpcwait const bool fWait = GetBoolArg("-rpcwait", false); diff --git a/src/dash-tx.cpp b/src/dash-tx.cpp index b36a94bf9ce4..5b70788b7d15 100644 --- a/src/dash-tx.cpp +++ b/src/dash-tx.cpp @@ -51,7 +51,7 @@ static int AppInitRawTx(int argc, char* argv[]) fCreateBlank = GetBoolArg("-create", false); - if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help")) + if (argc<2 || IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help")) { // First part of help message is specific to this utility std::string strUsage = strprintf(_("%s dash-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" + diff --git a/src/dashd.cpp b/src/dashd.cpp index 394a52b5e9bd..03e67d725c6a 100644 --- a/src/dashd.cpp +++ b/src/dashd.cpp @@ -77,11 +77,11 @@ bool AppInit(int argc, char* argv[]) ParseParameters(argc, argv); // Process help and version before taking care about datadir - if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) + if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) { std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n"; - if (mapArgs.count("-version")) + if (IsArgSet("-version")) { strUsage += FormatParagraph(LicenseInfo()); } @@ -99,22 +99,22 @@ bool AppInit(int argc, char* argv[]) try { - bool datadirFromCmdLine = mapArgs.count("-datadir") != 0; + bool datadirFromCmdLine = IsArgSet("-datadir"); if (datadirFromCmdLine && !boost::filesystem::is_directory(GetDataDir(false))) { - fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str()); + fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str()); return false; } try { - ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME), mapArgs, mapMultiArgs); + ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)); } catch (const std::exception& e) { fprintf(stderr,"Error reading configuration file: %s\n", e.what()); return false; } if (!datadirFromCmdLine && !boost::filesystem::is_directory(GetDataDir(false))) { - fprintf(stderr, "Error: Specified data directory \"%s\" from config file does not exist.\n", mapArgs["-datadir"].c_str()); + fprintf(stderr, "Error: Specified data directory \"%s\" from config file does not exist.\n", GetArg("-datadir", "").c_str()); return EXIT_FAILURE; } // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) diff --git a/src/httprpc.cpp b/src/httprpc.cpp index e35acb6cd99c..970ce2db73b7 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -95,7 +95,7 @@ static bool multiUserAuthorized(std::string strUserPass) if (mapMultiArgs.count("-rpcauth") > 0) { //Search for multi-user login/pass "rpcauth" from config - BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"]) + BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs.at("-rpcauth")) { std::vector vFields; boost::split(vFields, strRPCAuth, boost::is_any_of(":$")); @@ -215,7 +215,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) static bool InitRPCAuthentication() { - if (mapArgs["-rpcpassword"] == "") + if (GetArg("-rpcpassword", "") == "") { LogPrintf("No rpcpassword set - using random cookie authentication\n"); if (!GenerateAuthCookie(&strRPCUserColonPass)) { @@ -226,7 +226,7 @@ static bool InitRPCAuthentication() } } else { LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.\n"); - strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", ""); } return true; } diff --git a/src/httpserver.cpp b/src/httpserver.cpp index c74292225362..79e9f1ecb000 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -205,7 +205,7 @@ static bool InitHTTPAllowList() rpc_allow_subnets.push_back(CSubNet(localv4, 8)); // always allow IPv4 local subnet rpc_allow_subnets.push_back(CSubNet(localv6)); // always allow IPv6 localhost if (mapMultiArgs.count("-rpcallowip")) { - const std::vector& vAllow = mapMultiArgs["-rpcallowip"]; + const std::vector& vAllow = mapMultiArgs.at("-rpcallowip"); for (std::string strAllow : vAllow) { CSubNet subnet; LookupSubNet(strAllow.c_str(), subnet); @@ -323,14 +323,14 @@ static bool HTTPBindAddresses(struct evhttp* http) std::vector > endpoints; // Determine what addresses to bind to - if (!mapArgs.count("-rpcallowip")) { // Default to loopback if not allowing external IPs + if (!IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs endpoints.push_back(std::make_pair("::1", defaultPort)); endpoints.push_back(std::make_pair("127.0.0.1", defaultPort)); - if (mapArgs.count("-rpcbind")) { + if (IsArgSet("-rpcbind")) { LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); } - } else if (mapArgs.count("-rpcbind")) { // Specific bind address - const std::vector& vbind = mapMultiArgs["-rpcbind"]; + } else if (mapMultiArgs.count("-rpcbind")) { // Specific bind address + const std::vector& vbind = mapMultiArgs.at("-rpcbind"); for (std::vector::const_iterator i = vbind.begin(); i != vbind.end(); ++i) { int port = defaultPort; std::string host; diff --git a/src/init.cpp b/src/init.cpp index 4aa76342ab1f..3fd1afcc184d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -64,6 +64,7 @@ #endif // ENABLE_WALLET #include "privatesend-server.h" #include "spork.h" +#include "warnings.h" #include #include @@ -159,6 +160,7 @@ static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat"; // std::atomic fRequestShutdown(false); +std::atomic fDumpMempoolLater(false); void StartShutdown() { @@ -250,7 +252,8 @@ void PrepareShutdown() flatdb4.Dump(netfulfilledman); UnregisterNodeSignals(GetNodeSignals()); - DumpMempool(); + if (fDumpMempoolLater) + DumpMempool(); if (fFeeEstimatesInitialized) { @@ -582,7 +585,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpccookiefile=", _("Location of the auth cookie (default: data dir)")); strUsage += HelpMessageOpt("-rpcuser=", _("Username for JSON-RPC connections")); strUsage += HelpMessageOpt("-rpcpassword=", _("Password for JSON-RPC connections")); - strUsage += HelpMessageOpt("-rpcauth=", _("Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. This option can be specified multiple times")); + strUsage += HelpMessageOpt("-rpcauth=", _("Username and hashed password for JSON-RPC connections. The field comes in the format: :$. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=/rpcpassword= pair of arguments. This option can be specified multiple times")); strUsage += HelpMessageOpt("-rpcport=", strprintf(_("Listen for JSON-RPC connections on (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcallowip=", _("Allow JSON-RPC connections from specified source. Valid for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times")); strUsage += HelpMessageOpt("-rpcthreads=", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS)); @@ -765,6 +768,7 @@ void ThreadImport(std::vector vImportFiles) } } // End scope of CImportingNow LoadMempool(); + fDumpMempoolLater = !fRequestShutdown; } /** Sanity checks @@ -806,11 +810,11 @@ void InitParameterInteraction() { // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified - if (mapArgs.count("-bind")) { + if (IsArgSet("-bind")) { if (SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); } - if (mapArgs.count("-whitebind")) { + if (IsArgSet("-whitebind")) { if (SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); } @@ -821,7 +825,7 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -masternode=1 -> setting -listen=1\n", __func__); } - if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) { + if (mapMultiArgs.count("-connect") && mapMultiArgs.at("-connect").size() > 0) { // when only connecting to trusted nodes, do not seed via DNS, or listen by default if (SoftSetBoolArg("-dnsseed", false)) LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__); @@ -829,7 +833,7 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); } - if (mapArgs.count("-proxy")) { + if (IsArgSet("-proxy")) { // to protect privacy, do not listen by default if a default proxy server is specified if (SoftSetBoolArg("-listen", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); @@ -852,7 +856,7 @@ void InitParameterInteraction() LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } - if (mapArgs.count("-externalip")) { + if (IsArgSet("-externalip")) { // if an explicit public IP is specified, do not try to find others if (SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); @@ -878,19 +882,19 @@ void InitParameterInteraction() #ifdef ENABLE_WALLET int nLiqProvTmp = GetArg("-liquidityprovider", DEFAULT_PRIVATESEND_LIQUIDITY); if (nLiqProvTmp > 0) { - mapArgs["-enableprivatesend"] = "1"; + ForceSetArg("-enableprivatesend", "1"); LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -enableprivatesend=1\n", __func__, nLiqProvTmp); - mapArgs["-privatesendrounds"] = "99999"; + ForceSetArg("-privatesendrounds", "99999"); LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -privatesendrounds=99999\n", __func__, nLiqProvTmp); - mapArgs["-privatesendamount"] = "999999"; + ForceSetArg("-privatesendamount", "999999"); LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -privatesendamount=999999\n", __func__, nLiqProvTmp); - mapArgs["-privatesendmultisession"] = "0"; + ForceSetArg("-privatesendmultisession", "0"); LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -privatesendmultisession=0\n", __func__, nLiqProvTmp); } - if (mapArgs.count("-hdseed") && IsHex(GetArg("-hdseed", "not hex")) && (mapArgs.count("-mnemonic") || mapArgs.count("-mnemonicpassphrase"))) { - mapArgs.erase("-mnemonic"); - mapArgs.erase("-mnemonicpassphrase"); + if (IsArgSet("-hdseed") && IsHex(GetArg("-hdseed", "not hex")) && (IsArgSet("-mnemonic") || IsArgSet("-mnemonicpassphrase"))) { + ForceRemoveArg("-mnemonic"); + ForceRemoveArg("-mnemonicpassphrase"); LogPrintf("%s: parameter interaction: can't use -hdseed and -mnemonic/-mnemonicpassphrase together, will prefer -seed\n", __func__); } #endif // ENABLE_WALLET @@ -903,7 +907,7 @@ void InitParameterInteraction() GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX); if (fAdditionalIndexes && GetArg("-checklevel", DEFAULT_CHECKLEVEL) < 4) { - mapArgs["-checklevel"] = "4"; + ForceSetArg("-checklevel", "4"); LogPrintf("%s: parameter interaction: additional indexes -> setting -checklevel=4\n", __func__); } } @@ -1004,11 +1008,11 @@ bool AppInitParameterInteraction() return InitError(_("Prune mode is incompatible with -txindex.")); } - if (mapArgs.count("-devnet")) { + if (IsArgSet("-devnet")) { // Require setting of ports when running devnet - if (GetArg("-listen", DEFAULT_LISTEN) && !mapArgs.count("-port")) + if (GetArg("-listen", DEFAULT_LISTEN) && !IsArgSet("-port")) return InitError(_("-port must be specified when -devnet and -listen are specified")); - if (GetArg("-server", false) && !mapArgs.count("-rpcport")) + if (GetArg("-server", false) && !IsArgSet("-rpcport")) return InitError(_("-rpcport must be specified when -devnet and -server are specified")); if (mapMultiArgs.count("-devnet") > 1) @@ -1025,28 +1029,30 @@ bool AppInitParameterInteraction() nMaxConnections = std::max(nUserMaxConnections, 0); // Trim requested connection counts, to fit into system limitations - nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0); - nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS); + nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0); + nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS); if (nFD < MIN_CORE_FILEDESCRIPTORS) return InitError(_("Not enough file descriptors available.")); - nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections); + nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections); if (nMaxConnections < nUserMaxConnections) InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags - fDebug = !mapMultiArgs["-debug"].empty(); + fDebug = mapMultiArgs.count("-debug"); // Special-case: if -debug=0/-nodebug is set, turn off debugging messages - const vector& categories = mapMultiArgs["-debug"]; - if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), string("0")) != categories.end()) - fDebug = false; + if (fDebug) { + const vector& categories = mapMultiArgs.at("-debug"); + if (GetBoolArg("-nodebug", false) || find(categories.begin(), categories.end(), string("0")) != categories.end()) + fDebug = false; + } // Check for -debugnet if (GetBoolArg("-debugnet", false)) InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net.")); // Check for -socks - as this is a privacy risk to continue, exit here - if (mapArgs.count("-socks")) + if (IsArgSet("-socks")) return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); // Check for -tor - as this is a privacy risk to continue, exit here if (GetBoolArg("-tor", false)) @@ -1058,7 +1064,7 @@ bool AppInitParameterInteraction() if (GetBoolArg("-whitelistalwaysrelay", false)) InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); - if (mapArgs.count("-blockminsize")) + if (IsArgSet("-blockminsize")) InitWarning("Unsupported argument -blockminsize ignored."); // Checkmempool and checkblockindex default to true in regtest mode @@ -1119,11 +1125,11 @@ bool AppInitParameterInteraction() // a transaction spammer can cheaply fill blocks using // 1-satoshi-fee transactions. It should be set above the real // cost to you of processing a transaction. - if (mapArgs.count("-minrelaytxfee")) + if (IsArgSet("-minrelaytxfee")) { CAmount n = 0; - if (!ParseMoney(mapArgs["-minrelaytxfee"], n) || 0 == n) - return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"])); + if (!ParseMoney(GetArg("-minrelaytxfee", ""), n) || 0 == n) + return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", ""))); // High fee check is done afterward in CWallet::ParameterInteraction() ::minRelayTxFee = CFeeRate(n); } @@ -1153,7 +1159,7 @@ bool AppInitParameterInteraction() nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); - if ((!fEnableReplacement) && mapArgs.count("-mempoolreplacement")) { + if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) { // Minimal effort at forwards compatibility std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible std::vector vstrReplacementModes; @@ -1232,7 +1238,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Using data directory %s\n", GetDataDir().string()); LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string()); - LogPrintf("Using at most %i connections (%i file descriptors available)\n", nMaxConnections, nFD); + LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); + + InitSignatureCache(); LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); if (nScriptCheckThreads) { @@ -1240,7 +1248,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) threadGroup.create_thread(&ThreadScriptCheck); } - if (mapArgs.count("-sporkkey")) // spork priv key + if (IsArgSet("-sporkkey")) // spork priv key { if (!sporkManager.SetPrivKey(GetArg("-sporkkey", ""))) return InitError(_("Unable to sign spork message, wrong key?")); @@ -1297,11 +1305,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) uacomments.push_back(strprintf("devnet=%s", GetDevNetName())); } - BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"]) - { - if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) - return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); - uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)); + if (mapMultiArgs.count("-uacomment")) { + BOOST_FOREACH(string cmt, mapMultiArgs.at("-uacomment")) + { + if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); + uacomments.push_back(cmt); + } } strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { @@ -1309,9 +1319,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) strSubVersion.size(), MAX_SUBVERSION_LENGTH)); } - if (mapArgs.count("-onlynet")) { + if (mapMultiArgs.count("-onlynet")) { std::set nets; - BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) { + BOOST_FOREACH(const std::string& snet, mapMultiArgs.at("-onlynet")) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1324,8 +1334,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) } } - if (mapArgs.count("-whitelist")) { - BOOST_FOREACH(const std::string& net, mapMultiArgs["-whitelist"]) { + if (mapMultiArgs.count("-whitelist")) { + BOOST_FOREACH(const std::string& net, mapMultiArgs.at("-whitelist")) { CSubNet subnet; LookupSubNet(net.c_str(), subnet); if (!subnet.IsValid()) @@ -1377,14 +1387,16 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) if (fListen) { bool fBound = false; - if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) { - BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) { + if (mapMultiArgs.count("-bind")) { + BOOST_FOREACH(const std::string& strBind, mapMultiArgs.at("-bind")) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false)) return InitError(ResolveErrMsg("bind", strBind)); fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR)); } - BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) { + } + if (mapMultiArgs.count("-whitebind")) { + BOOST_FOREACH(const std::string& strBind, mapMultiArgs.at("-whitebind")) { CService addrBind; if (!Lookup(strBind.c_str(), addrBind, 0, false)) return InitError(ResolveErrMsg("whitebind", strBind)); @@ -1393,7 +1405,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) fBound |= Bind(connman, addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST)); } } - else { + if (!mapMultiArgs.count("-bind") && !mapMultiArgs.count("-whitebind")) { struct in_addr inaddr_any; inaddr_any.s_addr = INADDR_ANY; fBound |= Bind(connman, CService(in6addr_any, GetListenPort()), BF_NONE); @@ -1403,8 +1415,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(_("Failed to listen on any port. Use -listen=0 if you want this.")); } - if (mapArgs.count("-externalip")) { - BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) { + if (mapMultiArgs.count("-externalip")) { + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs.at("-externalip")) { CService addrLocal; if (Lookup(strAddr.c_str(), addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) AddLocal(addrLocal, LOCAL_MANUAL); @@ -1413,11 +1425,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) } } - BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"]) - connman.AddOneShot(strDest); + if (mapMultiArgs.count("-seednode")) { + BOOST_FOREACH(const std::string& strDest, mapMultiArgs.at("-seednode")) + connman.AddOneShot(strDest); + } #if ENABLE_ZMQ - pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs); + pzmqNotificationInterface = CZMQNotificationInterface::Create(); if (pzmqNotificationInterface) { RegisterValidationInterface(pzmqNotificationInterface); @@ -1430,7 +1444,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; - if (mapArgs.count("-maxuploadtarget")) { + if (IsArgSet("-maxuploadtarget")) { nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; } @@ -1653,13 +1667,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) fHaveGenesis = true; } - if (mapArgs.count("-blocknotify")) + if (IsArgSet("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); std::vector vImportFiles; - if (mapArgs.count("-loadblock")) + if (mapMultiArgs.count("-loadblock")) { - BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"]) + BOOST_FOREACH(const std::string& strFile, mapMultiArgs.at("-loadblock")) vImportFiles.push_back(strFile); } @@ -1826,6 +1840,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nRelevantServices = nRelevantServices; connOptions.nMaxConnections = nMaxConnections; connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections); + connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS; connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; diff --git a/src/instantx.cpp b/src/instantx.cpp index a2144e6abc29..b3ea9008e730 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -17,6 +17,7 @@ #include "util.h" #include "consensus/validation.h" #include "validationinterface.h" +#include "warnings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #endif // ENABLE_WALLET @@ -774,7 +775,7 @@ bool CInstantSend::GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet bool CInstantSend::IsInstantSendReadyToLock(const uint256& txHash) { - if(!fEnableInstantSend || fLargeWorkForkFound || fLargeWorkInvalidChainFound || + if(!fEnableInstantSend || GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound() || !sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return false; LOCK(cs_instantsend); @@ -786,7 +787,7 @@ bool CInstantSend::IsInstantSendReadyToLock(const uint256& txHash) bool CInstantSend::IsLockedInstantSendTransaction(const uint256& txHash) { - if(!fEnableInstantSend || fLargeWorkForkFound || fLargeWorkInvalidChainFound || + if(!fEnableInstantSend || GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound() || !sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) return false; LOCK(cs_instantsend); @@ -812,7 +813,7 @@ bool CInstantSend::IsLockedInstantSendTransaction(const uint256& txHash) int CInstantSend::GetTransactionLockSignatures(const uint256& txHash) { if(!fEnableInstantSend) return -1; - if(fLargeWorkForkFound || fLargeWorkInvalidChainFound) return -2; + if(GetfLargeWorkForkFound() || GetfLargeWorkInvalidChainFound()) return -2; if(!sporkManager.IsSporkActive(SPORK_2_INSTANTSEND_ENABLED)) return -3; LOCK(cs_instantsend); diff --git a/src/net.cpp b/src/net.cpp index f9b35dfa2e1a..0d107895e630 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -622,6 +622,7 @@ void CNode::copyStats(CNodeStats &stats) X(nVersion); X(cleanSubVer); X(fInbound); + X(fAddnode); X(nStartingHeight); X(nSendBytes); X(mapSendBytesPerMsgCmd); @@ -1598,12 +1599,12 @@ void CConnman::ProcessOneShot() void CConnman::ThreadOpenConnections() { // Connect to specific addresses - if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) + if (mapMultiArgs.count("-connect") && mapMultiArgs.at("-connect").size() > 0) { for (int64_t nLoop = 0;; nLoop++) { ProcessOneShot(); - BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"]) + BOOST_FOREACH(const std::string& strAddr, mapMultiArgs.at("-connect")) { CAddress addr(CService(), NODE_NONE); OpenNetworkConnection(addr, false, NULL, strAddr.c_str()); @@ -1659,7 +1660,12 @@ void CConnman::ThreadOpenConnections() if (!Params().AllowMultipleAddressesFromGroup()) { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { - if (!pnode->fInbound && !pnode->fMasternode) { + if (!pnode->fInbound && !pnode->fAddnode && !pnode->fMasternode) { + // Netgroups for inbound and addnode peers are not excluded because our goal here + // is to not use multiple of our limited outbound slots on a single netgroup + // but inbound and addnode peers do not use our outbound slots. Inbound peers + // also have the added issue that they're attacker controlled and could be used + // to prevent us from connecting to particular hosts if we used them here. setConnected.insert(pnode->addr.GetGroup()); nOutbound++; } @@ -1796,24 +1802,33 @@ void CConnman::ThreadOpenAddedConnections() { { LOCK(cs_vAddedNodes); - vAddedNodes = mapMultiArgs["-addnode"]; + if (mapMultiArgs.count("-addnode")) + vAddedNodes = mapMultiArgs.at("-addnode"); } - for (unsigned int i = 0; true; i++) + while (true) { + CSemaphoreGrant grant(*semAddnode); std::vector vInfo = GetAddedNodeInfo(); + bool tried = false; for (const AddedNodeInfo& info : vInfo) { if (!info.fConnected) { - CSemaphoreGrant grant(*semOutbound); + if (!grant.TryAcquire()) { + // If we've used up our semaphore and need a new one, lets not wait here since while we are waiting + // the addednodeinfo state might change. + break; + } // If strAddedNode is an IP/port, decode it immediately, so // OpenNetworkConnection can detect existing connections to that IP/port. + tried = true; CService service(LookupNumeric(info.strAddedNode.c_str(), Params().GetDefaultPort())); - OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false); + OpenNetworkConnection(CAddress(service, NODE_NONE), false, &grant, info.strAddedNode.c_str(), false, false, true); if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return; } } - if (!interruptNet.sleep_for(std::chrono::minutes(2))) + // Retry every 60 seconds if a connection was attempted, otherwise two seconds + if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2))) return; } } @@ -1821,7 +1836,7 @@ void CConnman::ThreadOpenAddedConnections() void CConnman::ThreadMnbRequestConnections() { // Connecting to specific addresses, no masternode connections available - if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) + if (IsArgSet("-connect") && mapMultiArgs.at("-connect").size() > 0) return; while (!interruptNet) @@ -1848,7 +1863,7 @@ void CConnman::ThreadMnbRequestConnections() } CAddress addr(p.first, NODE_NETWORK); - OpenNetworkConnection(CAddress(p.first, NODE_NETWORK), false, NULL, NULL, false, false, true); + OpenMasternodeConnection(addr); ForNode(addr, CConnman::AllNodes, [&](CNode* pnode) { if (pnode->fDisconnect) return false; @@ -1865,7 +1880,7 @@ void CConnman::ThreadMnbRequestConnections() } // if successful, this moves the passed grant to the constructed node -bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fConnectToMasternode) +bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool fAddnode, bool fConnectToMasternode) { // // Initiate outbound network connection @@ -1894,6 +1909,8 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai pnode->fOneShot = true; if (fFeeler) pnode->fFeeler = true; + if (fAddnode) + pnode->fAddnode = true; if (fConnectToMasternode) pnode->fMasternode = true; @@ -1907,7 +1924,7 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai } bool CConnman::OpenMasternodeConnection(const CAddress &addrConnect) { - return OpenNetworkConnection(addrConnect, false, NULL, NULL, false, false, true); + return OpenNetworkConnection(addrConnect, false, NULL, NULL, false, false, false, true); } void CConnman::ThreadMessageHandler() @@ -2133,9 +2150,11 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe nSendBufferMaxSize = 0; nReceiveFloodSize = 0; semOutbound = NULL; + semAddnode = NULL; semMasternodeOutbound = NULL; nMaxConnections = 0; nMaxOutbound = 0; + nMaxAddnode = 0; nBestHeight = 0; clientInterface = NULL; flagInterruptMsgProc = false; @@ -2157,6 +2176,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min((connOptions.nMaxOutbound), nMaxConnections); + nMaxAddnode = connOptions.nMaxAddnode; nMaxFeeler = connOptions.nMaxFeeler; nSendBufferMaxSize = connOptions.nSendBufferMaxSize; @@ -2209,6 +2229,10 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c // initialize semaphore semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections)); } + if (semAddnode == NULL) { + // initialize semaphore + semAddnode = new CSemaphore(nMaxAddnode); + } if (semMasternodeOutbound == NULL) { // initialize semaphore @@ -2239,7 +2263,7 @@ bool CConnman::Start(CScheduler& scheduler, std::string& strNodeError, Options c threadOpenAddedConnections = std::thread(&TraceThread >, "addcon", std::function(std::bind(&CConnman::ThreadOpenAddedConnections, this))); // Initiate outbound connections unless connect=0 - if (!mapArgs.count("-connect") || mapMultiArgs["-connect"].size() != 1 || mapMultiArgs["-connect"][0] != "0") + if (!mapMultiArgs.count("-connect") || mapMultiArgs.at("-connect").size() != 1 || mapMultiArgs.at("-connect")[0] != "0") threadOpenConnections = std::thread(&TraceThread >, "opencon", std::function(std::bind(&CConnman::ThreadOpenConnections, this))); // Initiate masternode connections @@ -2308,6 +2332,10 @@ void CConnman::Stop() if (threadSocketHandler.joinable()) threadSocketHandler.join(); + if (semAddnode) + for (int i=0; ipost(); + if (semMasternodeOutbound) for (int i=0; ipost(); @@ -2339,6 +2367,8 @@ void CConnman::Stop() vhListenSocket.clear(); delete semOutbound; semOutbound = NULL; + delete semAddnode; + semAddnode = NULL; delete semMasternodeOutbound; semMasternodeOutbound = NULL; } @@ -2636,6 +2666,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn strSubVer = ""; fWhitelisted = false; fOneShot = false; + fAddnode = false; fClient = false; // set by version message fFeeler = false; fSuccessfullyConnected = false; diff --git a/src/net.h b/src/net.h index fe7871e57296..4305f5dd1236 100644 --- a/src/net.h +++ b/src/net.h @@ -61,8 +61,10 @@ static const unsigned int MAX_ADDR_TO_SEND = 1000; static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 3 * 1024 * 1024; /** Maximum length of strSubVer in `version` message */ static const unsigned int MAX_SUBVERSION_LENGTH = 256; -/** Maximum number of outgoing nodes */ +/** Maximum number of automatic outgoing nodes */ static const int MAX_OUTBOUND_CONNECTIONS = 8; +/** Maximum number of addnode outgoing nodes */ +static const int MAX_ADDNODE_CONNECTIONS = 8; /** Maximum number if outgoing masternodes */ static const int MAX_OUTBOUND_MASTERNODE_CONNECTIONS = 20; /** -listen default */ @@ -140,6 +142,7 @@ class CConnman ServiceFlags nRelevantServices = NODE_NONE; int nMaxConnections = 0; int nMaxOutbound = 0; + int nMaxAddnode = 0; int nMaxFeeler = 0; int nBestHeight = 0; CClientUIInterface* uiInterface = nullptr; @@ -156,7 +159,7 @@ class CConnman bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false); bool GetNetworkActive() const { return fNetworkActive; }; void SetNetworkActive(bool active); - bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fConnectToMasternode = false); + bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false, bool fConnectToMasternode = false); bool OpenMasternodeConnection(const CAddress& addrConnect); bool CheckIncomingNonce(uint64_t nonce); @@ -483,9 +486,11 @@ class CConnman ServiceFlags nRelevantServices; CSemaphore *semOutbound; + CSemaphore *semAddnode; CSemaphore *semMasternodeOutbound; int nMaxConnections; int nMaxOutbound; + int nMaxAddnode; int nMaxFeeler; std::atomic nBestHeight; CClientUIInterface* clientInterface; @@ -602,6 +607,7 @@ class CNodeStats int nVersion; std::string cleanSubVer; bool fInbound; + bool fAddnode; int nStartingHeight; uint64_t nSendBytes; mapMsgCmdSize mapSendBytesPerMsgCmd; @@ -703,6 +709,7 @@ class CNode bool fWhitelisted; // This peer can bypass DoS banning. bool fFeeler; // If true this node is being used as a short lived feeler. bool fOneShot; + bool fAddnode; bool fClient; const bool fInbound; std::atomic_bool fSuccessfullyConnected; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b60d7b40da9c..6bbf82ec58f0 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -64,7 +64,7 @@ struct IteratorComparator struct COrphanTx { // When modifying, adapt the copy of this definition in tests/DoS_tests. - CTransaction tx; + CTransactionRef tx; NodeId fromPeer; int64_t nTimeExpire; }; @@ -527,9 +527,9 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) // mapOrphanTransactions // -bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { - uint256 hash = tx.GetHash(); + const uint256& hash = tx->GetHash(); if (mapOrphanTransactions.count(hash)) return false; @@ -540,7 +540,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c // have been mined or received. // 100 orphans, each of which is at most 99,999 bytes big is // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case): - unsigned int sz = GetSerializeSize(tx, SER_NETWORK, CTransaction::CURRENT_VERSION); + unsigned int sz = GetSerializeSize(*tx, SER_NETWORK, CTransaction::CURRENT_VERSION); if (sz > MAX_STANDARD_TX_SIZE) { LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); @@ -549,7 +549,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c auto ret = mapOrphanTransactions.emplace(hash, COrphanTx{tx, peer, GetTime() + ORPHAN_TX_EXPIRE_TIME}); assert(ret.second); - BOOST_FOREACH(const CTxIn& txin, tx.vin) { + BOOST_FOREACH(const CTxIn& txin, tx->vin) { mapOrphanTransactionsByPrev[txin.prevout].insert(ret.first); } @@ -563,7 +563,7 @@ int EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) map::iterator it = mapOrphanTransactions.find(hash); if (it == mapOrphanTransactions.end()) return 0; - BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) + BOOST_FOREACH(const CTxIn& txin, it->second.tx->vin) { auto itPrev = mapOrphanTransactionsByPrev.find(txin.prevout); if (itPrev == mapOrphanTransactionsByPrev.end()) @@ -585,7 +585,7 @@ void EraseOrphansFor(NodeId peer) map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid if (maybeErase->second.fromPeer == peer) { - nErased += EraseOrphanTx(maybeErase->second.tx.GetHash()); + nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); } } if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); @@ -606,7 +606,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE { map::iterator maybeErase = iter++; if (maybeErase->second.nTimeExpire <= nNow) { - nErased += EraseOrphanTx(maybeErase->second.tx.GetHash()); + nErased += EraseOrphanTx(maybeErase->second.tx->GetHash()); } else { nMinExpTime = std::min(maybeErase->second.nTimeExpire, nMinExpTime); } @@ -677,7 +677,7 @@ void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIn auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout); if (itByPrev == mapOrphanTransactionsByPrev.end()) continue; for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) { - const CTransaction& orphanTx = (*mi)->second.tx; + const CTransaction& orphanTx = *(*mi)->second.tx; const uint256& orphanHash = orphanTx.GetHash(); vOrphanErase.push_back(orphanHash); } @@ -1126,7 +1126,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); - if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) + if (IsArgSet("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 0)) == 0) { LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); return true; @@ -1612,23 +1612,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, deque vWorkQueue; vector vEraseQueue; - CMutableTransaction tx; + CTransactionRef ptx; CTxLockRequest txLockRequest; CDarksendBroadcastTx dstx; int nInvType = MSG_TX; // Read data and assign inv type if(strCommand == NetMsgType::TX) { - vRecv >> tx; + vRecv >> ptx; } else if(strCommand == NetMsgType::TXLOCKREQUEST) { vRecv >> txLockRequest; - tx = *txLockRequest.tx; + ptx = txLockRequest.tx; nInvType = MSG_TXLOCK_REQUEST; } else if (strCommand == NetMsgType::DSTX) { vRecv >> dstx; - tx = *dstx.tx; + ptx = dstx.tx; nInvType = MSG_DSTX; } + const CTransaction& tx = *ptx; CInv inv(nInvType, tx.GetHash()); pfrom->AddInventoryKnown(inv); @@ -1678,7 +1679,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapAlreadyAskedFor.erase(inv.hash); - if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, ptx, true, &fMissingInputs)) { // Process custom txes, this changes AlreadyHave to "true" if (strCommand == NetMsgType::DSTX) { LogPrintf("DSTX -- Masternode transaction accepted, txid=%s, peer=%d\n", @@ -1715,7 +1716,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mi != itByPrev->second.end(); ++mi) { - const CTransaction& orphanTx = (*mi)->second.tx; + const CTransactionRef& porphanTx = (*mi)->second.tx; + const CTransaction& orphanTx = *porphanTx; const uint256& orphanHash = orphanTx.GetHash(); NodeId fromPeer = (*mi)->second.fromPeer; bool fMissingInputs2 = false; @@ -1727,7 +1729,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (setMisbehaving.count(fromPeer)) continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) + if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, true, &fMissingInputs2)) { LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); connman.RelayTransaction(orphanTx); @@ -1775,7 +1777,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->AddInventoryKnown(_inv); if (!AlreadyHave(_inv)) pfrom->AskFor(_inv); } - AddOrphanTx(tx, pfrom->GetId()); + AddOrphanTx(ptx, pfrom->GetId()); // DoS prevention: do not allow mapOrphanTransactions to grow unbounded unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); @@ -2011,7 +2013,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapBlockSource.emplace(hash, pfrom->GetId()); } bool fNewBlock = false; - ProcessNewBlock(chainparams, pblock, forceProcessing, NULL, &fNewBlock); + ProcessNewBlock(chainparams, pblock, forceProcessing, &fNewBlock); if (fNewBlock) pfrom->nLastBlockTime = GetTime(); } @@ -2490,6 +2492,8 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg state.fShouldBan = false; if (pto->fWhitelisted) LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString()); + else if (pto->fAddnode) + LogPrintf("Warning: not punishing addnoded peer %s!\n", pto->addr.ToString()); else { pto->fDisconnect = true; if (pto->addr.IsLocal()) @@ -2952,6 +2956,9 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic& interruptMsg int64_t timeNow = GetTimeMicros(); if (timeNow > pto->nextSendTimeFeeFilter) { CAmount filterToSend = filterRounder.round(currentFilter); + // If we don't allow free transactions, then we always have a fee filter of at least minRelayTxFee + if (GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0) + filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); if (filterToSend != pto->lastSentFeeFilter) { connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); pto->lastSentFeeFilter = filterToSend; diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 2824f95ee7f8..34835c803a62 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -281,23 +281,27 @@ void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHe } } -void CBlockPolicyEstimator::removeTx(uint256 hash) +// This function is called from CTxMemPool::removeUnchecked to ensure +// txs removed from the mempool for any reason are no longer +// tracked. Txs that were part of a block have already been removed in +// processBlockTx to ensure they are never double tracked, but it is +// of no harm to try to remove them again. +bool CBlockPolicyEstimator::removeTx(uint256 hash) { std::map::iterator pos = mapMemPoolTxs.find(hash); - if (pos == mapMemPoolTxs.end()) { - LogPrint("estimatefee", "Blockpolicy error mempool tx %s not found for removeTx\n", hash.ToString()); - return; + if (pos != mapMemPoolTxs.end()) { + feeStats.removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex); + mapMemPoolTxs.erase(hash); + return true; + } else { + return false; } - unsigned int entryHeight = pos->second.blockHeight; - unsigned int bucketIndex = pos->second.bucketIndex; - - feeStats.removeTx(entryHeight, nBestSeenHeight, bucketIndex); - mapMemPoolTxs.erase(hash); } CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee) - : nBestSeenHeight(0) + : nBestSeenHeight(0), trackedTxs(0), untrackedTxs(0) { + static_assert(MIN_FEERATE > 0, "Min feerate must be nonzero"); minTrackedFee = _minRelayFee < CFeeRate(MIN_FEERATE) ? CFeeRate(MIN_FEERATE) : _minRelayFee; std::vector vfeelist; for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) { @@ -307,7 +311,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee) feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY); } -void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate) +void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate) { unsigned int txHeight = entry.GetHeight(); uint256 hash = entry.GetTx().GetHash(); @@ -316,23 +320,21 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo return; } - if (txHeight < nBestSeenHeight) { + if (txHeight != nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random they don't // affect the estimate. We'll potentially double count transactions in 1-block reorgs. + // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip(). + // It will be synced next time a block is processed. return; } // Only want to be updating estimates when our blockchain is synced, // otherwise we'll miscalculate how many blocks its taking to get included. - if (!fCurrentEstimate) - return; - - if (!entry.WasClearAtEntry()) { - // This transaction depends on other transactions in the mempool to - // be included in a block before it will be able to be included, so - // we shouldn't include it in our calculations + if (!validFeeEstimate) { + untrackedTxs++; return; } + trackedTxs++; // Feerates are stored and reported as BTC-per-kb: CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); @@ -341,34 +343,33 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK()); } -void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry) +bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) { - if (!entry.WasClearAtEntry()) { - // This transaction depended on other transactions in the mempool to - // be included in a block before it was able to be included, so - // we shouldn't include it in our calculations - return; + if (!removeTx(entry->GetTx().GetHash())) { + // This transaction wasn't being tracked for fee estimation + return false; } // How many blocks did it take for miners to include this transaction? // blocksToConfirm is 1-based, so a transaction included in the earliest // possible block has confirmation count of 1 - int blocksToConfirm = nBlockHeight - entry.GetHeight(); + int blocksToConfirm = nBlockHeight - entry->GetHeight(); if (blocksToConfirm <= 0) { // This can't happen because we don't process transactions from a block with a height // lower than our greatest seen height LogPrint("estimatefee", "Blockpolicy error Transaction had negative blocksToConfirm\n"); - return; + return false; } // Feerates are stored and reported as BTC-per-kb: - CFeeRate feeRate(entry.GetFee(), entry.GetTxSize()); + CFeeRate feeRate(entry->GetFee(), entry->GetTxSize()); feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK()); + return true; } void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, - std::vector& entries, bool fCurrentEstimate) + std::vector& entries) { if (nBlockHeight <= nBestSeenHeight) { // Ignore side chains and re-orgs; assuming they are random @@ -378,25 +379,30 @@ void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight, // transaction fees." return; } - nBestSeenHeight = nBlockHeight; - // Only want to be updating estimates when our blockchain is synced, - // otherwise we'll miscalculate how many blocks its taking to get included. - if (!fCurrentEstimate) - return; + // Must update nBestSeenHeight in sync with ClearCurrent so that + // calls to removeTx (via processBlockTx) correctly calculate age + // of unconfirmed txs to remove from tracking. + nBestSeenHeight = nBlockHeight; - // Clear the current block state + // Clear the current block state and update unconfirmed circular buffer feeStats.ClearCurrent(nBlockHeight); + unsigned int countedTxs = 0; // Repopulate the current block states - for (unsigned int i = 0; i < entries.size(); i++) - processBlockTx(nBlockHeight, entries[i]); + for (unsigned int i = 0; i < entries.size(); i++) { + if (processBlockTx(nBlockHeight, entries[i])) + countedTxs++; + } // Update all exponential averages with the current block state feeStats.UpdateMovingAverages(); - LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n", - entries.size(), mapMemPoolTxs.size()); + LogPrint("estimatefee", "Blockpolicy after updating estimates for %u of %u txs in block, since last block %u of %u tracked, new mempool map size %u\n", + countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size()); + + trackedTxs = 0; + untrackedTxs = 0; } CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) @@ -483,7 +489,7 @@ void CBlockPolicyEstimator::Read(CAutoFile& filein, int nFileVersion) FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee) { - CAmount minFeeLimit = minIncrementalFee.GetFeePerK() / 2; + CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2); feeset.insert(0); for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) { feeset.insert(bucketBoundary); diff --git a/src/policy/fees.h b/src/policy/fees.h index 690982af9c84..26cfd9465905 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -179,7 +179,7 @@ static const double MIN_SUCCESS_PCT = .95; static const double SUFFICIENT_FEETXS = 1; // Minimum and Maximum values for tracking feerates -static const double MIN_FEERATE = 10; +static constexpr double MIN_FEERATE = 10; static const double MAX_FEERATE = 1e7; static const double INF_FEERATE = MAX_MONEY; static const double INF_PRIORITY = 1e9 * MAX_MONEY; @@ -203,16 +203,16 @@ class CBlockPolicyEstimator /** Process all the transactions that have been included in a block */ void processBlock(unsigned int nBlockHeight, - std::vector& entries, bool fCurrentEstimate); + std::vector& entries); /** Process a transaction confirmed in a block*/ - void processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry); + bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry); /** Process a transaction accepted to the mempool*/ - void processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate); + void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate); /** Remove a transaction from the mempool tracking stats*/ - void removeTx(uint256 hash); + bool removeTx(uint256 hash); /** Return a feerate estimate */ CFeeRate estimateFee(int confTarget); @@ -258,6 +258,9 @@ class CBlockPolicyEstimator /** Classes to track historical data on transaction confirmations */ TxConfirmStats feeStats; + + unsigned int trackedTxs; + unsigned int untrackedTxs; }; class FeeFilterRounder diff --git a/src/prevector.h b/src/prevector.h index 25bce522dc9b..46af80d1e60d 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -248,6 +248,10 @@ class prevector { } } + prevector(prevector&& other) : _size(0) { + swap(other); + } + prevector& operator=(const prevector& other) { if (&other == this) { return *this; @@ -263,6 +267,11 @@ class prevector { return *this; } + prevector& operator=(prevector&& other) { + swap(other); + return *this; + } + size_type size() const { return is_direct() ? _size : _size - N - 1; } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 397e380571e9..a243e4d1879d 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -346,8 +346,6 @@ struct CMutableTransaction typedef std::shared_ptr CTransactionRef; static inline CTransactionRef MakeTransactionRef() { return std::make_shared(); } template static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared(std::forward(txIn)); } -static inline CTransactionRef MakeTransactionRef(const CTransactionRef& txIn) { return txIn; } -static inline CTransactionRef MakeTransactionRef(CTransactionRef&& txIn) { return std::move(txIn); } /** Implementation of BIP69 * https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index f0a2c05cf86f..4bc0b8348e4c 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -420,7 +420,7 @@ bool CPrivateSendClient::SendDenominate(const std::vector& vecTxDSIn, c mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN); TRY_LOCK(cs_main, lockMain); - if(!lockMain || !AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, maxTxFee, true)) { + if(!lockMain || !AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(tx), false, NULL, false, maxTxFee, true)) { LogPrintf("CPrivateSendClient::SendDenominate -- AcceptToMemoryPool() failed! tx=%s", tx.ToString()); UnlockCoins(); keyHolderStorage.ReturnAll(); diff --git a/src/privatesend-server.cpp b/src/privatesend-server.cpp index 52a379669c05..1b12bf201c01 100644 --- a/src/privatesend-server.cpp +++ b/src/privatesend-server.cpp @@ -217,7 +217,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C LOCK(cs_main); CValidationState validationState; mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN); - if(!AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, maxTxFee, true)) { + if(!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(tx), false, NULL, false, maxTxFee, true)) { LogPrintf("DSVIN -- transaction not valid! tx=%s", tx.ToString()); PushStatus(pfrom, STATUS_REJECTED, ERR_INVALID_TX, connman); return; @@ -334,10 +334,10 @@ void CPrivateSendServer::CommitFinalTransaction(CConnman& connman) { if(!fMasterNode) return; // check and relay final tx only on masternode - CTransaction finalTransaction = CTransaction(finalMutableTransaction); - uint256 hashTx = finalTransaction.GetHash(); + CTransactionRef finalTransaction = MakeTransactionRef(finalMutableTransaction); + uint256 hashTx = finalTransaction->GetHash(); - LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction.ToString()); + LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction->ToString()); { // See if the transaction is valid @@ -447,7 +447,7 @@ void CPrivateSendServer::ChargeFees(CConnman& connman) CValidationState state; bool fMissingInputs; - if(!AcceptToMemoryPool(mempool, state, *vecOffendersCollaterals[0], false, &fMissingInputs, false, maxTxFee)) { + if(!AcceptToMemoryPool(mempool, state, vecOffendersCollaterals[0], false, &fMissingInputs, false, maxTxFee)) { // should never really happen LogPrintf("CPrivateSendServer::ChargeFees -- ERROR: AcceptToMemoryPool failed!\n"); } else { @@ -482,7 +482,7 @@ void CPrivateSendServer::ChargeRandomFees(CConnman& connman) CValidationState state; bool fMissingInputs; - if(!AcceptToMemoryPool(mempool, state, *txCollateral, false, &fMissingInputs, false, maxTxFee)) { + if(!AcceptToMemoryPool(mempool, state, txCollateral, false, &fMissingInputs, false, maxTxFee)) { // should never really happen LogPrintf("CPrivateSendServer::ChargeRandomFees -- ERROR: AcceptToMemoryPool failed!\n"); } else { diff --git a/src/privatesend.cpp b/src/privatesend.cpp index 755f2fb55a85..845cfc6610ba 100644 --- a/src/privatesend.cpp +++ b/src/privatesend.cpp @@ -216,7 +216,7 @@ bool CPrivateSend::IsCollateralValid(const CTransaction& txCollateral) { LOCK(cs_main); CValidationState validationState; - if(!AcceptToMemoryPool(mempool, validationState, txCollateral, false, NULL, false, maxTxFee, true)) { + if(!AcceptToMemoryPool(mempool, validationState, MakeTransactionRef(txCollateral), false, NULL, false, maxTxFee, true)) { LogPrint("privatesend", "CPrivateSend::IsCollateralValid -- didn't pass AcceptToMemoryPool()\n"); return false; } diff --git a/src/privatesend.h b/src/privatesend.h index dff95935b14a..37a413c44935 100644 --- a/src/privatesend.h +++ b/src/privatesend.h @@ -229,9 +229,9 @@ class CDarksendBroadcastTx sigTime(0) {} - CDarksendBroadcastTx(const CTransaction& _tx, COutPoint _outpoint, int64_t _sigTime) : + CDarksendBroadcastTx(const CTransactionRef& _tx, COutPoint _outpoint, int64_t _sigTime) : nConfirmedHeight(-1), - tx(MakeTransactionRef(_tx)), + tx(_tx), vin(CTxIn(_outpoint)), vchSig(), sigTime(_sigTime) diff --git a/src/qt/dash.cpp b/src/qt/dash.cpp index 74de41ebd008..9166ea0704c8 100644 --- a/src/qt/dash.cpp +++ b/src/qt/dash.cpp @@ -33,6 +33,7 @@ #include "scheduler.h" #include "ui_interface.h" #include "util.h" +#include "warnings.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" @@ -269,7 +270,7 @@ BitcoinCore::BitcoinCore(): void BitcoinCore::handleRunawayException(const std::exception *e) { PrintExceptionContinue(e, "Runaway exception"); - Q_EMIT runawayException(QString::fromStdString(strMiscWarning)); + Q_EMIT runawayException(QString::fromStdString(GetWarnings("gui"))); } void BitcoinCore::initialize() @@ -485,6 +486,8 @@ void BitcoinApplication::requestShutdown() delete clientModel; clientModel = 0; + StartShutdown(); + // Request shutdown from core thread Q_EMIT requestedShutdown(); } @@ -629,9 +632,9 @@ int main(int argc, char *argv[]) // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. - if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version")) + if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version")) { - HelpMessageDialog help(NULL, mapArgs.count("-version") ? HelpMessageDialog::about : HelpMessageDialog::cmdline); + HelpMessageDialog help(NULL, IsArgSet("-version") ? HelpMessageDialog::about : HelpMessageDialog::cmdline); help.showOrPrint(); return EXIT_SUCCESS; } @@ -646,11 +649,11 @@ int main(int argc, char *argv[]) if (!boost::filesystem::is_directory(GetDataDir(false))) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), - QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); + QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(GetArg("-datadir", "")))); return EXIT_FAILURE; } try { - ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME), mapArgs, mapMultiArgs); + ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)); } catch (const std::exception& e) { QMessageBox::critical(0, QObject::tr(PACKAGE_NAME), QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what())); @@ -722,7 +725,7 @@ int main(int argc, char *argv[]) // Allow parameter interaction before we create the options model app.parameterSetup(); // Load GUI settings from QSettings - app.createOptionsModel(mapArgs.count("-resetguisettings") != 0); + app.createOptionsModel(IsArgSet("-resetguisettings")); // Subscribe to global signals from core uiInterface.InitMessage.connect(InitMessage); @@ -742,10 +745,10 @@ int main(int argc, char *argv[]) app.exec(); } catch (const std::exception& e) { PrintExceptionContinue(&e, "Runaway exception"); - app.handleRunawayException(QString::fromStdString(strMiscWarning)); + app.handleRunawayException(QString::fromStdString(GetWarnings("gui"))); } catch (...) { PrintExceptionContinue(NULL, "Runaway exception"); - app.handleRunawayException(QString::fromStdString(strMiscWarning)); + app.handleRunawayException(QString::fromStdString(GetWarnings("gui"))); } return app.getReturnValue(); } diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui index d86920cf878b..85dff29599a0 100644 --- a/src/qt/forms/modaloverlay.ui +++ b/src/qt/forms/modaloverlay.ui @@ -265,7 +265,7 @@ - ~ + ~ diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index ddc4954b458b..26d7f36a1497 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -1111,7 +1111,7 @@ - (count) + (count) diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index df887eba4b73..4fed7ea20f85 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -39,7 +39,7 @@ OptionsModel::OptionsModel(QObject *parent, bool resetSettings) : void OptionsModel::addOverriddenOption(const std::string &option) { - strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(mapArgs[option]) + " "; + strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(GetArg(option, "")) + " "; } // Writes all missing QSettings with their default values @@ -572,4 +572,4 @@ void OptionsModel::checkAndMigrate() settings.setValue(strSettingsVersionKey, CLIENT_VERSION); } -} \ No newline at end of file +} diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index 39484f02e500..523000144551 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -159,7 +159,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c std::string data_to_verify; // Everything but the signature rcopy.SerializeToString(&data_to_verify); -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if HAVE_DECL_EVP_MD_CTX_NEW EVP_MD_CTX *ctx = EVP_MD_CTX_new(); if (!ctx) throw SSLVerifyError("Error allocating OpenSSL context."); #else @@ -177,7 +177,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c throw SSLVerifyError("Bad signature, invalid payment request."); } -#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#if HAVE_DECL_EVP_MD_CTX_NEW EVP_MD_CTX_free(ctx); #endif diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index a30e4eed2f02..8fa6ad28627c 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,20 @@ const struct { {NULL, NULL} }; +namespace { + +// don't add private key handling cmd's to the history +const QStringList historyFilter = QStringList() + << "importprivkey" + << "importmulti" + << "signmessagewithprivkey" + << "signrawtransaction" + << "walletpassphrase" + << "walletpassphrasechange" + << "encryptwallet"; + +} + /* Object for executing console RPC commands in a separate thread. */ class RPCExecutor : public QObject @@ -123,10 +138,10 @@ class QtRPCTimerInterface: public RPCTimerInterface #include "rpcconsole.moc" /** - * Split shell command line into a list of arguments and execute the command(s). + * Split shell command line into a list of arguments and optionally execute the command(s). * Aims to emulate \c bash and friends. * - * - Command nesting is possible with brackets [example: validateaddress(getnewaddress())] + * - Command nesting is possible with parenthesis; for example: validateaddress(getnewaddress()) * - Arguments are delimited with whitespace or comma * - Extra whitespace at the beginning and end and between arguments will be ignored * - Text can be "double" or 'single' quoted @@ -137,9 +152,11 @@ class QtRPCTimerInterface: public RPCTimerInterface * * @param[out] result stringified Result from the executed command(chain) * @param[in] strCommand Command line to split + * @param[in] fExecute set true if you want the command to be executed + * @param[out] pstrFilteredOut Command line, filtered to remove any sensitive data */ -bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand) +bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string &strCommand, const bool fExecute, std::string * const pstrFilteredOut) { std::vector< std::vector > stack; stack.push_back(std::vector()); @@ -147,6 +164,8 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string enum CmdParseState { STATE_EATING_SPACES, + STATE_EATING_SPACES_IN_ARG, + STATE_EATING_SPACES_IN_BRACKETS, STATE_ARGUMENT, STATE_SINGLEQUOTED, STATE_DOUBLEQUOTED, @@ -157,12 +176,35 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string } state = STATE_EATING_SPACES; std::string curarg; UniValue lastResult; + unsigned nDepthInsideSensitive = 0; + size_t filter_begin_pos = 0, chpos; + std::vector> filter_ranges; + + auto add_to_current_stack = [&](const std::string& strArg) { + if (stack.back().empty() && (!nDepthInsideSensitive) && historyFilter.contains(QString::fromStdString(strArg), Qt::CaseInsensitive)) { + nDepthInsideSensitive = 1; + filter_begin_pos = chpos; + } + stack.back().push_back(strArg); + }; + + auto close_out_params = [&]() { + if (nDepthInsideSensitive) { + if (!--nDepthInsideSensitive) { + assert(filter_begin_pos); + filter_ranges.push_back(std::make_pair(filter_begin_pos, chpos)); + filter_begin_pos = 0; + } + } + stack.pop_back(); + }; std::string strCommandTerminated = strCommand; if (strCommandTerminated.back() != '\n') strCommandTerminated += "\n"; - for(char ch: strCommandTerminated) + for (chpos = 0; chpos < strCommandTerminated.size(); ++chpos) { + char ch = strCommandTerminated[chpos]; switch(state) { case STATE_COMMAND_EXECUTED_INNER: @@ -181,7 +223,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string curarg += ch; break; } - if (curarg.size()) + if (curarg.size() && fExecute) { // if we have a value query, query arrays with index and objects with a string key UniValue subelement; @@ -206,7 +248,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string breakParsing = false; // pop the stack and return the result to the current command arguments - stack.pop_back(); + close_out_params(); // don't stringify the json in case of a string to avoid doublequotes if (lastResult.isStr()) @@ -218,7 +260,7 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string if (curarg.size()) { if (stack.size()) - stack.back().push_back(curarg); + add_to_current_stack(curarg); else strResult = curarg; } @@ -230,6 +272,8 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string break; } case STATE_ARGUMENT: // In or after argument + case STATE_EATING_SPACES_IN_ARG: + case STATE_EATING_SPACES_IN_BRACKETS: case STATE_EATING_SPACES: // Handle runs of whitespace switch(ch) { @@ -237,41 +281,55 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string case '\'': state = STATE_SINGLEQUOTED; break; case '\\': state = STATE_ESCAPE_OUTER; break; case '(': case ')': case '\n': + if (state == STATE_EATING_SPACES_IN_ARG) + throw std::runtime_error("Invalid Syntax"); if (state == STATE_ARGUMENT) { if (ch == '(' && stack.size() && stack.back().size() > 0) - stack.push_back(std::vector()); - if (curarg.size()) { - // don't allow commands after executed commands on baselevel - if (!stack.size()) - throw std::runtime_error("Invalid Syntax"); - stack.back().push_back(curarg); + if (nDepthInsideSensitive) { + ++nDepthInsideSensitive; + } + stack.push_back(std::vector()); } + + // don't allow commands after executed commands on baselevel + if (!stack.size()) + throw std::runtime_error("Invalid Syntax"); + + add_to_current_stack(curarg); curarg.clear(); - state = STATE_EATING_SPACES; + state = STATE_EATING_SPACES_IN_BRACKETS; } if ((ch == ')' || ch == '\n') && stack.size() > 0) { - std::string strPrint; - // Convert argument list to JSON objects in method-dependent way, - // and pass it along with the method name to the dispatcher. - JSONRPCRequest req; - req.params = RPCConvertValues(stack.back()[0], std::vector(stack.back().begin() + 1, stack.back().end())); - req.strMethod = stack.back()[0]; - lastResult = tableRPC.execute(req); + if (fExecute) { + // Convert argument list to JSON objects in method-dependent way, + // and pass it along with the method name to the dispatcher. + JSONRPCRequest req; + req.params = RPCConvertValues(stack.back()[0], std::vector(stack.back().begin() + 1, stack.back().end())); + req.strMethod = stack.back()[0]; + lastResult = tableRPC.execute(req); + } state = STATE_COMMAND_EXECUTED; curarg.clear(); } break; case ' ': case ',': case '\t': - if(state == STATE_ARGUMENT) // Space ends argument + if(state == STATE_EATING_SPACES_IN_ARG && curarg.empty() && ch == ',') + throw std::runtime_error("Invalid Syntax"); + + else if(state == STATE_ARGUMENT) // Space ends argument { - if (curarg.size()) - stack.back().push_back(curarg); + add_to_current_stack(curarg); curarg.clear(); } + if ((state == STATE_EATING_SPACES_IN_BRACKETS || state == STATE_ARGUMENT) && ch == ',') + { + state = STATE_EATING_SPACES_IN_ARG; + break; + } state = STATE_EATING_SPACES; break; default: curarg += ch; state = STATE_ARGUMENT; @@ -301,6 +359,16 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string break; } } + if (pstrFilteredOut) { + if (STATE_COMMAND_EXECUTED == state) { + assert(!stack.empty()); + close_out_params(); + } + *pstrFilteredOut = strCommand; + for (auto i = filter_ranges.rbegin(); i != filter_ranges.rend(); ++i) { + pstrFilteredOut->replace(i->first, i->second - i->first, "(…)"); + } + } switch(state) // final state { case STATE_COMMAND_EXECUTED: @@ -829,12 +897,30 @@ void RPCConsole::setMempoolSize(long numberOfTxs, size_t dynUsage) void RPCConsole::on_lineEdit_returnPressed() { QString cmd = ui->lineEdit->text(); - ui->lineEdit->clear(); if(!cmd.isEmpty()) { + std::string strFilteredCmd; + try { + std::string dummy; + if (!RPCParseCommandLine(dummy, cmd.toStdString(), false, &strFilteredCmd)) { + // Failed to parse command, so we cannot even filter it for the history + throw std::runtime_error("Invalid command line"); + } + } catch (const std::exception& e) { + QMessageBox::critical(this, "Error", QString("Error: ") + QString::fromStdString(e.what())); + return; + } + + ui->lineEdit->clear(); + + cmdBeforeBrowsing = QString(); + message(CMD_REQUEST, cmd); Q_EMIT cmdRequest(cmd); + + cmd = QString::fromStdString(strFilteredCmd); + // Remove command, if already in history history.removeOne(cmd); // Append command to history @@ -844,6 +930,7 @@ void RPCConsole::on_lineEdit_returnPressed() history.removeFirst(); // Set pointer to end of history historyPtr = history.size(); + // Scroll console view to end scrollToEnd(); } @@ -851,6 +938,11 @@ void RPCConsole::on_lineEdit_returnPressed() void RPCConsole::browseHistory(int offset) { + // store current text when start browsing through the history + if (historyPtr == history.size()) { + cmdBeforeBrowsing = ui->lineEdit->text(); + } + historyPtr += offset; if(historyPtr < 0) historyPtr = 0; @@ -859,6 +951,9 @@ void RPCConsole::browseHistory(int offset) QString cmd; if(historyPtr < history.size()) cmd = history.at(historyPtr); + else if (!cmdBeforeBrowsing.isNull()) { + cmd = cmdBeforeBrowsing; + } ui->lineEdit->setText(cmd); } diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 83e4f7558f57..d31762e03898 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -37,7 +37,10 @@ class RPCConsole: public QWidget explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent); ~RPCConsole(); - static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand); + static bool RPCParseCommandLine(std::string &strResult, const std::string &strCommand, bool fExecute, std::string * const pstrFilteredOut = NULL); + static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand, std::string * const pstrFilteredOut = NULL) { + return RPCParseCommandLine(strResult, strCommand, true, pstrFilteredOut); + } void setClientModel(ClientModel *model); @@ -157,6 +160,7 @@ public Q_SLOTS: ClientModel *clientModel; QStringList history; int historyPtr; + QString cmdBeforeBrowsing; QList cachedNodeids; const PlatformStyle *platformStyle; RPCTimerInterface *rpcTimerInterface; diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 177df2b6427c..aa10af686d36 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -885,6 +885,19 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text) if (!model->havePrivKey(keyid)) // Unknown change address { ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address")); + + // confirmation dialog + QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm custom change address"), tr("The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + + if(btnRetVal == QMessageBox::Yes) + CoinControlDialog::coinControl->destChange = addr.Get(); + else + { + ui->lineEditCoinControlChange->setText(""); + ui->labelCoinControlChangeLabel->setStyleSheet("QLabel{color:black;}"); + ui->labelCoinControlChangeLabel->setText(""); + } } else // Known change address { diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 0aef4b485559..87dbc8ab3a4a 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -56,7 +56,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) splashScreenPath = ":/images/" + GUIUtil::getThemeName() + "/splash_testnet"; if(GetBoolArg("-testnet", false)) splashScreenPath = ":/images/" + GUIUtil::getThemeName() + "/splash_testnet"; - if(mapArgs.count("-devnet")) + if(IsArgSet("-devnet")) splashScreenPath = ":/images/" + GUIUtil::getThemeName() + "/splash_testnet"; QString font = QApplication::font().toString(); diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index c9a155345811..66572979c626 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -15,9 +15,23 @@ #include "util.h" #include +#include #include +static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request) +{ + if (request.fHelp) { + return "help message"; + } + return request.params.write(0, 0); +} + +static const CRPCCommand vRPCCommands[] = +{ + { "test", "rpcNestedTest", &rpcNestedTest_rpc, true }, +}; + void RPCNestedTests::rpcNestedTests() { UniValue jsonRPCError; @@ -26,11 +40,12 @@ void RPCNestedTests::rpcNestedTests() // could be moved to a more generic place when we add more tests on QT level const CChainParams& chainparams = Params(); RegisterAllCoreRPCCommands(tableRPC); + tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); ClearDatadirCache(); std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); QDir dir(QString::fromStdString(path)); dir.mkpath("."); - mapArgs["-datadir"] = path; + ForceSetArg("-datadir", path); //mempool.setSanityCheck(1.0); pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); @@ -46,8 +61,10 @@ void RPCNestedTests::rpcNestedTests() std::string result; std::string result2; - RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]"); //simple result filtering with path + std::string filtered; + RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path QVERIFY(result=="main"); + QVERIFY(filtered == "getblockchaininfo()[chain]"); RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)"); @@ -63,16 +80,6 @@ void RPCNestedTests::rpcNestedTests() RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated QVERIFY(result.substr(0,1) == "{"); -#if QT_VERSION >= 0x050300 - // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax - (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments - (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument - QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found -#endif - (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key QVERIFY(result == "null"); @@ -82,8 +89,64 @@ void RPCNestedTests::rpcNestedTests() (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed QVERIFY(result == result2); - RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]"); + RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered); QVERIFY(result == "e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7"); + QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]"); + + RPCConsole::RPCParseCommandLine(result, "importprivkey", false, &filtered); + QVERIFY(filtered == "importprivkey(…)"); + RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc", false, &filtered); + QVERIFY(filtered == "signmessagewithprivkey(…)"); + RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc,def", false, &filtered); + QVERIFY(filtered == "signmessagewithprivkey(…)"); + RPCConsole::RPCParseCommandLine(result, "signrawtransaction(abc)", false, &filtered); + QVERIFY(filtered == "signrawtransaction(…)"); + RPCConsole::RPCParseCommandLine(result, "walletpassphrase(help())", false, &filtered); + QVERIFY(filtered == "walletpassphrase(…)"); + RPCConsole::RPCParseCommandLine(result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered); + QVERIFY(filtered == "walletpassphrasechange(…)"); + RPCConsole::RPCParseCommandLine(result, "help(encryptwallet(abc, def))", false, &filtered); + QVERIFY(filtered == "help(encryptwallet(…))"); + RPCConsole::RPCParseCommandLine(result, "help(importprivkey())", false, &filtered); + QVERIFY(filtered == "help(importprivkey(…))"); + RPCConsole::RPCParseCommandLine(result, "help(importprivkey(help()))", false, &filtered); + QVERIFY(filtered == "help(importprivkey(…))"); + RPCConsole::RPCParseCommandLine(result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered); + QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))"); + + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest"); + QVERIFY(result == "[]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest ''"); + QVERIFY(result == "[\"\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest \"\""); + QVERIFY(result == "[\"\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest '' abc"); + QVERIFY(result == "[\"\",\"abc\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc '' abc"); + QVERIFY(result == "[\"abc\",\"\",\"abc\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc abc"); + QVERIFY(result == "[\"abc\",\"abc\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc\t\tabc"); + QVERIFY(result == "[\"abc\",\"abc\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc )"); + QVERIFY(result == "[\"abc\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc )"); + QVERIFY(result == "[\"abc\"]"); + RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc , cba )"); + QVERIFY(result == "[\"abc\",\"cba\"]"); + +#if QT_VERSION >= 0x050300 + // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3) + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments + (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , + QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , +#endif delete pcoinsTip; delete pcoinsdbview; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 854cc45d5108..fa61be52c742 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -169,9 +169,9 @@ UniValue getbestblockhash(const JSONRPCRequest& request) throw runtime_error( "getbestblockhash\n" "\nReturns the hash of the best (tip) block in the longest blockchain.\n" - "\nResult\n" + "\nResult:\n" "\"hex\" (string) the block hash hex encoded\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", "") ); @@ -204,7 +204,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request) " \"hash\" : { (string) The blockhash\n" " \"height\" : { (int) Block height\n" "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("waitfornewblock", "1000") + HelpExampleRpc("waitfornewblock", "1000") ); @@ -236,14 +236,14 @@ UniValue waitforblock(const JSONRPCRequest& request) "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n" "\nArguments:\n" - "1. blockhash to wait for (string)\n" - "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + "1. \"blockhash\" (required, string) Block hash to wait for.\n" + "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" "\nResult:\n" "{ (json object)\n" " \"hash\" : { (string) The blockhash\n" " \"height\" : { (int) Block height\n" "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") ); @@ -274,19 +274,19 @@ UniValue waitforblockheight(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( - "waitforblockheight (timeout)\n" + "waitforblockheight (timeout)\n" "\nWaits for (at least) block height and returns the height and hash\n" "of the current tip.\n" "\nReturns the current block on timeout or exit.\n" "\nArguments:\n" - "1. block height to wait for (int)\n" + "1. height (required, int) Block height to wait for (int)\n" "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" "\nResult:\n" "{ (json object)\n" " \"hash\" : { (string) The blockhash\n" " \"height\" : { (int) Block height\n" "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("waitforblockheight", "\"100\", 1000") + HelpExampleRpc("waitforblockheight", "\"100\", 1000") ); @@ -418,7 +418,7 @@ UniValue getrawmempool(const JSONRPCRequest& request) "getrawmempool ( verbose )\n" "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nArguments:\n" - "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult: (for verbose = false):\n" "[ (json array of string)\n" " \"transactionid\" (string) The transaction id\n" @@ -430,7 +430,7 @@ UniValue getrawmempool(const JSONRPCRequest& request) + EntryDescriptionString() + " }, ...\n" "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true") ); @@ -449,8 +449,8 @@ UniValue getmempoolancestors(const JSONRPCRequest& request) "getmempoolancestors txid (verbose)\n" "\nIf txid is in the mempool, returns all in-mempool ancestors.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" - "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult (for verbose=false):\n" "[ (json array of strings)\n" " \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n" @@ -462,7 +462,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request) + EntryDescriptionString() + " }, ...\n" "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("getmempoolancestors", "\"mytxid\"") + HelpExampleRpc("getmempoolancestors", "\"mytxid\"") ); @@ -513,8 +513,8 @@ UniValue getmempooldescendants(const JSONRPCRequest& request) "getmempooldescendants txid (verbose)\n" "\nIf txid is in the mempool, returns all in-mempool descendants.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" - "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult (for verbose=false):\n" "[ (json array of strings)\n" " \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n" @@ -526,7 +526,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request) + EntryDescriptionString() + " }, ...\n" "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("getmempooldescendants", "\"mytxid\"") + HelpExampleRpc("getmempooldescendants", "\"mytxid\"") ); @@ -582,7 +582,7 @@ UniValue getmempoolentry(const JSONRPCRequest& request) "{ (json object)\n" + EntryDescriptionString() + "}\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("getmempoolentry", "\"mytxid\"") + HelpExampleRpc("getmempoolentry", "\"mytxid\"") ); @@ -641,10 +641,10 @@ UniValue getblockhash(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "getblockhash index\n" - "\nReturns hash of block in best-block-chain at index provided.\n" + "getblockhash height\n" + "\nReturns hash of block in best-block-chain at height provided.\n" "\nArguments:\n" - "1. index (numeric, required) The block index\n" + "1. height (numeric, required) The height index\n" "\nResult:\n" "\"hash\" (string) The block hash\n" "\nExamples:\n" @@ -814,12 +814,12 @@ UniValue getblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( - "getblock \"hash\" ( verbose )\n" + "getblock \"blockhash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbose is true, returns an Object with information about block .\n" "\nArguments:\n" - "1. \"hash\" (string, required) The block hash\n" - "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" + "1. \"blockhash\" (string, required) The block hash\n" + "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" @@ -992,12 +992,12 @@ UniValue gettxout(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) throw runtime_error( - "gettxout \"txid\" n ( includemempool )\n" + "gettxout \"txid\" n ( include_mempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "2. n (numeric, required) vout number\n" - "3. includemempool (boolean, optional) Whether to include the mempool\n" + "3. include_mempool (boolean, optional) Whether to include the mempool\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" @@ -1009,7 +1009,7 @@ UniValue gettxout(const JSONRPCRequest& request) " \"reqSigs\" : n, (numeric) Number of required signatures\n" " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n" " \"addresses\" : [ (array of string) array of dash addresses\n" - " \"dashaddress\" (string) dash address\n" + " \"address\" (string) dash address\n" " ,...\n" " ]\n" " },\n" @@ -1074,11 +1074,11 @@ UniValue verifychain(const JSONRPCRequest& request) int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS); if (request.fHelp || request.params.size() > 2) throw runtime_error( - "verifychain ( checklevel numblocks )\n" + "verifychain ( checklevel nblocks )\n" "\nVerifies blockchain database.\n" "\nArguments:\n" "1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n" - "2. numblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n" + "2. nblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n" "\nResult:\n" "true|false (boolean) Verified or not\n" "\nExamples:\n" @@ -1416,12 +1416,12 @@ UniValue preciousblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "preciousblock \"hash\"\n" + "preciousblock \"blockhash\"\n" "\nTreats a block as if it were received before others with the same work.\n" "\nA later preciousblock call can override the effect of an earlier one.\n" "\nThe effects of preciousblock are not retained across restarts.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as precious\n" + "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("preciousblock", "\"blockhash\"") @@ -1454,10 +1454,10 @@ UniValue invalidateblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "invalidateblock \"hash\"\n" + "invalidateblock \"blockhash\"\n" "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as invalid\n" + "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("invalidateblock", "\"blockhash\"") @@ -1492,11 +1492,11 @@ UniValue reconsiderblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "reconsiderblock \"hash\"\n" + "reconsiderblock \"blockhash\"\n" "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to reconsider\n" + "1. \"blockhash\" (string, required) the hash of the block to reconsider\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("reconsiderblock", "\"blockhash\"") @@ -1526,35 +1526,35 @@ UniValue reconsiderblock(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // --------------------- ------------------------ ----------------------- ---------- - { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, - { "blockchain", "getbestblockhash", &getbestblockhash, true }, - { "blockchain", "getblockcount", &getblockcount, true }, - { "blockchain", "getblock", &getblock, true }, - { "blockchain", "getblockhashes", &getblockhashes, true }, - { "blockchain", "getblockhash", &getblockhash, true }, - { "blockchain", "getblockheader", &getblockheader, true }, - { "blockchain", "getblockheaders", &getblockheaders, true }, - { "blockchain", "getchaintips", &getchaintips, true }, - { "blockchain", "getdifficulty", &getdifficulty, true }, - { "blockchain", "getmempoolancestors", &getmempoolancestors, true }, - { "blockchain", "getmempooldescendants", &getmempooldescendants, true }, - { "blockchain", "getmempoolentry", &getmempoolentry, true }, - { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, - { "blockchain", "getrawmempool", &getrawmempool, true }, - { "blockchain", "gettxout", &gettxout, true }, - { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, - { "blockchain", "verifychain", &verifychain, true }, - - { "blockchain", "preciousblock", &preciousblock, true }, +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ ---------- + { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} }, + { "blockchain", "getbestblockhash", &getbestblockhash, true, {} }, + { "blockchain", "getblockcount", &getblockcount, true, {} }, + { "blockchain", "getblock", &getblock, true, {"blockhash","verbose"} }, + { "blockchain", "getblockhashes", &getblockhashes, true, {"high","low"} }, + { "blockchain", "getblockhash", &getblockhash, true, {"height"} }, + { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} }, + { "blockchain", "getblockheaders", &getblockheaders, true, {"blockhash","count","verbose"} }, + { "blockchain", "getchaintips", &getchaintips, true, {"count","branchlen"} }, + { "blockchain", "getdifficulty", &getdifficulty, true, {} }, + { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} }, + { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} }, + { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} }, + { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} }, + { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} }, + { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} }, + { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} }, + + { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} }, /* Not shown in help */ - { "hidden", "invalidateblock", &invalidateblock, true }, - { "hidden", "reconsiderblock", &reconsiderblock, true }, - { "hidden", "waitfornewblock", &waitfornewblock, true }, - { "hidden", "waitforblock", &waitforblock, true }, - { "hidden", "waitforblockheight", &waitforblockheight, true }, + { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} }, + { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} }, + { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} }, + { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} }, + { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} }, }; void RegisterBlockchainRPCCommands(CRPCTable &t) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index dad90937f27e..512bd057b6d0 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -21,136 +21,152 @@ class CRPCConvertParam public: std::string methodName; //!< method whose params want conversion int paramIdx; //!< 0-based idx of param to convert + std::string paramName; //!< parameter name }; +/** + * Specifiy a (method, idx, name) here if the argument is a non-string RPC + * argument and needs to be converted from JSON. + * + * @note Parameter indexes start from 0. + */ static const CRPCConvertParam vRPCConvertParams[] = { - { "stop", 0 }, - { "setmocktime", 0 }, - { "generate", 0 }, - { "generate", 1 }, - { "generatetoaddress", 0 }, - { "generatetoaddress", 2 }, - { "getnetworkhashps", 0 }, - { "getnetworkhashps", 1 }, - { "sendtoaddress", 1 }, - { "sendtoaddress", 4 }, - { "sendtoaddress", 5 }, - { "sendtoaddress", 6 }, - { "instantsendtoaddress", 1 }, - { "instantsendtoaddress", 4 }, - { "settxfee", 0 }, - { "getreceivedbyaddress", 1 }, - { "getreceivedbyaddress", 2 }, - { "getreceivedbyaccount", 1 }, - { "getreceivedbyaccount", 2 }, - { "listreceivedbyaddress", 0 }, - { "listreceivedbyaddress", 1 }, - { "listreceivedbyaddress", 2 }, - { "listreceivedbyaddress", 3 }, - { "listreceivedbyaccount", 0 }, - { "listreceivedbyaccount", 1 }, - { "listreceivedbyaccount", 2 }, - { "listreceivedbyaccount", 3 }, - { "getbalance", 1 }, - { "getbalance", 2 }, - { "getbalance", 3 }, - { "getchaintips", 0 }, - { "getchaintips", 1 }, - { "getblockhash", 0 }, - { "getsuperblockbudget", 0 }, - { "waitforblockheight", 0 }, - { "waitforblockheight", 1 }, - { "waitforblock", 1 }, - { "waitforblock", 2 }, - { "waitfornewblock", 0 }, - { "waitfornewblock", 1 }, - { "move", 2 }, - { "move", 3 }, - { "sendfrom", 2 }, - { "sendfrom", 3 }, - { "sendfrom", 4 }, - { "listtransactions", 1 }, - { "listtransactions", 2 }, - { "listtransactions", 3 }, - { "listaccounts", 0 }, - { "listaccounts", 1 }, - { "listaccounts", 2 }, - { "walletpassphrase", 1 }, - { "walletpassphrase", 2 }, - { "getblocktemplate", 0 }, - { "listsinceblock", 1 }, - { "listsinceblock", 2 }, - { "sendmany", 1 }, - { "sendmany", 2 }, - { "sendmany", 3 }, - { "sendmany", 5 }, - { "sendmany", 6 }, - { "sendmany", 7 }, - { "addmultisigaddress", 0 }, - { "addmultisigaddress", 1 }, - { "createmultisig", 0 }, - { "createmultisig", 1 }, - { "listunspent", 0 }, - { "listunspent", 1 }, - { "listunspent", 2 }, - { "getblock", 1 }, - { "getblockheader", 1 }, - { "getblockheaders", 1 }, - { "getblockheaders", 2 }, - { "gettransaction", 1 }, - { "getrawtransaction", 1 }, - { "createrawtransaction", 0 }, - { "createrawtransaction", 1 }, - { "createrawtransaction", 2 }, - { "signrawtransaction", 1 }, - { "signrawtransaction", 2 }, - { "sendrawtransaction", 1 }, - { "sendrawtransaction", 2 }, - { "fundrawtransaction", 1 }, - { "gettxout", 1 }, - { "gettxout", 2 }, - { "gettxoutproof", 0 }, - { "lockunspent", 0 }, - { "lockunspent", 1 }, - { "importprivkey", 2 }, - { "importelectrumwallet", 1 }, - { "importaddress", 2 }, - { "importaddress", 3 }, - { "importpubkey", 2 }, - { "importmulti", 0 }, - { "importmulti", 1 }, - { "verifychain", 0 }, - { "verifychain", 1 }, - { "keypoolrefill", 0 }, - { "getrawmempool", 0 }, - { "estimatefee", 0 }, - { "estimatepriority", 0 }, - { "estimatesmartfee", 0 }, - { "estimatesmartpriority", 0 }, - { "prioritisetransaction", 1 }, - { "prioritisetransaction", 2 }, - { "setban", 2 }, - { "setban", 3 }, - { "getmempoolancestors", 1 }, - { "getmempooldescendants", 1 }, - { "setnetworkactive", 0 }, - { "spork", 1 }, - { "voteraw", 1 }, - { "voteraw", 5 }, - { "getblockhashes", 0 }, - { "getblockhashes", 1 }, - { "getspentinfo", 0}, - { "getaddresstxids", 0}, - { "getaddressbalance", 0}, - { "getaddressdeltas", 0}, - { "getaddressutxos", 0}, - { "getaddressmempool", 0}, + { "setmocktime", 0, "timestamp" }, + { "generate", 0, "nblocks" }, + { "generate", 1, "maxtries" }, + { "generatetoaddress", 0, "nblocks" }, + { "generatetoaddress", 2, "maxtries" }, + { "getnetworkhashps", 0, "nblocks" }, + { "getnetworkhashps", 1, "height" }, + { "sendtoaddress", 1, "amount" }, + { "sendtoaddress", 4, "subtractfeefromamount" }, + { "sendtoaddress", 5, "use_is" }, + { "sendtoaddress", 6, "use_ps" }, + { "instantsendtoaddress", 1, "address" }, + { "instantsendtoaddress", 4, "comment_to" }, + { "settxfee", 0, "amount" }, + { "getreceivedbyaddress", 1, "minconf" }, + { "getreceivedbyaddress", 2, "addlockconf" }, + { "getreceivedbyaccount", 1, "minconf" }, + { "getreceivedbyaccount", 2, "addlockconf" }, + { "listreceivedbyaddress", 0, "minconf" }, + { "listreceivedbyaddress", 1, "addlockconf" }, + { "listreceivedbyaddress", 2, "include_empty" }, + { "listreceivedbyaddress", 3, "include_watchonly" }, + { "listreceivedbyaccount", 0, "minconf" }, + { "listreceivedbyaccount", 1, "addlockconf" }, + { "listreceivedbyaccount", 2, "include_empty" }, + { "listreceivedbyaccount", 3, "include_watchonly" }, + { "getbalance", 1, "minconf" }, + { "getbalance", 2, "addlockconf" }, + { "getbalance", 3, "include_watchonly" }, + { "getchaintips", 0, "count" }, + { "getchaintips", 1, "branchlen" }, + { "getblockhash", 0, "height" }, + { "getsuperblockbudget", 0, "index" }, + { "waitforblockheight", 0, "height" }, + { "waitforblockheight", 1, "timeout" }, + { "waitforblock", 1, "timeout" }, + { "waitfornewblock", 0, "timeout" }, + { "move", 2, "amount" }, + { "move", 3, "minconf" }, + { "sendfrom", 2, "amount" }, + { "sendfrom", 3, "minconf" }, + { "sendfrom", 4, "addlockconf" }, + { "listtransactions", 1, "count" }, + { "listtransactions", 2, "skip" }, + { "listtransactions", 3, "include_watchonly" }, + { "listaccounts", 0, "minconf" }, + { "listaccounts", 1, "addlockconf" }, + { "listaccounts", 2, "include_watchonly" }, + { "walletpassphrase", 1, "timeout" }, + { "walletpassphrase", 2, "mixingonly" }, + { "getblocktemplate", 0, "template_request" }, + { "listsinceblock", 1, "target_confirmations" }, + { "listsinceblock", 2, "include_watchonly" }, + { "sendmany", 1, "amounts" }, + { "sendmany", 2, "minconf" }, + { "sendmany", 3, "addlockconf" }, + { "sendmany", 5, "subtractfeefromamount" }, + { "sendmany", 6, "use_is" }, + { "sendmany", 7, "use_ps" }, + { "addmultisigaddress", 0, "nrequired" }, + { "addmultisigaddress", 1, "keys" }, + { "createmultisig", 0, "nrequired" }, + { "createmultisig", 1, "keys" }, + { "listunspent", 0, "minconf" }, + { "listunspent", 1, "maxconf" }, + { "listunspent", 2, "addresses" }, + { "getblock", 1, "verbose" }, + { "getblockheader", 1, "verbose" }, + { "getblockheaders", 1, "count" }, + { "getblockheaders", 2, "verbose" }, + { "gettransaction", 1, "include_watchonly" }, + { "getrawtransaction", 1, "verbose" }, + { "createrawtransaction", 0, "transactions" }, + { "createrawtransaction", 1, "outputs" }, + { "createrawtransaction", 2, "locktime" }, + { "signrawtransaction", 1, "prevtxs" }, + { "signrawtransaction", 2, "privkeys" }, + { "sendrawtransaction", 1, "allowhighfees" }, + { "sendrawtransaction", 2, "instantsend" }, + { "fundrawtransaction", 1, "options" }, + { "gettxout", 1, "n" }, + { "gettxout", 2, "include_mempool" }, + { "gettxoutproof", 0, "txids" }, + { "lockunspent", 0, "unlock" }, + { "lockunspent", 1, "transactions" }, + { "importprivkey", 2, "rescan" }, + { "importelectrumwallet", 1, "index" }, + { "importaddress", 2, "rescan" }, + { "importaddress", 3, "p2sh" }, + { "importpubkey", 2, "rescan" }, + { "importmulti", 0, "requests" }, + { "importmulti", 1, "options" }, + { "verifychain", 0, "checklevel" }, + { "verifychain", 1, "nblocks" }, + { "keypoolrefill", 0, "newsize" }, + { "getrawmempool", 0, "verbose" }, + { "estimatefee", 0, "nblocks" }, + { "estimatepriority", 0, "nblocks" }, + { "estimatesmartfee", 0, "nblocks" }, + { "estimatesmartpriority", 0, "nblocks" }, + { "prioritisetransaction", 1, "priority_delta" }, + { "prioritisetransaction", 2, "fee_delta" }, + { "setban", 2, "bantime" }, + { "setban", 3, "absolute" }, + { "setnetworkactive", 0, "state" }, + { "getmempoolancestors", 1, "verbose" }, + { "getmempooldescendants", 1, "verbose" }, + { "spork", 1, "datetime" }, + { "voteraw", 1, "tx_index" }, + { "voteraw", 5, "time" }, + { "getblockhashes", 0, "high"}, + { "getblockhashes", 1, "low" }, + { "getspentinfo", 0, "json" }, + { "getaddresstxids", 0, "addresses" }, + { "getaddressbalance", 0, "addresses" }, + { "getaddressdeltas", 0, "addresses" }, + { "getaddressutxos", 0, "addresses" }, + { "getaddressmempool", 0, "addresses" }, + // Echo with conversion (For testing only) + { "echojson", 0, "arg0" }, + { "echojson", 1, "arg1" }, + { "echojson", 2, "arg2" }, + { "echojson", 3, "arg3" }, + { "echojson", 4, "arg4" }, + { "echojson", 5, "arg5" }, + { "echojson", 6, "arg6" }, + { "echojson", 7, "arg7" }, + { "echojson", 8, "arg8" }, + { "echojson", 9, "arg9" }, }; class CRPCConvertTable { private: - std::set > members; + std::set> members; + std::set> membersByName; public: CRPCConvertTable(); @@ -158,6 +174,9 @@ class CRPCConvertTable bool convert(const std::string& method, int idx) { return (members.count(std::make_pair(method, idx)) > 0); } + bool convert(const std::string& method, const std::string& name) { + return (membersByName.count(std::make_pair(method, name)) > 0); + } }; CRPCConvertTable::CRPCConvertTable() @@ -168,6 +187,8 @@ CRPCConvertTable::CRPCConvertTable() for (unsigned int i = 0; i < n_elem; i++) { members.insert(std::make_pair(vRPCConvertParams[i].methodName, vRPCConvertParams[i].paramIdx)); + membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName, + vRPCConvertParams[i].paramName)); } } @@ -185,7 +206,6 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal) return jVal[0]; } -/** Convert strings to command-specific RPC representation */ UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) { UniValue params(UniValue::VARR); @@ -204,3 +224,28 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector &strParams) +{ + UniValue params(UniValue::VOBJ); + + for (const std::string &s: strParams) { + size_t pos = s.find("="); + if (pos == std::string::npos) { + throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)")); + } + + std::string name = s.substr(0, pos); + std::string value = s.substr(pos+1); + + if (!rpcCvtTable.convert(strMethod, name)) { + // insert string value directly + params.pushKV(name, value); + } else { + // parse string as JSON, insert bool/number/object/etc. value + params.pushKV(name, ParseNonRFCJSONValue(value)); + } + } + + return params; +} diff --git a/src/rpc/client.h b/src/rpc/client.h index ae015860b671..0b9fa648f7cc 100644 --- a/src/rpc/client.h +++ b/src/rpc/client.h @@ -8,7 +8,12 @@ #include +/** Convert positional arguments to command-specific RPC representation */ UniValue RPCConvertValues(const std::string& strMethod, const std::vector& strParams); + +/** Convert named arguments to command-specific RPC representation */ +UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector& strParams); + /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 952dad487f96..23716210c70a 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -997,12 +997,13 @@ UniValue getsuperblockbudget(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ ---------- /* Dash features */ - { "dash", "getgovernanceinfo", &getgovernanceinfo, true }, - { "dash", "getsuperblockbudget", &getsuperblockbudget, true }, - { "dash", "gobject", &gobject, true }, - { "dash", "voteraw", &voteraw, true }, + { "dash", "getgovernanceinfo", &getgovernanceinfo, true, {} }, + { "dash", "getsuperblockbudget", &getsuperblockbudget, true, {"index"} }, + { "dash", "gobject", &gobject, true, {} }, + { "dash", "voteraw", &voteraw, true, {} }, }; diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 7c6131d684f9..8b813027d7c4 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -854,15 +854,15 @@ UniValue sentinelping(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - /* Dash features */ - { "dash", "masternode", &masternode, true }, - { "dash", "masternodelist", &masternodelist, true }, - { "dash", "masternodebroadcast", &masternodebroadcast, true }, - { "dash", "getpoolinfo", &getpoolinfo, true }, - { "dash", "sentinelping", &sentinelping, true }, +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ ---------- + { "dash", "masternode", &masternode, true, {} }, + { "dash", "masternodelist", &masternodelist, true, {} }, + { "dash", "masternodebroadcast", &masternodebroadcast, true, {} }, + { "dash", "getpoolinfo", &getpoolinfo, true, {} }, + { "dash", "sentinelping", &sentinelping, true, {} }, #ifdef ENABLE_WALLET - { "dash", "privatesend", &privatesend, false }, + { "dash", "privatesend", &privatesend, false, {} }, #endif // ENABLE_WALLET }; diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 602512b7216f..ea88d5b18a0f 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -84,13 +84,13 @@ UniValue getnetworkhashps(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 2) throw runtime_error( - "getnetworkhashps ( blocks height )\n" + "getnetworkhashps ( nblocks height )\n" "\nReturns the estimated network hashes per second based on the last n blocks.\n" "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" "\nArguments:\n" - "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n" - "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" + "1. nblocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n" + "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" "\nResult:\n" "x (numeric) Hashes per second estimated\n" "\nExamples:\n" @@ -138,7 +138,7 @@ UniValue generateBlocks(boost::shared_ptr coinbaseScript, int nG continue; } std::shared_ptr shared_pblock = std::make_shared(*pblock); - if (!ProcessNewBlock(Params(), shared_pblock, true, NULL, NULL)) + if (!ProcessNewBlock(Params(), shared_pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -156,12 +156,12 @@ UniValue generate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( - "generate numblocks ( maxtries )\n" - "\nMine up to numblocks blocks immediately (before the RPC call returns)\n" + "generate nblocks ( maxtries )\n" + "\nMine up to nblocks blocks immediately (before the RPC call returns)\n" "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "1. nblocks (numeric, required) How many blocks are generated immediately.\n" "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" - "\nResult\n" + "\nResult:\n" "[ blockhashes ] (array) hashes of blocks generated\n" "\nExamples:\n" "\nGenerate 11 blocks\n" @@ -192,13 +192,13 @@ UniValue generatetoaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) throw runtime_error( - "generatetoaddress numblocks address (maxtries)\n" + "generatetoaddress nblocks address (maxtries)\n" "\nMine blocks immediately to a specified address (before the RPC call returns)\n" "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" - "2. address (string, required) The address to send the newly generated Dash to.\n" + "1. nblocks (numeric, required) How many blocks are generated immediately.\n" + "2. address (string, required) The address to send the newly generated Dash to.\n" "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" - "\nResult\n" + "\nResult:\n" "[ blockhashes ] (array) hashes of blocks generated\n" "\nExamples:\n" "\nGenerate 11 blocks to myaddress\n" @@ -268,13 +268,13 @@ UniValue prioritisetransaction(const JSONRPCRequest& request) "Accepts the transaction into mined blocks at a higher (or lower) priority\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id.\n" - "2. priority delta (numeric, required) The priority to add or subtract.\n" + "2. priority_delta (numeric, required) The priority to add or subtract.\n" " The transaction selection algorithm considers the tx as it would have a higher priority.\n" " (priority of a transaction is calculated: coinage * value_in_duffs / txsize) \n" - "3. fee delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\n" + "3. fee_delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee.\n" - "\nResult\n" + "\nResult:\n" "true (boolean) Returns true\n" "\nExamples:\n" + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") @@ -332,7 +332,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" "\nArguments:\n" - "1. TemplateRequest (json object, optional) A json object in the following spec\n" + "1. template_request (json object, optional) A json object in the following spec\n" " {\n" " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n" " \"capabilities\":[ (array, optional) A list of strings\n" @@ -760,9 +760,9 @@ UniValue submitblock(const JSONRPCRequest& request) "The 'jsonparametersobject' parameter is currently ignored.\n" "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" - "\nArguments\n" - "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" - "2. \"jsonparametersobject\" (string, optional) object of optional parameters\n" + "\nArguments:\n" + "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" + "2. \"parameters\" (string, optional) object of optional parameters\n" " {\n" " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n" " }\n" @@ -795,7 +795,7 @@ UniValue submitblock(const JSONRPCRequest& request) submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL, NULL); + bool fAccepted = ProcessNewBlock(Params(), blockptr, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { @@ -816,7 +816,7 @@ UniValue estimatefee(const JSONRPCRequest& request) "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" "confirmation within nblocks blocks.\n" "\nArguments:\n" - "1. nblocks (numeric)\n" + "1. nblocks (numeric, required)\n" "\nResult:\n" "n (numeric) estimated fee-per-kilobyte\n" "\n" @@ -849,7 +849,7 @@ UniValue estimatepriority(const JSONRPCRequest& request) "\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n" "confirmation within nblocks blocks.\n" "\nArguments:\n" - "1. nblocks (numeric)\n" + "1. nblocks (numeric, required)\n" "\nResult:\n" "n (numeric) estimated priority\n" "\n" @@ -914,7 +914,7 @@ UniValue estimatesmartpriority(const JSONRPCRequest& request) "confirmation within nblocks blocks if possible and return the number of blocks\n" "for which the estimate is valid.\n" "\nArguments:\n" - "1. nblocks (numeric)\n" + "1. nblocks (numeric, required)\n" "\nResult:\n" "{\n" " \"priority\" : x.x, (numeric) estimated priority\n" @@ -943,19 +943,19 @@ UniValue estimatesmartpriority(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "mining", "getnetworkhashps", &getnetworkhashps, true }, - { "mining", "getmininginfo", &getmininginfo, true }, - { "mining", "prioritisetransaction", &prioritisetransaction, true }, - { "mining", "getblocktemplate", &getblocktemplate, true }, - { "mining", "submitblock", &submitblock, true }, - - { "generating", "generate", &generate, true }, - { "generating", "generatetoaddress", &generatetoaddress, true }, - - { "util", "estimatefee", &estimatefee, true }, - { "util", "estimatepriority", &estimatepriority, true }, - { "util", "estimatesmartfee", &estimatesmartfee, true }, - { "util", "estimatesmartpriority", &estimatesmartpriority, true }, + { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} }, + { "mining", "getmininginfo", &getmininginfo, true, {} }, + { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","priority_delta","fee_delta"} }, + { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} }, + { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} }, + + { "generating", "generate", &generate, true, {"nblocks","maxtries"} }, + { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} }, + + { "util", "estimatefee", &estimatefee, true, {"nblocks"} }, + { "util", "estimatepriority", &estimatepriority, true, {"nblocks"} }, + { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} }, + { "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} }, }; void RegisterMiningRPCCommands(CRPCTable &t) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 15f4ab51bfd1..96350342ffd9 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -132,11 +132,12 @@ UniValue debug(const JSONRPCRequest& request) std::string strMode = request.params[0].get_str(); - mapMultiArgs["-debug"].clear(); - boost::split(mapMultiArgs["-debug"], strMode, boost::is_any_of(",")); - mapArgs["-debug"] = mapMultiArgs["-debug"][mapMultiArgs["-debug"].size() - 1]; + std::vector newMultiArgs; + boost::split(newMultiArgs, strMode, boost::is_any_of(",")); + ForceSetMultiArgs("-debug", newMultiArgs); + ForceSetArg("-debug", newMultiArgs[newMultiArgs.size() - 1]); - fDebug = mapArgs["-debug"] != "0"; + fDebug = GetArg("-debug", "") != "0"; return "Debug mode: " + (fDebug ? strMode : "off"); } @@ -280,14 +281,14 @@ UniValue validateaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "validateaddress \"dashaddress\"\n" + "validateaddress \"address\"\n" "\nReturn information about the given dash address.\n" "\nArguments:\n" - "1. \"dashaddress\" (string, required) The dash address to validate\n" + "1. \"address\" (string, required) The dash address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" - " \"address\" : \"dashaddress\", (string) The dash address validated\n" + " \"address\" : \"address\", (string) The dash address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n" @@ -454,10 +455,10 @@ UniValue verifymessage(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 3) throw runtime_error( - "verifymessage \"dashaddress\" \"signature\" \"message\"\n" + "verifymessage \"address\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" - "1. \"dashaddress\" (string, required) The dash address to use for the signature.\n" + "1. \"address\" (string, required) The dash address to use for the signature.\n" "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was signed.\n" "\nResult:\n" @@ -716,7 +717,7 @@ UniValue getaddressutxos(const JSONRPCRequest& request) " ,...\n" " ]\n" "}\n" - "\nResult\n" + "\nResult:\n" "[\n" " {\n" " \"address\" (string) The address base58check encoded\n" @@ -1085,31 +1086,46 @@ UniValue getmemoryinfo(const JSONRPCRequest& request) return obj; } +UniValue echo(const JSONRPCRequest& request) +{ + if (request.fHelp) + throw runtime_error( + "echo|echojson \"message\" ...\n" + "\nSimply echo back the input arguments. This command is for testing.\n" + "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in" + "bitcoin-cli and the GUI. There is no server-side difference." + ); + + return request.params; +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "control", "debug", &debug, true }, - { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */ - { "control", "getmemoryinfo", &getmemoryinfo, true }, - { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ - { "util", "createmultisig", &createmultisig, true }, - { "util", "verifymessage", &verifymessage, true }, - { "util", "signmessagewithprivkey", &signmessagewithprivkey, true }, - { "blockchain", "getspentinfo", &getspentinfo, false }, + { "control", "debug", &debug, true, {} }, + { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */ + { "control", "getmemoryinfo", &getmemoryinfo, true, {} }, + { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */ + { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} }, + { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} }, + { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} }, + { "blockchain", "getspentinfo", &getspentinfo, false, {"json"} }, /* Address index */ - { "addressindex", "getaddressmempool", &getaddressmempool, true }, - { "addressindex", "getaddressutxos", &getaddressutxos, false }, - { "addressindex", "getaddressdeltas", &getaddressdeltas, false }, - { "addressindex", "getaddresstxids", &getaddresstxids, false }, - { "addressindex", "getaddressbalance", &getaddressbalance, false }, + { "addressindex", "getaddressmempool", &getaddressmempool, true, {"addresses"} }, + { "addressindex", "getaddressutxos", &getaddressutxos, false, {"addresses"} }, + { "addressindex", "getaddressdeltas", &getaddressdeltas, false, {"addresses"} }, + { "addressindex", "getaddresstxids", &getaddresstxids, false, {"addresses"} }, + { "addressindex", "getaddressbalance", &getaddressbalance, false, {"addresses"} }, /* Dash features */ - { "dash", "mnsync", &mnsync, true }, - { "dash", "spork", &spork, true }, + { "dash", "mnsync", &mnsync, true, {} }, + { "dash", "spork", &spork, true, {"datetime"} }, /* Not shown in help */ - { "hidden", "setmocktime", &setmocktime, true }, + { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}}, + { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, + { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, }; void RegisterMiscRPCCommands(CRPCTable &t) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 24d7f5f007b3..b1e64918279c 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -93,6 +93,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) " \"version\": v, (numeric) The peer version, such as 7001\n" " \"subver\": \"/Dash Core:x.x.x/\", (string) The string version\n" " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n" + " \"addnode\": true|false, (boolean) Whether connection was due to addnode and is using an addnode slot\n" " \"startingheight\": n, (numeric) The starting height (block) of the peer\n" " \"banscore\": n, (numeric) The ban score\n" " \"synced_headers\": n, (numeric) The last header we have in common with this peer\n" @@ -153,6 +154,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) // their ver message. obj.push_back(Pair("subver", stats.cleanSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); + obj.push_back(Pair("addnode", stats.fAddnode)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); if (fStateStats) { obj.push_back(Pair("banscore", statestats.nMisbehavior)); @@ -469,10 +471,10 @@ UniValue setban(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || (strCommand != "add" && strCommand != "remove")) throw runtime_error( - "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n" + "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n" "\nAttempts add or remove a IP/Subnet from the banned list.\n" "\nArguments:\n" - "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n" + "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n" "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n" "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n" "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n" @@ -581,7 +583,9 @@ UniValue setnetworkactive(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) { throw runtime_error( "setnetworkactive true|false\n" - "Disable/enable all p2p network activity." + "\nDisable/enable all p2p network activity.\n" + "\nArguments:\n" + "1. \"state\" (boolean, required) true to enable networking, false to disable\n" ); } @@ -597,18 +601,18 @@ UniValue setnetworkactive(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "network", "getconnectioncount", &getconnectioncount, true }, - { "network", "ping", &ping, true }, - { "network", "getpeerinfo", &getpeerinfo, true }, - { "network", "addnode", &addnode, true }, - { "network", "disconnectnode", &disconnectnode, true }, - { "network", "getaddednodeinfo", &getaddednodeinfo, true }, - { "network", "getnettotals", &getnettotals, true }, - { "network", "getnetworkinfo", &getnetworkinfo, true }, - { "network", "setban", &setban, true }, - { "network", "listbanned", &listbanned, true }, - { "network", "clearbanned", &clearbanned, true }, - { "network", "setnetworkactive", &setnetworkactive, true, }, + { "network", "getconnectioncount", &getconnectioncount, true, {} }, + { "network", "ping", &ping, true, {} }, + { "network", "getpeerinfo", &getpeerinfo, true, {} }, + { "network", "addnode", &addnode, true, {"node","command"} }, + { "network", "disconnectnode", &disconnectnode, true, {"node"} }, + { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} }, + { "network", "getnettotals", &getnettotals, true, {} }, + { "network", "getnetworkinfo", &getnetworkinfo, true, {} }, + { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} }, + { "network", "listbanned", &listbanned, true, {} }, + { "network", "clearbanned", &clearbanned, true, {} }, + { "network", "setnetworkactive", &setnetworkactive, true, {"state"} }, }; void RegisterNetRPCCommands(CRPCTable &t) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4a9819174c79..f58284b2dff9 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -189,7 +189,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"dashaddress\" (string) dash address\n" + " \"address\" (string) dash address\n" " ,...\n" " ]\n" " }\n" @@ -263,7 +263,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request) " \"txid\" (string) A transaction hash\n" " ,...\n" " ]\n" - "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n" + "2. \"blockhash\" (string, optional) If specified, looks for txid in the block with this hash\n" "\nResult:\n" "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" @@ -383,26 +383,26 @@ UniValue createrawtransaction(const JSONRPCRequest& request) "it is not stored in the wallet or transmitted to the network.\n" "\nArguments:\n" - "1. \"transactions\" (string, required) A json array of json objects\n" + "1. \"inputs\" (string, required) A json array of json objects\n" " [\n" " {\n" " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n (numeric, required) The output number\n" - " \"sequence\":n (numeric, optional) The sequence number\n" - " }\n" + " \"vout\":n, (numeric, required) The output number\n" + " \"sequence\":n (numeric, optional) The sequence number\n" + " } \n" " ,...\n" " ]\n" - "2. \"outputs\" (string, required) a json object with outputs\n" + "2. \"outputs\" (string, required) a json object with outputs\n" " {\n" - " \"address\": x.xxx (numeric or string, required) The key is the dash address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" - " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n" - " ...\n" + " \"address\": x.xxx, (numeric or string, required) The key is the dash address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" + " \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n" + " ,...\n" " }\n" - "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" + "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" "\nResult:\n" - "\"transaction\" (string) hex string of the transaction\n" + "\"transaction\" (string) hex string of the transaction\n" - "\nExamples\n" + "\nExamples:\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") @@ -492,7 +492,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" "\nArguments:\n" - "1. \"hex\" (string, required) The transaction hex string\n" + "1. \"hexstring\" (string, required) The transaction hex string\n" "\nResult:\n" "{\n" @@ -554,10 +554,10 @@ UniValue decodescript(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "decodescript \"hex\"\n" + "decodescript \"hexstring\"\n" "\nDecode a hex-encoded script.\n" "\nArguments:\n" - "1. \"hex\" (string) the hex encoded script\n" + "1. \"hexstring\" (string) the hex encoded script\n" "\nResult:\n" "{\n" " \"asm\":\"asm\", (string) Script public key\n" @@ -638,7 +638,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) " }\n" " ,...\n" " ]\n" - "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" + "3. \"privkeys\" (string, optional) A json array of base58-encoded private keys for signing\n" " [ (json array of strings, or 'null' if none provided)\n" " \"privatekey\" (string) private key in base58-encoding\n" " ,...\n" @@ -899,8 +899,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) CMutableTransaction mtx; if (!DecodeHexTx(mtx, request.params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - CTransaction tx(std::move(mtx)); - uint256 hashTx = tx.GetHash(); + CTransactionRef tx(MakeTransactionRef(std::move(mtx))); + const uint256& hashTx = tx->GetHash(); bool fLimitFree = false; CAmount nMaxRawTxFee = maxTxFee; @@ -913,19 +913,19 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) CCoinsViewCache &view = *pcoinsTip; bool fHaveChain = false; - for (size_t o = 0; !fHaveChain && o < tx.vout.size(); o++) { + for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) { const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); fHaveChain = !existingCoin.IsSpent(); } bool fHaveMempool = mempool.exists(hashTx); if (!fHaveMempool && !fHaveChain) { // push to local node and sync with wallets - if (fInstantSend && !instantsend.ProcessTxLockRequest(tx, *g_connman)) { + if (fInstantSend && !instantsend.ProcessTxLockRequest(*tx, *g_connman)) { throw JSONRPCError(RPC_TRANSACTION_ERROR, "Not a valid InstantSend transaction, see debug.log for more info"); } CValidationState state; bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, tx, fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) { + if (!AcceptToMemoryPool(mempool, state, std::move(tx), fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) { if (state.IsInvalid()) { throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); } else { @@ -941,7 +941,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - g_connman->RelayTransaction(tx); + g_connman->RelayTransaction(*tx); return hashTx.GetHex(); } @@ -949,15 +949,15 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true }, - { "rawtransactions", "decodescript", &decodescript, true }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ - - { "blockchain", "gettxoutproof", &gettxoutproof, true }, - { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, + { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"transactions","outputs","locktime"} }, + { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} }, + { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} }, + { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees","instantsend"} }, + { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ + + { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} }, + { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} }, }; void RegisterRawTransactionRPCCommands(CRPCTable &t) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e30c84162789..3ff336aacca7 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -27,6 +27,7 @@ #include // for to_upper() #include // for unique_ptr +#include using namespace RPCServer; using namespace std; @@ -269,11 +270,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest) * Call Table */ static const CRPCCommand vRPCCommands[] = -{ // category name actor (function) okSafeMode - // --------------------- ------------------------ ----------------------- ---------- +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ ---------- /* Overall control/query calls */ - { "control", "help", &help, true }, - { "control", "stop", &stop, true }, + { "control", "help", &help, true, {"command"} }, + { "control", "stop", &stop, true, {} }, }; CRPCTable::CRPCTable() @@ -380,12 +381,12 @@ void JSONRPCRequest::parse(const UniValue& valRequest) // Parse params UniValue valParams = find_value(request, "params"); - if (valParams.isArray()) - params = valParams.get_array(); + if (valParams.isArray() || valParams.isObject()) + params = valParams; else if (valParams.isNull()) params = UniValue(UniValue::VARR); else - throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); + throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object"); } static UniValue JSONRPCExecOne(const UniValue& req) @@ -421,6 +422,48 @@ std::string JSONRPCExecBatch(const UniValue& vReq) return ret.write() + "\n"; } +/** + * Process named arguments into a vector of positional arguments, based on the + * passed-in specification for the RPC call's arguments. + */ +static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector& argNames) +{ + JSONRPCRequest out = in; + out.params = UniValue(UniValue::VARR); + // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if + // there is an unknown one. + const std::vector& keys = in.params.getKeys(); + const std::vector& values = in.params.getValues(); + std::unordered_map argsIn; + for (size_t i=0; isecond); + argsIn.erase(fr); + } else { + hole += 1; + } + } + // If there are still arguments in the argsIn map, this is an error. + if (!argsIn.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first); + } + // Return request with named arguments transformed to positional arguments + return out; +} + UniValue CRPCTable::execute(const JSONRPCRequest &request) const { // Return immediately if in warmup @@ -439,8 +482,12 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const try { - // Execute - return pcmd->actor(request); + // Execute, convert arguments to array if necessary + if (request.params.isObject()) { + return pcmd->actor(transformNamedArguments(request, pcmd->argNames)); + } else { + return pcmd->actor(request); + } } catch (const std::exception& e) { diff --git a/src/rpc/server.h b/src/rpc/server.h index 28ac5ec67758..ff87125a2a69 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -134,6 +134,7 @@ class CRPCCommand std::string name; rpcfn_type actor; bool okSafeMode; + std::vector argNames; }; /** diff --git a/src/script/script.h b/src/script/script.h index f2650456ba4c..216520dd9e11 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -394,7 +394,6 @@ class CScript : public CScriptBase } public: CScript() { } - CScript(const CScript& b) : CScriptBase(b.begin(), b.end()) { } CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { } CScript(std::vector::const_iterator pbegin, std::vector::const_iterator pend) : CScriptBase(pbegin, pend) { } CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { } diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index bdc0bfdc1c0f..b78d7b607ff9 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -11,20 +11,29 @@ #include "uint256.h" #include "util.h" +#include "cuckoocache.h" #include -#include namespace { /** * We're hashing a nonce into the entries themselves, so we don't need extra * blinding in the set hash computation. + * + * This may exhibit platform endian dependent behavior but because these are + * nonced hashes (random) and this state is only ever used locally it is safe. + * All that matters is local consistency. */ -class CSignatureCacheHasher +class SignatureCacheHasher { public: - size_t operator()(const uint256& key) const { - return key.GetCheapHash(); + template + uint32_t operator()(const uint256& key) const + { + static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available."); + uint32_t u; + std::memcpy(&u, key.begin()+4*hash_select, 4); + return u; } }; @@ -38,11 +47,10 @@ class CSignatureCache private: //! Entries are SHA256(nonce || signature hash || public key || signature): uint256 nonce; - typedef boost::unordered_set map_type; + typedef CuckooCache::cache map_type; map_type setValid; boost::shared_mutex cs_sigcache; - public: CSignatureCache() { @@ -56,58 +64,51 @@ class CSignatureCache } bool - Get(const uint256& entry) + Get(const uint256& entry, const bool erase) { boost::shared_lock lock(cs_sigcache); - return setValid.count(entry); + return setValid.contains(entry, erase); } - void Erase(const uint256& entry) + void Set(uint256& entry) { boost::unique_lock lock(cs_sigcache); - setValid.erase(entry); + setValid.insert(entry); } - - void Set(const uint256& entry) + uint32_t setup_bytes(size_t n) { - size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); - if (nMaxCacheSize <= 0) return; - - boost::unique_lock lock(cs_sigcache); - while (memusage::DynamicUsage(setValid) > nMaxCacheSize) - { - map_type::size_type s = GetRand(setValid.bucket_count()); - map_type::local_iterator it = setValid.begin(s); - if (it != setValid.end(s)) { - setValid.erase(*it); - } - } - - setValid.insert(entry); + return setValid.setup_bytes(n); } }; +/* In previous versions of this code, signatureCache was a local static variable + * in CachingTransactionSignatureChecker::VerifySignature. We initialize + * signatureCache outside of VerifySignature to avoid the atomic operation per + * call overhead associated with local static variables even though + * signatureCache could be made local to VerifySignature. +*/ +static CSignatureCache signatureCache; } -bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const +// To be called once in AppInit2/TestingSetup to initialize the signatureCache +void InitSignatureCache() { - static CSignatureCache signatureCache; + size_t nMaxCacheSize = GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); + if (nMaxCacheSize <= 0) return; + size_t nElems = signatureCache.setup_bytes(nMaxCacheSize); + LogPrintf("Using %zu MiB out of %zu requested for signature cache, able to store %zu elements\n", + (nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems); +} +bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const +{ uint256 entry; signatureCache.ComputeEntry(entry, sighash, vchSig, pubkey); - - if (signatureCache.Get(entry)) { - if (!store) { - signatureCache.Erase(entry); - } + if (signatureCache.Get(entry, !store)) return true; - } - if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) return false; - - if (store) { + if (store) signatureCache.Set(entry); - } return true; } diff --git a/src/script/sigcache.h b/src/script/sigcache.h index be1df09c2ade..09cde1b6279d 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -10,9 +10,10 @@ #include -// DoS prevention: limit cache size to less than 40MB (over 500000 -// entries on 64-bit systems). -static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 40; +// DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit +// systems). Due to how we count cache size, actual memory usage is slightly +// more (~32.25 MB) +static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32; class CPubKey; @@ -27,4 +28,6 @@ class CachingTransactionSignatureChecker : public TransactionSignatureChecker bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; }; +void InitSignatureCache(); + #endif // BITCOIN_SCRIPT_SIGCACHE_H diff --git a/src/sendalert.cpp b/src/sendalert.cpp index 2896278517db..1aa8a0cbfc2f 100644 --- a/src/sendalert.cpp +++ b/src/sendalert.cpp @@ -25,12 +25,12 @@ the bad alert. void ThreadSendAlert(CConnman& connman) { - if (!mapArgs.count("-sendalert") && !mapArgs.count("-printalert")) + if (!IsArgSet("-sendalert") && !IsArgSet("-printalert")) return; // Wait one minute so we get well connected. If we only need to print // but not to broadcast - do this right away. - if (mapArgs.count("-sendalert")) + if (IsArgSet("-sendalert")) MilliSleep(60*1000); // @@ -89,7 +89,7 @@ void ThreadSendAlert(CConnman& connman) printf("vchSig=%s\n", HexStr(alert2.vchSig).c_str()); // Confirm - if (!mapArgs.count("-sendalert")) + if (!IsArgSet("-sendalert")) return; while (connman.GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && !ShutdownRequested()) MilliSleep(500); diff --git a/src/support/events.h b/src/support/events.h new file mode 100644 index 000000000000..4f2f3cf9ef76 --- /dev/null +++ b/src/support/events.h @@ -0,0 +1,56 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SUPPORT_EVENTS_H +#define BITCOIN_SUPPORT_EVENTS_H + +#include +#include + +#include +#include + +#define MAKE_RAII(type) \ +/* deleter */\ +struct type##_deleter {\ + void operator()(struct type* ob) {\ + type##_free(ob);\ + }\ +};\ +/* unique ptr typedef */\ +typedef std::unique_ptr raii_##type + +MAKE_RAII(event_base); +MAKE_RAII(event); +MAKE_RAII(evhttp); +MAKE_RAII(evhttp_request); +MAKE_RAII(evhttp_connection); + +raii_event_base obtain_event_base() { + auto result = raii_event_base(event_base_new()); + if (!result.get()) + throw std::runtime_error("cannot create event_base"); + return result; +} + +raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) { + return raii_event(event_new(base, s, events, cb, arg)); +} + +raii_evhttp obtain_evhttp(struct event_base* base) { + return raii_evhttp(evhttp_new(base)); +} + +raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) { + return raii_evhttp_request(evhttp_request_new(cb, arg)); +} + +raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) { + auto result = raii_evhttp_connection(evhttp_connection_base_new(base, NULL, host.c_str(), port)); + if (!result.get()) + throw std::runtime_error("create connection failed"); + return result; +} + +#endif // BITCOIN_SUPPORT_EVENTS_H diff --git a/src/sync.h b/src/sync.h index 753eb90c81b5..467b5224d779 100644 --- a/src/sync.h +++ b/src/sync.h @@ -264,7 +264,6 @@ class CSemaphoreGrant grant.Release(); grant.sem = sem; grant.fHaveGrant = fHaveGrant; - sem = NULL; fHaveGrant = false; } diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 1c0c11d08a11..84c9a962f710 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -12,6 +12,7 @@ #include "script/sign.h" #include "serialize.h" #include "util.h" +#include "validation.h" #include "test/test_dash.h" @@ -23,11 +24,11 @@ #include // Tests this internal-to-main.cpp method: -extern bool AddOrphanTx(const CTransaction& tx, NodeId peer); +extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer); extern void EraseOrphansFor(NodeId peer); extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); struct COrphanTx { - CTransaction tx; + CTransactionRef tx; NodeId fromPeer; int64_t nTimeExpire; }; @@ -80,7 +81,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) std::atomic interruptDummy(false); connman->ClearBanned(); - mapArgs["-banscore"] = "111"; // because 11 is my favorite number + ForceSetArg("-banscore", "111"); // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); @@ -96,7 +97,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) Misbehaving(dummyNode1.GetId(), 1); SendMessages(&dummyNode1, *connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); - mapArgs.erase("-banscore"); + ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); } BOOST_AUTO_TEST_CASE(DoS_bantime) @@ -125,7 +126,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) BOOST_CHECK(!connman->IsBanned(addr)); } -CTransaction RandomOrphan() +CTransactionRef RandomOrphan() { std::map::iterator it; it = mapOrphanTransactions.lower_bound(GetRandHash()); @@ -153,30 +154,30 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - AddOrphanTx(tx, i); + AddOrphanTx(MakeTransactionRef(tx), i); } // ... and 50 that depend on other orphans: for (int i = 0; i < 50; i++) { - CTransaction txPrev = RandomOrphan(); + CTransactionRef txPrev = RandomOrphan(); CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = txPrev.GetHash(); + tx.vin[0].prevout.hash = txPrev->GetHash(); tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - SignSignature(keystore, txPrev, tx, 0); + SignSignature(keystore, *txPrev, tx, 0); - AddOrphanTx(tx, i); + AddOrphanTx(MakeTransactionRef(tx), i); } // This really-big orphan should be ignored: for (int i = 0; i < 10; i++) { - CTransaction txPrev = RandomOrphan(); + CTransactionRef txPrev = RandomOrphan(); CMutableTransaction tx; tx.vout.resize(1); @@ -186,15 +187,15 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) for (unsigned int j = 0; j < tx.vin.size(); j++) { tx.vin[j].prevout.n = j; - tx.vin[j].prevout.hash = txPrev.GetHash(); + tx.vin[j].prevout.hash = txPrev->GetHash(); } - SignSignature(keystore, txPrev, tx, 0); + SignSignature(keystore, *txPrev, tx, 0); // Re-use same signature for other inputs // (they don't have to be valid for this test) for (unsigned int j = 1; j < tx.vin.size(); j++) tx.vin[j].scriptSig = tx.vin[0].scriptSig; - BOOST_CHECK(!AddOrphanTx(tx, i)); + BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i)); } // Test EraseOrphansFor: diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index f8030574fbf1..cf5533d332d7 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -10,8 +10,6 @@ #include "netbase.h" #include "random.h" -using namespace std; - class CAddrManTest : public CAddrMan { uint64_t state; @@ -365,7 +363,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) // Test 22: Sanity check, GetAddr should never return anything if addrman // is empty. BOOST_CHECK(addrman.size() == 0); - vector vAddr1 = addrman.GetAddr(); + std::vector vAddr1 = addrman.GetAddr(); BOOST_CHECK(vAddr1.size() == 0); CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE); @@ -401,7 +399,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) int octet1 = i % 256; int octet2 = (i / 256) % 256; int octet3 = (i / (256 * 2)) % 256; - string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; + std::string strAddr = boost::to_string(octet1) + "." + boost::to_string(octet2) + "." + boost::to_string(octet3) + ".23"; CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE); // Ensure that for all addrs in addrman, isTerrible == false. @@ -410,7 +408,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) if (i % 8 == 0) addrman.Good(addr); } - vector vAddr = addrman.GetAddr(); + std::vector vAddr = addrman.GetAddr(); size_t percent23 = (addrman.size() * 23) / 100; BOOST_CHECK(vAddr.size() == percent23); @@ -452,7 +450,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) BOOST_CHECK(info1.GetKey() != info2.GetKey()); BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1)); - set buckets; + std::set buckets; for (int i = 0; i < 255; i++) { CAddrInfo infoi = CAddrInfo( CAddress(ResolveService("250.1.1." + boost::to_string(i)), NODE_NONE), @@ -505,7 +503,7 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) BOOST_CHECK(info1.GetKey() != info2.GetKey()); BOOST_CHECK(info1.GetNewBucket(nKey1) == info2.GetNewBucket(nKey1)); - set buckets; + std::set buckets; for (int i = 0; i < 255; i++) { CAddrInfo infoi = CAddrInfo( CAddress(ResolveService("250.1.1." + boost::to_string(i)), NODE_NONE), diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp index 39fdefd67b0a..5696c796022a 100644 --- a/src/test/alert_tests.cpp +++ b/src/test/alert_tests.cpp @@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(AlertNotify) boost::filesystem::path temp = GetTempPath() / boost::filesystem::unique_path("alertnotify-%%%%.txt"); - mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string(); + ForceSetArg("-alertnotify", std::string("echo %s >> ") + temp.string()); BOOST_FOREACH(CAlert alert, alerts) alert.ProcessAlert(alertKey, false); diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 016833601ab5..6eeafac09b61 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -21,8 +21,6 @@ #include #include -using namespace std; - BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) @@ -43,8 +41,8 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; - vector vch = ParseHex("03614e9b050000000000000001"); - vector expected(vch.size()); + std::vector vch = ParseHex("03614e9b050000000000000001"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -75,8 +73,8 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; - vector vch = ParseHex("03ce4299050000000100008001"); - vector expected(vch.size()); + std::vector vch = ParseHex("03ce4299050000000100008001"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -86,24 +84,24 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) BOOST_AUTO_TEST_CASE(bloom_create_insert_key) { - string strSecret = string("7sQb6QHALg4XyHsJHsSNXnEHGhZfzTTUPJXJqaqK7CavQkiL9Ms"); + std::string strSecret = std::string("7sQb6QHALg4XyHsJHsSNXnEHGhZfzTTUPJXJqaqK7CavQkiL9Ms"); CBitcoinSecret vchSecret; BOOST_CHECK(vchSecret.SetString(strSecret)); CKey key = vchSecret.GetKey(); CPubKey pubkey = key.GetPubKey(); - vector vchPubKey(pubkey.begin(), pubkey.end()); + std::vector vchPubKey(pubkey.begin(), pubkey.end()); CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); filter.insert(vchPubKey); uint160 hash = pubkey.GetID(); - filter.insert(vector(hash.begin(), hash.end())); + filter.insert(std::vector(hash.begin(), hash.end())); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; - vector vch = ParseHex("038fc16b080000000000000001"); - vector expected(vch.size()); + std::vector vch = ParseHex("038fc16b080000000000000001"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -119,7 +117,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) // and one which spends it (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; - vector vch(ch, ch + sizeof(ch) -1); + std::vector vch(ch, ch + sizeof(ch) -1); CDataStream spendStream(vch, SER_DISK, CLIENT_VERSION); CTransaction spendingTx(deserialize, spendStream); @@ -156,7 +154,7 @@ BOOST_AUTO_TEST_CASE(bloom_match) filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), 0); { - vector data(32 + sizeof(unsigned int)); + std::vector data(32 + sizeof(unsigned int)); memcpy(&data[0], prevOutPoint.hash.begin(), 32); memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); filter.insert(data); @@ -196,13 +194,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_1) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); - vector vMatched; - vector vIndex; + std::vector vMatched; + std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -242,13 +240,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); - vector vMatched; - vector vIndex; + std::vector vMatched; + std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -297,13 +295,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); - vector vMatched; - vector vIndex; + std::vector vMatched; + std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -353,8 +351,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); - vector vMatched; - vector vIndex; + std::vector vMatched; + std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) @@ -363,8 +361,8 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION); merkleStream << merkleBlock; - vector vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); - vector expected(vch.size()); + std::vector vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); + std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; @@ -388,13 +386,13 @@ BOOST_AUTO_TEST_CASE(merkle_block_4) BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); - pair pair = merkleBlock.vMatchedTxn[0]; + std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); - vector vMatched; - vector vIndex; + std::vector vMatched; + std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 72c93350a859..e0dd3dacc4dc 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -539,7 +539,6 @@ const static char NO_ENTRY = -1; const static auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)}; const static auto CLEAN_FLAGS = {char(0), FRESH}; -const static auto DIRTY_FLAGS = {DIRTY, char(DIRTY | FRESH)}; const static auto ABSENT_FLAGS = {NO_ENTRY}; void SetCoinsValue(CAmount value, Coin& coin) diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp new file mode 100644 index 000000000000..326ddb02004e --- /dev/null +++ b/src/test/cuckoocache_tests.cpp @@ -0,0 +1,394 @@ +// Copyright (c) 2012-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include "cuckoocache.h" +#include "test/test_dash.h" +#include "random.h" +#include +#include + + +/** Test Suite for CuckooCache + * + * 1) All tests should have a deterministic result (using insecure rand + * with deterministic seeds) + * 2) Some test methods are templated to allow for easier testing + * against new versions / comparing + * 3) Results should be treated as a regression test, ie, did the behavior + * change significantly from what was expected. This can be OK, depending on + * the nature of the change, but requires updating the tests to reflect the new + * expected behavior. For example improving the hit rate may cause some tests + * using BOOST_CHECK_CLOSE to fail. + * + */ +FastRandomContext insecure_rand(true); + +BOOST_AUTO_TEST_SUITE(cuckoocache_tests); + + +/** insecure_GetRandHash fills in a uint256 from insecure_rand + */ +void insecure_GetRandHash(uint256& t) +{ + uint32_t* ptr = (uint32_t*)t.begin(); + for (uint8_t j = 0; j < 8; ++j) + *(ptr++) = insecure_rand.rand32(); +} + +/** Definition copied from /src/script/sigcache.cpp + */ +class uint256Hasher +{ +public: + template + uint32_t operator()(const uint256& key) const + { + static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available."); + uint32_t u; + std::memcpy(&u, key.begin() + 4 * hash_select, 4); + return u; + } +}; + + +/* Test that no values not inserted into the cache are read out of it. + * + * There are no repeats in the first 200000 insecure_GetRandHash calls + */ +BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) +{ + insecure_rand = FastRandomContext(true); + CuckooCache::cache cc{}; + cc.setup_bytes(32 << 20); + uint256 v; + for (int x = 0; x < 100000; ++x) { + insecure_GetRandHash(v); + cc.insert(v); + } + for (int x = 0; x < 100000; ++x) { + insecure_GetRandHash(v); + BOOST_CHECK(!cc.contains(v, false)); + } +}; + +/** This helper returns the hit rate when megabytes*load worth of entries are + * inserted into a megabytes sized cache + */ +template +double test_cache(size_t megabytes, double load) +{ + insecure_rand = FastRandomContext(true); + std::vector hashes; + Cache set{}; + size_t bytes = megabytes * (1 << 20); + set.setup_bytes(bytes); + uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); + hashes.resize(n_insert); + for (uint32_t i = 0; i < n_insert; ++i) { + uint32_t* ptr = (uint32_t*)hashes[i].begin(); + for (uint8_t j = 0; j < 8; ++j) + *(ptr++) = insecure_rand.rand32(); + } + /** We make a copy of the hashes because future optimizations of the + * cuckoocache may overwrite the inserted element, so the test is + * "future proofed". + */ + std::vector hashes_insert_copy = hashes; + /** Do the insert */ + for (uint256& h : hashes_insert_copy) + set.insert(h); + /** Count the hits */ + uint32_t count = 0; + for (uint256& h : hashes) + count += set.contains(h, false); + double hit_rate = ((double)count) / ((double)n_insert); + return hit_rate; +} + +/** The normalized hit rate for a given load. + * + * The semantics are a little confusing, so please see the below + * explanation. + * + * Examples: + * + * 1) at load 0.5, we expect a perfect hit rate, so we multiply by + * 1.0 + * 2) at load 2.0, we expect to see half the entries, so a perfect hit rate + * would be 0.5. Therefore, if we see a hit rate of 0.4, 0.4*2.0 = 0.8 is the + * normalized hit rate. + * + * This is basically the right semantics, but has a bit of a glitch depending on + * how you measure around load 1.0 as after load 1.0 your normalized hit rate + * becomes effectively perfect, ignoring freshness. + */ +double normalize_hit_rate(double hits, double load) +{ + return hits * std::max(load, 1.0); +} + +/** Check the hit rate on loads ranging from 0.1 to 2.0 */ +BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok) +{ + /** Arbitrarily selected Hit Rate threshold that happens to work for this test + * as a lower bound on performance. + */ + double HitRateThresh = 0.98; + size_t megabytes = 32; + for (double load = 0.1; load < 2; load *= 2) { + double hits = test_cache>(megabytes, load); + BOOST_CHECK(normalize_hit_rate(hits, load) > HitRateThresh); + } +} + + +/** This helper checks that erased elements are preferentially inserted onto and + * that the hit rate of "fresher" keys is reasonable*/ +template +void test_cache_erase(size_t megabytes) +{ + double load = 1; + insecure_rand = FastRandomContext(true); + std::vector hashes; + Cache set{}; + size_t bytes = megabytes * (1 << 20); + set.setup_bytes(bytes); + uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); + hashes.resize(n_insert); + for (uint32_t i = 0; i < n_insert; ++i) { + uint32_t* ptr = (uint32_t*)hashes[i].begin(); + for (uint8_t j = 0; j < 8; ++j) + *(ptr++) = insecure_rand.rand32(); + } + /** We make a copy of the hashes because future optimizations of the + * cuckoocache may overwrite the inserted element, so the test is + * "future proofed". + */ + std::vector hashes_insert_copy = hashes; + + /** Insert the first half */ + for (uint32_t i = 0; i < (n_insert / 2); ++i) + set.insert(hashes_insert_copy[i]); + /** Erase the first quarter */ + for (uint32_t i = 0; i < (n_insert / 4); ++i) + set.contains(hashes[i], true); + /** Insert the second half */ + for (uint32_t i = (n_insert / 2); i < n_insert; ++i) + set.insert(hashes_insert_copy[i]); + + /** elements that we marked erased but that are still there */ + size_t count_erased_but_contained = 0; + /** elements that we did not erase but are older */ + size_t count_stale = 0; + /** elements that were most recently inserted */ + size_t count_fresh = 0; + + for (uint32_t i = 0; i < (n_insert / 4); ++i) + count_erased_but_contained += set.contains(hashes[i], false); + for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i) + count_stale += set.contains(hashes[i], false); + for (uint32_t i = (n_insert / 2); i < n_insert; ++i) + count_fresh += set.contains(hashes[i], false); + + double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0); + double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0); + double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0); + + // Check that our hit_rate_fresh is perfect + BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0); + // Check that we have a more than 2x better hit rate on stale elements than + // erased elements. + BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); +} + +BOOST_AUTO_TEST_CASE(cuckoocache_erase_ok) +{ + size_t megabytes = 32; + test_cache_erase>(megabytes); +} + +template +void test_cache_erase_parallel(size_t megabytes) +{ + double load = 1; + insecure_rand = FastRandomContext(true); + std::vector hashes; + Cache set{}; + size_t bytes = megabytes * (1 << 20); + set.setup_bytes(bytes); + uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); + hashes.resize(n_insert); + for (uint32_t i = 0; i < n_insert; ++i) { + uint32_t* ptr = (uint32_t*)hashes[i].begin(); + for (uint8_t j = 0; j < 8; ++j) + *(ptr++) = insecure_rand.rand32(); + } + /** We make a copy of the hashes because future optimizations of the + * cuckoocache may overwrite the inserted element, so the test is + * "future proofed". + */ + std::vector hashes_insert_copy = hashes; + boost::shared_mutex mtx; + + { + /** Grab lock to make sure we release inserts */ + boost::unique_lock l(mtx); + /** Insert the first half */ + for (uint32_t i = 0; i < (n_insert / 2); ++i) + set.insert(hashes_insert_copy[i]); + } + + /** Spin up 3 threads to run contains with erase. + */ + std::vector threads; + /** Erase the first quarter */ + for (uint32_t x = 0; x < 3; ++x) + /** Each thread is emplaced with x copy-by-value + */ + threads.emplace_back([&, x] { + boost::shared_lock l(mtx); + size_t ntodo = (n_insert/4)/3; + size_t start = ntodo*x; + size_t end = ntodo*(x+1); + for (uint32_t i = start; i < end; ++i) + set.contains(hashes[i], true); + }); + + /** Wait for all threads to finish + */ + for (std::thread& t : threads) + t.join(); + /** Grab lock to make sure we observe erases */ + boost::unique_lock l(mtx); + /** Insert the second half */ + for (uint32_t i = (n_insert / 2); i < n_insert; ++i) + set.insert(hashes_insert_copy[i]); + + /** elements that we marked erased but that are still there */ + size_t count_erased_but_contained = 0; + /** elements that we did not erase but are older */ + size_t count_stale = 0; + /** elements that were most recently inserted */ + size_t count_fresh = 0; + + for (uint32_t i = 0; i < (n_insert / 4); ++i) + count_erased_but_contained += set.contains(hashes[i], false); + for (uint32_t i = (n_insert / 4); i < (n_insert / 2); ++i) + count_stale += set.contains(hashes[i], false); + for (uint32_t i = (n_insert / 2); i < n_insert; ++i) + count_fresh += set.contains(hashes[i], false); + + double hit_rate_erased_but_contained = double(count_erased_but_contained) / (double(n_insert) / 4.0); + double hit_rate_stale = double(count_stale) / (double(n_insert) / 4.0); + double hit_rate_fresh = double(count_fresh) / (double(n_insert) / 2.0); + + // Check that our hit_rate_fresh is perfect + BOOST_CHECK_EQUAL(hit_rate_fresh, 1.0); + // Check that we have a more than 2x better hit rate on stale elements than + // erased elements. + BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); +} +BOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok) +{ + size_t megabytes = 32; + test_cache_erase_parallel>(megabytes); +} + + +template +void test_cache_generations() +{ + // This test checks that for a simulation of network activity, the fresh hit + // rate is never below 99%, and the number of times that it is worse than + // 99.9% are less than 1% of the time. + double min_hit_rate = 0.99; + double tight_hit_rate = 0.999; + double max_rate_less_than_tight_hit_rate = 0.01; + // A cache that meets this specification is therefore shown to have a hit + // rate of at least tight_hit_rate * (1 - max_rate_less_than_tight_hit_rate) + + // min_hit_rate*max_rate_less_than_tight_hit_rate = 0.999*99%+0.99*1% == 99.89% + // hit rate with low variance. + + // We use deterministic values, but this test has also passed on many + // iterations with non-deterministic values, so it isn't "overfit" to the + // specific entropy in FastRandomContext(true) and implementation of the + // cache. + insecure_rand = FastRandomContext(true); + + // block_activity models a chunk of network activity. n_insert elements are + // adde to the cache. The first and last n/4 are stored for removal later + // and the middle n/2 are not stored. This models a network which uses half + // the signatures of recently (since the last block) added transactions + // immediately and never uses the other half. + struct block_activity { + std::vector reads; + block_activity(uint32_t n_insert, Cache& c) : reads() + { + std::vector inserts; + inserts.resize(n_insert); + reads.reserve(n_insert / 2); + for (uint32_t i = 0; i < n_insert; ++i) { + uint32_t* ptr = (uint32_t*)inserts[i].begin(); + for (uint8_t j = 0; j < 8; ++j) + *(ptr++) = insecure_rand.rand32(); + } + for (uint32_t i = 0; i < n_insert / 4; ++i) + reads.push_back(inserts[i]); + for (uint32_t i = n_insert - (n_insert / 4); i < n_insert; ++i) + reads.push_back(inserts[i]); + for (auto h : inserts) + c.insert(h); + } + }; + + const uint32_t BLOCK_SIZE = 10000; + // We expect window size 60 to perform reasonably given that each epoch + // stores 45% of the cache size (~472k). + const uint32_t WINDOW_SIZE = 60; + const uint32_t POP_AMOUNT = (BLOCK_SIZE / WINDOW_SIZE) / 2; + const double load = 10; + const size_t megabytes = 32; + const size_t bytes = megabytes * (1 << 20); + const uint32_t n_insert = static_cast(load * (bytes / sizeof(uint256))); + + std::vector hashes; + Cache set{}; + set.setup_bytes(bytes); + hashes.reserve(n_insert / BLOCK_SIZE); + std::deque last_few; + uint32_t out_of_tight_tolerance = 0; + uint32_t total = n_insert / BLOCK_SIZE; + // we use the deque last_few to model a sliding window of blocks. at each + // step, each of the last WINDOW_SIZE block_activities checks the cache for + // POP_AMOUNT of the hashes that they inserted, and marks these erased. + for (uint32_t i = 0; i < total; ++i) { + if (last_few.size() == WINDOW_SIZE) + last_few.pop_front(); + last_few.emplace_back(BLOCK_SIZE, set); + uint32_t count = 0; + for (auto& act : last_few) + for (uint32_t k = 0; k < POP_AMOUNT; ++k) { + count += set.contains(act.reads.back(), true); + act.reads.pop_back(); + } + // We use last_few.size() rather than WINDOW_SIZE for the correct + // behavior on the first WINDOW_SIZE iterations where the deque is not + // full yet. + double hit = (double(count)) / (last_few.size() * POP_AMOUNT); + // Loose Check that hit rate is above min_hit_rate + BOOST_CHECK(hit > min_hit_rate); + // Tighter check, count number of times we are less than tight_hit_rate + // (and implicityly, greater than min_hit_rate) + out_of_tight_tolerance += hit < tight_hit_rate; + } + // Check that being out of tolerance happens less than + // max_rate_less_than_tight_hit_rate of the time + BOOST_CHECK(double(out_of_tight_tolerance) / double(total) < max_rate_less_than_tight_hit_rate); +} +BOOST_AUTO_TEST_CASE(cuckoocache_generations) +{ + test_cache_generations>(); +} + +BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 909eb5f54c63..3f0bff9e2f03 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -10,13 +10,9 @@ #include // for 'operator+=()' #include #include - -using namespace std; -using namespace boost::assign; // bring 'operator+=()' into scope -using namespace boost::filesystem; - + // Test if a string consists entirely of null characters -bool is_null_key(const vector& key) { +bool is_null_key(const std::vector& key) { bool isnull = true; for (unsigned int i = 0; i < key.size(); i++) @@ -32,7 +28,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; - path ph = temp_directory_path() / unique_path(); + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'k'; uint256 in = GetRandHash(); @@ -53,7 +49,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; - path ph = temp_directory_path() / unique_path(); + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'i'; @@ -90,7 +86,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; - path ph = temp_directory_path() / unique_path(); + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering @@ -129,8 +125,8 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) // Test that we do not obfuscation if there is existing data. BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) { - // We're going to share this path between two wrappers - path ph = temp_directory_path() / unique_path(); + // We're going to share this boost::filesystem::path between two wrappers + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. @@ -170,8 +166,8 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) // Ensure that we start obfuscating during a reindex. BOOST_AUTO_TEST_CASE(existing_data_reindex) { - // We're going to share this path between two wrappers - path ph = temp_directory_path() / unique_path(); + // We're going to share this boost::filesystem::path between two wrappers + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. @@ -206,7 +202,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) BOOST_AUTO_TEST_CASE(iterator_ordering) { - path ph = temp_directory_path() / unique_path(); + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x=0x00; x<256; ++x) { uint8_t key = x; @@ -241,11 +237,11 @@ BOOST_AUTO_TEST_CASE(iterator_ordering) struct StringContentsSerializer { // Used to make two serialized objects the same while letting them have a different lengths // This is a terrible idea - string str; + std::string str; StringContentsSerializer() {} - StringContentsSerializer(const string& inp) : str(inp) {} + StringContentsSerializer(const std::string& inp) : str(inp) {} - StringContentsSerializer& operator+=(const string& s) { + StringContentsSerializer& operator+=(const std::string& s) { str += s; return *this; } @@ -277,7 +273,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering) { char buf[10]; - path ph = temp_directory_path() / unique_path(); + boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x=0x00; x<10; ++x) { for (int y = 0; y < 10; y++) { @@ -303,7 +299,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering) for (int x=seek_start; x<10; ++x) { for (int y = 0; y < 10; y++) { sprintf(buf, "%d", x); - string exp_key(buf); + std::string exp_key(buf); for (int z = 0; z < y; z++) exp_key += exp_key; StringContentsSerializer key; diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index f52f79869105..82d7b3177d37 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -10,8 +10,6 @@ #include -using namespace std; - BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(murmurhash3) diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index a3504ab5b2aa..1af3dfd60695 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -16,19 +16,17 @@ #include -using namespace std; - -static const string strSecret1 ("7qh6LYnLN2w2ntz2wwUhRUEgkQ2j8XB16FGw77ZRDZmC29bn7cD"); -static const string strSecret2 ("7rve4MxeWFQHGbSYH6J2yaaZd3MBUqoDEwN6ZAZ6ZHmhTT4r3hW"); -static const string strSecret1C ("XBuxZHH6TqXUuaSjbVTFR1DQSYecxCB9QA1Koyx5tTc3ddhqEnhm"); -static const string strSecret2C ("XHMkZqWcY6Zkoq1j42NBijD8z5N5FtNy2Wx7WyAfXX2HZgxry8cr"); +static const std::string strSecret1 ("7qh6LYnLN2w2ntz2wwUhRUEgkQ2j8XB16FGw77ZRDZmC29bn7cD"); +static const std::string strSecret2 ("7rve4MxeWFQHGbSYH6J2yaaZd3MBUqoDEwN6ZAZ6ZHmhTT4r3hW"); +static const std::string strSecret1C ("XBuxZHH6TqXUuaSjbVTFR1DQSYecxCB9QA1Koyx5tTc3ddhqEnhm"); +static const std::string strSecret2C ("XHMkZqWcY6Zkoq1j42NBijD8z5N5FtNy2Wx7WyAfXX2HZgxry8cr"); static const CBitcoinAddress addr1 ("Xywgfc872nn5CKtpATCoAjZCc4v96pJczy"); static const CBitcoinAddress addr2 ("XpmouUj9KKJ99ZuU331ZS1KqsboeFnLGgK"); static const CBitcoinAddress addr1C("XxV9h4Xmv6Pup8tVAQmH97K6grzvDwMG9F"); static const CBitcoinAddress addr2C("Xn7ZrYdExuk79Dm7CJCw7sfUWi2qWJSbRy"); -static const string strAddressBad("Xta1praZQjyELweyMByXyiREw1ZRsjXzVP"); +static const std::string strAddressBad("Xta1praZQjyELweyMByXyiREw1ZRsjXzVP"); #ifdef KEY_TESTS_DUMPINFO @@ -37,7 +35,7 @@ void dumpKeyInfo(uint256 privkey) CKey key; key.resize(32); memcpy(&secret[0], &privkey, 32); - vector sec; + std::vector sec; sec.resize(32); memcpy(&sec[0], &secret[0], 32); printf(" * secret (hex): %s\n", HexStr(sec).c_str()); @@ -51,7 +49,7 @@ void dumpKeyInfo(uint256 privkey) printf(" * secret (base58): %s\n", bsecret.ToString().c_str()); CKey key; key.SetSecret(secret, fCompressed); - vector vchPubKey = key.GetPubKey(); + std::vector vchPubKey = key.GetPubKey(); printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str()); printf(" * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str()); } @@ -111,12 +109,12 @@ BOOST_AUTO_TEST_CASE(key_test1) for (int n=0; n<16; n++) { - string strMsg = strprintf("Very secret message %i: 11", n); + std::string strMsg = strprintf("Very secret message %i: 11", n); uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); // normal signatures - vector sign1, sign2, sign1C, sign2C; + std::vector sign1, sign2, sign1C, sign2C; BOOST_CHECK(key1.Sign (hashMsg, sign1)); BOOST_CHECK(key2.Sign (hashMsg, sign2)); @@ -145,7 +143,7 @@ BOOST_AUTO_TEST_CASE(key_test1) // compact signatures (with key recovery) - vector csign1, csign2, csign1C, csign2C; + std::vector csign1, csign2, csign1C, csign2C; BOOST_CHECK(key1.SignCompact (hashMsg, csign1)); BOOST_CHECK(key2.SignCompact (hashMsg, csign2)); @@ -168,7 +166,7 @@ BOOST_AUTO_TEST_CASE(key_test1) // test deterministic signing std::vector detsig, detsigc; - string strMsg = "Very deterministic message"; + std::string strMsg = "Very deterministic message"; uint256 hashMsg = Hash(strMsg.begin(), strMsg.end()); BOOST_CHECK(key1.Sign(hashMsg, detsig)); BOOST_CHECK(key1C.Sign(hashMsg, detsigc)); diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 32a08fbcc64a..397442d03fcc 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -119,7 +119,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest) { CTxMemPool pool(CFeeRate(0)); TestMemPoolEntryHelper entry; - entry.hadNoDependencies = true; /* 3rd highest fee */ CMutableTransaction tx1 = CMutableTransaction(); @@ -322,7 +321,6 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) { CTxMemPool pool(CFeeRate(0)); TestMemPoolEntryHelper entry; - entry.hadNoDependencies = true; /* 3rd highest fee */ CMutableTransaction tx1 = CMutableTransaction(); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index f29e8bac784d..d862f5ba2831 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -229,7 +229,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; std::shared_ptr shared_pblock = std::make_shared(*pblock); - BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL, NULL)); + BOOST_CHECK(ProcessNewBlock(chainparams, shared_pblock, true, NULL)); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index d010a0695738..2c2f76323813 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -17,14 +17,12 @@ #include #include -using namespace std; - -typedef vector valtype; +typedef std::vector valtype; BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript -sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) +sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, int whichIn) { uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL); @@ -32,7 +30,7 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, result << OP_0; // CHECKMULTISIG bug workaround BOOST_FOREACH(const CKey &key, keys) { - vector vchSig; + std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); result << vchSig; @@ -74,7 +72,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify) txTo[i].vout[0].nValue = 1; } - vector keys; + std::vector keys; CScript s; // Test a AND b: @@ -199,7 +197,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) partialkeystore.AddKey(key[0]); { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; @@ -212,7 +210,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK(!IsMine(emptykeystore, s)); } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; @@ -225,7 +223,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK(!IsMine(emptykeystore, s)); } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; @@ -238,13 +236,13 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK(!IsMine(partialkeystore, s)); } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK(Solver(s, whichType, solutions)); BOOST_CHECK_EQUAL(solutions.size(), 4U); - vector addrs; + std::vector addrs; int nRequired; BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(addrs[0] == keyaddr[0]); @@ -255,7 +253,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_CHECK(!IsMine(partialkeystore, s)); } { - vector solutions; + std::vector solutions; txnouttype whichType; CScript s; s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 69ce556f5be9..b401d809e00c 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -12,8 +12,6 @@ #include "netbase.h" #include "chainparams.h" -using namespace std; - class CAddrManSerializationMock : public CAddrMan { public: @@ -68,7 +66,7 @@ CDataStream AddrmanToStream(CAddrManSerializationMock& _addrman) ssPeersIn << FLATDATA(Params().MessageStart()); ssPeersIn << _addrman; std::string str = ssPeersIn.str(); - vector vchData(str.begin(), str.end()); + std::vector vchData(str.begin(), str.end()); return CDataStream(vchData, SER_DISK, CLIENT_VERSION); } diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 1f96eb4468fc..4fe47f937a4d 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -11,8 +11,6 @@ #include #include -using namespace std; - BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup) static CNetAddr ResolveIP(const char* ip) @@ -65,9 +63,9 @@ BOOST_AUTO_TEST_CASE(netbase_properties) } -bool static TestSplitHost(string test, string host, int port) +bool static TestSplitHost(std::string test, std::string host, int port) { - string hostOut; + std::string hostOut; int portOut = -1; SplitHostPort(test, portOut, hostOut); return hostOut == host && port == portOut; @@ -92,7 +90,7 @@ BOOST_AUTO_TEST_CASE(netbase_splithost) BOOST_CHECK(TestSplitHost("", "", -1)); } -bool static TestParse(string src, string canon) +bool static TestParse(std::string src, std::string canon) { CService addr(LookupNumeric(src.c_str(), 65535)); return canon == addr.ToString(); diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 82f5efa9b230..81d279f66f59 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -17,8 +17,6 @@ #include #include -using namespace std; - class CPartialMerkleTreeTester : public CPartialMerkleTree { public: diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index d978d49b0206..a602b28b4738 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -11,8 +11,6 @@ #include -using namespace std; - BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* Test calculation of next difficulty target with DGW */ diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index a916619fd875..f3740c1d64b3 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -169,6 +169,19 @@ class prevector_tester { pre_vector.swap(pre_vector_alt); test(); } + + void move() { + real_vector = std::move(real_vector_alt); + real_vector_alt.clear(); + pre_vector = std::move(pre_vector_alt); + pre_vector_alt.clear(); + } + + void copy() { + real_vector = real_vector_alt; + pre_vector = pre_vector_alt; + } + ~prevector_tester() { BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: " << rand_cache.Rz @@ -240,9 +253,15 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) if (((r >> 21) % 512) == 12) { test.assign(insecure_rand() % 32, insecure_rand()); } - if (((r >> 15) % 64) == 3) { + if (((r >> 15) % 8) == 3) { test.swap(); } + if (((r >> 15) % 16) == 8) { + test.copy(); + } + if (((r >> 15) % 32) == 18) { + test.move(); + } } } } diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp new file mode 100644 index 000000000000..d14272f04d95 --- /dev/null +++ b/src/test/raii_event_tests.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include "support/events.h" + +#include "test/test_dash.h" + +#include + +#include + +static std::map tags; +static std::map orders; +static uint16_t tagSequence = 0; + +static void* tag_malloc(size_t sz) { + void* mem = malloc(sz); + if (!mem) return mem; + tags[mem]++; + orders[mem] = tagSequence++; + return mem; +} + +static void tag_free(void* mem) { + tags[mem]--; + orders[mem] = tagSequence++; + free(mem); +} + +BOOST_FIXTURE_TEST_SUITE(raii_event_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(raii_event_creation) +{ + event_set_mem_functions(tag_malloc, realloc, tag_free); + + void* base_ptr = NULL; + { + auto base = obtain_event_base(); + base_ptr = (void*)base.get(); + BOOST_CHECK(tags[base_ptr] == 1); + } + BOOST_CHECK(tags[base_ptr] == 0); + + void* event_ptr = NULL; + { + auto base = obtain_event_base(); + auto event = obtain_event(base.get(), -1, 0, NULL, NULL); + + base_ptr = (void*)base.get(); + event_ptr = (void*)event.get(); + + BOOST_CHECK(tags[base_ptr] == 1); + BOOST_CHECK(tags[event_ptr] == 1); + } + BOOST_CHECK(tags[base_ptr] == 0); + BOOST_CHECK(tags[event_ptr] == 0); + + event_set_mem_functions(malloc, realloc, free); +} + +BOOST_AUTO_TEST_CASE(raii_event_order) +{ + event_set_mem_functions(tag_malloc, realloc, tag_free); + + void* base_ptr = NULL; + void* event_ptr = NULL; + { + auto base = obtain_event_base(); + auto event = obtain_event(base.get(), -1, 0, NULL, NULL); + + base_ptr = (void*)base.get(); + event_ptr = (void*)event.get(); + + // base should have allocated before event + BOOST_CHECK(orders[base_ptr] < orders[event_ptr]); + } + // base should be freed after event + BOOST_CHECK(orders[base_ptr] > orders[event_ptr]); + + event_set_mem_functions(malloc, realloc, free); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 7b4460c57f88..5b99cec5582f 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -16,13 +16,11 @@ #include -using namespace std; - -UniValue CallRPC(string args) +UniValue CallRPC(std::string args) { - vector vArgs; + std::vector vArgs; boost::split(vArgs, args, boost::is_any_of(" \t")); - string strMethod = vArgs[0]; + std::string strMethod = vArgs[0]; vArgs.erase(vArgs.begin()); JSONRPCRequest request; request.strMethod = strMethod; @@ -35,7 +33,7 @@ UniValue CallRPC(string args) return result; } catch (const UniValue& objError) { - throw runtime_error(find_value(objError, "message").get_str()); + throw std::runtime_error(find_value(objError, "message").get_str()); } } @@ -47,41 +45,41 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams) // Test raw transaction API argument handling UniValue r; - BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error); - BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("getrawtransaction a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed not_int"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction null null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction not_array"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] []"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction {} {}"), std::runtime_error); BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [] {}")); - BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [] {} extra"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error); - string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; - BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx)); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), std::runtime_error); + std::string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000"; + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx)); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1); BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0); - BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error); + BOOST_CHECK_THROW(r = CallRPC(std::string("decoderawtransaction ")+rawtx+" extra"), std::runtime_error); - BOOST_CHECK_THROW(CallRPC("signrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx)); - BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY")); - BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY")); - BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), std::runtime_error); + BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx)); + BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY")); + BOOST_CHECK_NO_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY")); + BOOST_CHECK_THROW(CallRPC(std::string("signrawtransaction ")+rawtx+" null null badenum"), std::runtime_error); // Only check failure cases for sendrawtransaction, there's no network to send to... - BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), runtime_error); - BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), runtime_error); - BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), runtime_error); - BOOST_CHECK_THROW(CallRPC(string("sendrawtransaction ")+rawtx+" extra"), runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction null"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("sendrawtransaction DEADBEEF"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC(std::string("sendrawtransaction ")+rawtx+" extra"), std::runtime_error); } BOOST_AUTO_TEST_CASE(rpc_togglenetwork) @@ -110,18 +108,18 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign) { UniValue r; // input is a 1-of-2 multisig (so is output): - string prevout = + std::string prevout = "[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\"," "\"vout\":1,\"scriptPubKey\":\"a914b10c9df5f7edf436c697f02f1efdba4cf399615187\"," "\"redeemScript\":\"512103debedc17b3df2badbcdd86d5feb4562b86fe182e5998abd8bcd4f122c6155b1b21027e940bb73ab8732bfdf7f9216ecefca5b94d6df834e77e108f68e66f126044c052ae\"}]"; - r = CallRPC(string("createrawtransaction ")+prevout+" "+ + r = CallRPC(std::string("createrawtransaction ")+prevout+" "+ "{\"7iYoULd4BAqRsRt1UbD5qqna88JvKRU3SL\":11}"); - string notsigned = r.get_str(); - string privkey1 = "\"XEwTRsCX3CiWSQf8YmKMTeb84KyTbibkUv9mDTZHQ5MwuKG2ZzES\""; - string privkey2 = "\"XDmZ7LjGd94Q81eUBjb2h6uV5Y14s7fmeXWEGYabfBJP8RVpprBu\""; - r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]"); + std::string notsigned = r.get_str(); + std::string privkey1 = "\"XEwTRsCX3CiWSQf8YmKMTeb84KyTbibkUv9mDTZHQ5MwuKG2ZzES\""; + std::string privkey2 = "\"XDmZ7LjGd94Q81eUBjb2h6uV5Y14s7fmeXWEGYabfBJP8RVpprBu\""; + r = CallRPC(std::string("signrawtransaction ")+notsigned+" "+prevout+" "+"[]"); BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == false); - r = CallRPC(string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]"); + r = CallRPC(std::string("signrawtransaction ")+notsigned+" "+prevout+" "+"["+privkey1+","+privkey2+"]"); BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true); } @@ -133,11 +131,11 @@ BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}")); // Key not "data" (bad address) - BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), std::runtime_error); // Bad hex encoding of data output - BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), runtime_error); - BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), std::runtime_error); // Data 81 bytes long BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081\"}")); @@ -241,23 +239,23 @@ BOOST_AUTO_TEST_CASE(json_parse_errors) BOOST_AUTO_TEST_CASE(rpc_ban) { - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + UniValue r; - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add"))); - BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.0:8334")), std::runtime_error); //portnumber for setban not allowed + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); UniValue ar = r.get_array(); UniValue o1 = ar[0].get_obj(); UniValue adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32"); - BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0 remove"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 1607731200 true"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); @@ -265,10 +263,10 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24"); BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/24 add 200"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); @@ -279,43 +277,43 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK(banned_until.get_int64()-now <= 200); // must throw an exception because 127.0.0.1 is in already banned suubnet range - BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error); + BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0/24 remove"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add"))); - BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 127.0.0.0/255.255.0.0 add"))); + BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.1.1 add")), std::runtime_error); - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); BOOST_CHECK_EQUAL(ar.size(), 0); - BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); //invalid IP + BOOST_CHECK_THROW(r = CallRPC(std::string("setban test add")), std::runtime_error); //invalid IP //IPv6 tests - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128"); - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30"); - BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add"))); - BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned"))); + BOOST_CHECK_NO_THROW(CallRPC(std::string("clearbanned"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add"))); + BOOST_CHECK_NO_THROW(r = CallRPC(std::string("listbanned"))); ar = r.get_array(); o1 = ar[0].get_obj(); adr = find_value(o1, "address"); @@ -348,8 +346,8 @@ BOOST_AUTO_TEST_CASE(rpc_convert_values_generatetoaddress) BOOST_AUTO_TEST_CASE(rpc_sentinel_ping) { BOOST_CHECK_NO_THROW(CallRPC("sentinelping 1.0.2")); - BOOST_CHECK_THROW(CallRPC("sentinelping"), runtime_error); - BOOST_CHECK_THROW(CallRPC("sentinelping 2"), bad_cast); + BOOST_CHECK_THROW(CallRPC("sentinelping"), std::runtime_error); + BOOST_CHECK_THROW(CallRPC("sentinelping 2"), std::bad_cast); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index fa41eac6e780..1521bb5c2641 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -16,8 +16,6 @@ #include -using namespace std; - // Helpers: static std::vector Serialize(const CScript& s) @@ -79,7 +77,7 @@ BOOST_AUTO_TEST_CASE(sign) } CMutableTransaction txFrom; // Funding transaction: - string reason; + std::string reason; txFrom.vout.resize(8); for (int i = 0; i < 4; i++) { @@ -176,7 +174,7 @@ BOOST_AUTO_TEST_CASE(set) } CMutableTransaction txFrom; // Funding transaction: - string reason; + std::string reason; txFrom.vout.resize(4); for (int i = 0; i < 4; i++) { @@ -261,7 +259,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) CCoinsViewCache coins(&coinsDummy); CBasicKeyStore keystore; CKey key[6]; - vector keys; + std::vector keys; for (int i = 0; i < 6; i++) { key[i].MakeNewKey(true); @@ -333,8 +331,8 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) // SignSignature doesn't know how to sign these. We're // not testing validating signatures, so just create // dummy signatures that DO include the correct P2SH scripts: - txTo.vin[3].scriptSig << OP_11 << OP_11 << vector(oneAndTwo.begin(), oneAndTwo.end()); - txTo.vin[4].scriptSig << vector(fifteenSigops.begin(), fifteenSigops.end()); + txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector(oneAndTwo.begin(), oneAndTwo.end()); + txTo.vin[4].scriptSig << std::vector(fifteenSigops.begin(), fifteenSigops.end()); BOOST_CHECK(::AreInputsStandard(txTo, coins)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] @@ -347,7 +345,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout.n = 5; txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd1.vin[0].scriptSig << vector(sixteenSigops.begin(), sixteenSigops.end()); + txToNonStd1.vin[0].scriptSig << std::vector(sixteenSigops.begin(), sixteenSigops.end()); BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); @@ -359,7 +357,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout.n = 6; txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd2.vin[0].scriptSig << vector(twentySigops.begin(), twentySigops.end()); + txToNonStd2.vin[0].scriptSig << std::vector(twentySigops.begin(), twentySigops.end()); BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 9cf287fdb8e9..f7267ade0d93 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -28,15 +28,13 @@ #include -using namespace std; - // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; -unsigned int ParseScriptFlags(string strFlags); -string FormatScriptFlags(unsigned int flags); +unsigned int ParseScriptFlags(std::string strFlags); +std::string FormatScriptFlags(unsigned int flags); UniValue read_json(const std::string& jsondata) @@ -709,7 +707,7 @@ BOOST_AUTO_TEST_CASE(script_json_test) for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); if (test.size() < 4) // Allow size > 3; extra stuff ignored (useful for comments) { if (test.size() != 1) { @@ -717,9 +715,9 @@ BOOST_AUTO_TEST_CASE(script_json_test) } continue; } - string scriptSigString = test[0].get_str(); + std::string scriptSigString = test[0].get_str(); CScript scriptSig = ParseScript(scriptSigString); - string scriptPubKeyString = test[1].get_str(); + std::string scriptPubKeyString = test[1].get_str(); CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); int scriptError = ParseScriptError(test[3].get_str()); @@ -738,21 +736,21 @@ BOOST_AUTO_TEST_CASE(script_PushData) static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; ScriptError err; - vector > directStack; + std::vector > directStack; BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - vector > pushdata1Stack; + std::vector > pushdata1Stack; BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - vector > pushdata2Stack; + std::vector > pushdata2Stack; BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - vector > pushdata4Stack; + std::vector > pushdata4Stack; BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); @@ -775,7 +773,7 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac result << OP_0; BOOST_FOREACH(const CKey &key, keys) { - vector vchSig; + std::vector vchSig; BOOST_CHECK(key.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); result << vchSig; @@ -893,8 +891,8 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) { // Test the CombineSignatures function CBasicKeyStore keystore; - vector keys; - vector pubkeys; + std::vector keys; + std::vector pubkeys; for (int i = 0; i < 3; i++) { CKey key; @@ -939,7 +937,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: - scriptSigCopy = CScript() << OP_0 << vector(pkSingle.begin(), pkSingle.end()); + scriptSigCopy = CScript() << OP_0 << std::vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig); BOOST_CHECK(combined == scriptSig); combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy); @@ -955,15 +953,15 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_CHECK(combined == scriptSig); // A couple of partially-signed versions: - vector sig1; + std::vector sig1; uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); - vector sig2; + std::vector sig2; uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); - vector sig3; + std::vector sig3; uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); @@ -1037,9 +1035,9 @@ BOOST_AUTO_TEST_CASE(script_GetScriptAsm) BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_NOP2)); BOOST_CHECK_EQUAL("OP_CHECKLOCKTIMEVERIFY", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); - string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090"); - string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); - vector vchPubKey = ToByteVector(ParseHex(pubKey)); + std::string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090"); + std::string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); + std::vector vchPubKey = ToByteVector(ParseHex(pubKey)); BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 91a2c0d08540..d0e43159fb7c 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -10,7 +10,6 @@ #include #include -using namespace std; BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) @@ -227,7 +226,7 @@ BOOST_AUTO_TEST_CASE(varints_bitpatterns) BOOST_AUTO_TEST_CASE(compactsize) { CDataStream ss(SER_DISK, 0); - vector::size_type i, j; + std::vector::size_type i, j; for (i = 1; i <= MAX_SIZE; i *= 2) { @@ -260,7 +259,7 @@ BOOST_AUTO_TEST_CASE(noncanonical) // Write some non-canonical CompactSize encodings, and // make sure an exception is thrown when read back. CDataStream ss(SER_DISK, 0); - vector::size_type n; + std::vector::size_type n; // zero encoded with three bytes: ss.write("\xfd\x00\x00", 3); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 045dacd0b881..ae79bec4be81 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -14,8 +14,6 @@ #include #include -using namespace std; - // Helpers: static std::vector Serialize(const CScript& s) diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 2605fe3b051e..186961aa3aae 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -9,8 +9,7 @@ #include // for 'operator+=()' #include #include - -using namespace std; + using namespace boost::assign; // bring 'operator+=()' into scope BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup) diff --git a/src/test/test_dash.cpp b/src/test/test_dash.cpp index afc0cf646641..c4281c2b394e 100644 --- a/src/test/test_dash.cpp +++ b/src/test/test_dash.cpp @@ -20,6 +20,7 @@ #include "ui_interface.h" #include "rpc/server.h" #include "rpc/register.h" +#include "script/sigcache.h" #include "test/testutil.h" @@ -40,6 +41,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) ECC_Start(); SetupEnvironment(); SetupNetworking(); + InitSignatureCache(); fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; SelectParams(chainName); @@ -61,7 +63,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_dash_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); + ForceSetArg("-datadir", pathTemp.string()); mempool.setSanityCheck(1.0); pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); @@ -127,7 +129,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; std::shared_ptr shared_pblock = std::make_shared(block); - ProcessNewBlock(chainparams, shared_pblock, true, NULL, NULL); + ProcessNewBlock(chainparams, shared_pblock, true, NULL); CBlock result = block; return result; @@ -140,12 +142,11 @@ TestChain100Setup::~TestChain100Setup() CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) { CTransaction txn(tx); - bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies; // Hack to assume either its completely dependent on other mempool txs or not at all - CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; + CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : 0; - return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight, - hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); + return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight, + inChainValue, spendsCoinbase, sigOpCount, lp); } void Shutdown(void* parg) diff --git a/src/test/test_dash.h b/src/test/test_dash.h index 5323b9637862..c1f6b593aaa2 100644 --- a/src/test/test_dash.h +++ b/src/test/test_dash.h @@ -71,14 +71,13 @@ struct TestMemPoolEntryHelper int64_t nTime; double dPriority; unsigned int nHeight; - bool hadNoDependencies; bool spendsCoinbase; unsigned int sigOpCount; LockPoints lp; TestMemPoolEntryHelper() : nFee(0), nTime(0), dPriority(0.0), nHeight(1), - hadNoDependencies(false), spendsCoinbase(false), sigOpCount(1) { } + spendsCoinbase(false), sigOpCount(4) { } CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = NULL); @@ -87,7 +86,6 @@ struct TestMemPoolEntryHelper TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; } TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; } TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; } - TestMemPoolEntryHelper &HadNoDependencies(bool _hnd) { hadNoDependencies = _hnd; return *this; } TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; } TestMemPoolEntryHelper &SigOps(unsigned int _sigops) { sigOpCount = _sigops; return *this; } }; diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp index 70a700081824..d0c4748b8a73 100644 --- a/src/test/timedata_tests.cpp +++ b/src/test/timedata_tests.cpp @@ -7,8 +7,6 @@ #include -using namespace std; - BOOST_FIXTURE_TEST_SUITE(timedata_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(util_MedianFilter) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 9c124967d652..da227442d25e 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -33,31 +33,31 @@ using namespace std; // In script_tests.cpp extern UniValue read_json(const std::string& jsondata); -static std::map mapFlagNames = boost::assign::map_list_of - (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) - (string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH) - (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC) - (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG) - (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S) - (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY) - (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA) - (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) - (string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) - (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK) - (string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL) - (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) - (string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY); - -unsigned int ParseScriptFlags(string strFlags) +static std::map mapFlagNames = boost::assign::map_list_of + (std::string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) + (std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH) + (std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC) + (std::string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG) + (std::string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S) + (std::string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY) + (std::string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA) + (std::string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY) + (std::string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) + (std::string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK) + (std::string("NULLFAIL"), (unsigned int)SCRIPT_VERIFY_NULLFAIL) + (std::string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) + (std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY); + +unsigned int ParseScriptFlags(std::string strFlags) { if (strFlags.empty()) { return 0; } unsigned int flags = 0; - vector words; + std::vector words; boost::algorithm::split(words, strFlags, boost::algorithm::is_any_of(",")); - BOOST_FOREACH(string word, words) + BOOST_FOREACH(std::string word, words) { if (!mapFlagNames.count(word)) BOOST_ERROR("Bad test: unknown verification flag '" << word << "'"); @@ -67,13 +67,13 @@ unsigned int ParseScriptFlags(string strFlags) return flags; } -string FormatScriptFlags(unsigned int flags) +std::string FormatScriptFlags(unsigned int flags) { if (flags == 0) { return ""; } - string ret; - std::map::const_iterator it = mapFlagNames.begin(); + std::string ret; + std::map::const_iterator it = mapFlagNames.begin(); while (it != mapFlagNames.end()) { if (flags & it->second) { ret += it->first + ","; @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) ScriptError err; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); if (test[0].isArray()) { if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) continue; } - map mapprevOutScriptPubKeys; + std::map mapprevOutScriptPubKeys; UniValue inputs = test[0].get_array(); bool fValid = true; for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) continue; } - string transaction = test[1].get_str(); + std::string transaction = test[1].get_str(); CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx(deserialize, stream); @@ -173,7 +173,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) ScriptError err; for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; - string strTest = test.write(); + std::string strTest = test.write(); if (test[0].isArray()) { if (test.size() != 3 || !test[1].isStr() || !test[2].isStr()) @@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) continue; } - map mapprevOutScriptPubKeys; + std::map mapprevOutScriptPubKeys; UniValue inputs = test[0].get_array(); bool fValid = true; for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) { @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) continue; } - string transaction = test[1].get_str(); + std::string transaction = test[1].get_str(); CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx(deserialize, stream); @@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) { // Random real transaction (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) unsigned char ch[] = {0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; - vector vch(ch, ch + sizeof(ch) -1); + std::vector vch(ch, ch + sizeof(ch) -1); CDataStream stream(vch, SER_DISK, CLIENT_VERSION); CMutableTransaction tx; stream >> tx; @@ -331,7 +331,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) key.MakeNewKey(true); t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - string reason; + std::string reason; BOOST_CHECK(IsStandardTx(t, reason)); // Check dust with default relay fee: diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 36d4271b6be7..4209d191d8f8 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -23,7 +23,7 @@ ToMemPool(CMutableTransaction& tx) LOCK(cs_main); CValidationState state; - return AcceptToMemoryPool(mempool, state, tx, false, NULL, true, 0); + return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, NULL, true, 0); } BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index de1cd7e2c4a1..a6ac201a99a3 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -12,8 +12,6 @@ #include -using namespace std; - BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(univalue_constructor) @@ -53,7 +51,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor) BOOST_CHECK(v7.isNum()); BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21"); - string vs("yawn"); + std::string vs("yawn"); UniValue v8(vs); BOOST_CHECK(v8.isStr()); BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); @@ -69,41 +67,41 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck) UniValue v1; BOOST_CHECK(v1.setNumStr("1")); BOOST_CHECK(v1.isNum()); - BOOST_CHECK_THROW(v1.get_bool(), runtime_error); + BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error); UniValue v2; BOOST_CHECK(v2.setBool(true)); BOOST_CHECK_EQUAL(v2.get_bool(), true); - BOOST_CHECK_THROW(v2.get_int(), runtime_error); + BOOST_CHECK_THROW(v2.get_int(), std::runtime_error); UniValue v3; BOOST_CHECK(v3.setNumStr("32482348723847471234")); - BOOST_CHECK_THROW(v3.get_int64(), runtime_error); + BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error); BOOST_CHECK(v3.setNumStr("1000")); BOOST_CHECK_EQUAL(v3.get_int64(), 1000); UniValue v4; BOOST_CHECK(v4.setNumStr("2147483648")); BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648ULL); - BOOST_CHECK_THROW(v4.get_int(), runtime_error); + BOOST_CHECK_THROW(v4.get_int(), std::runtime_error); BOOST_CHECK(v4.setNumStr("1000")); BOOST_CHECK_EQUAL(v4.get_int(), 1000); - BOOST_CHECK_THROW(v4.get_str(), runtime_error); + BOOST_CHECK_THROW(v4.get_str(), std::runtime_error); BOOST_CHECK_EQUAL(v4.get_real(), 1000); - BOOST_CHECK_THROW(v4.get_array(), runtime_error); - BOOST_CHECK_THROW(v4.getKeys(), runtime_error); - BOOST_CHECK_THROW(v4.getValues(), runtime_error); - BOOST_CHECK_THROW(v4.get_obj(), runtime_error); + BOOST_CHECK_THROW(v4.get_array(), std::runtime_error); + BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error); + BOOST_CHECK_THROW(v4.getValues(), std::runtime_error); + BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error); UniValue v5; BOOST_CHECK(v5.read("[true, 10]")); BOOST_CHECK_NO_THROW(v5.get_array()); std::vector vals = v5.getValues(); - BOOST_CHECK_THROW(vals[0].get_int(), runtime_error); + BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error); BOOST_CHECK_EQUAL(vals[0].get_bool(), true); BOOST_CHECK_EQUAL(vals[1].get_int(), 10); - BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error); + BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error); } BOOST_AUTO_TEST_CASE(univalue_set) @@ -172,13 +170,13 @@ BOOST_AUTO_TEST_CASE(univalue_array) UniValue v((int64_t)1023LL); BOOST_CHECK(arr.push_back(v)); - string vStr("zippy"); + std::string vStr("zippy"); BOOST_CHECK(arr.push_back(vStr)); const char *s = "pippy"; BOOST_CHECK(arr.push_back(s)); - vector vec; + std::vector vec; v.setStr("boing"); vec.push_back(v); @@ -206,7 +204,7 @@ BOOST_AUTO_TEST_CASE(univalue_array) BOOST_AUTO_TEST_CASE(univalue_object) { UniValue obj(UniValue::VOBJ); - string strKey, strVal; + std::string strKey, strVal; UniValue v; strKey = "age"; @@ -266,7 +264,7 @@ BOOST_AUTO_TEST_CASE(univalue_object) BOOST_CHECK(!obj.exists("nyuknyuknyuk")); - map objTypes; + std::map objTypes; objTypes["age"] = UniValue::VNUM; objTypes["first"] = UniValue::VSTR; objTypes["last"] = UniValue::VSTR; @@ -294,7 +292,7 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite) UniValue v; BOOST_CHECK(v.read(json1)); - string strJson1(json1); + std::string strJson1(json1); BOOST_CHECK(v.read(strJson1)); BOOST_CHECK(v.isArray()); @@ -333,4 +331,3 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite) } BOOST_AUTO_TEST_SUITE_END() - diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 15135b7bec1b..00dc73ac788f 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -17,7 +17,7 @@ #include -using namespace std; +extern std::map mapArgs; BOOST_FIXTURE_TEST_SUITE(util_tests, BasicTestingSetup) @@ -115,13 +115,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters) // -a, -b and -ccc end up in map, -d ignored because it is after // a non-option argument (non-GNU option parsing) BOOST_CHECK(mapArgs.size() == 3 && mapMultiArgs.size() == 3); - BOOST_CHECK(mapArgs.count("-a") && mapArgs.count("-b") && mapArgs.count("-ccc") - && !mapArgs.count("f") && !mapArgs.count("-d")); + BOOST_CHECK(IsArgSet("-a") && IsArgSet("-b") && IsArgSet("-ccc") + && !IsArgSet("f") && !IsArgSet("-d")); BOOST_CHECK(mapMultiArgs.count("-a") && mapMultiArgs.count("-b") && mapMultiArgs.count("-ccc") && !mapMultiArgs.count("f") && !mapMultiArgs.count("-d")); BOOST_CHECK(mapArgs["-a"] == "" && mapArgs["-ccc"] == "multiple"); - BOOST_CHECK(mapMultiArgs["-ccc"].size() == 2); + BOOST_CHECK(mapMultiArgs.at("-ccc").size() == 2); } BOOST_AUTO_TEST_CASE(util_GetArg) @@ -571,14 +571,14 @@ BOOST_AUTO_TEST_CASE(version_info_helper) BOOST_CHECK(StringVersionToInt("1.1.1") == 0x010101); BOOST_CHECK(IntVersionToString(0x010101) == "1.1.1"); - BOOST_CHECK_THROW(StringVersionToInt("1.1.hgdghfgf"), bad_cast); - BOOST_CHECK_THROW(StringVersionToInt("1.1"), bad_cast); - BOOST_CHECK_THROW(StringVersionToInt("1.1.1f"), bad_cast); - BOOST_CHECK_THROW(StringVersionToInt("1.1.1000"), bad_cast); - BOOST_CHECK_THROW(StringVersionToInt("10"), bad_cast); - BOOST_CHECK_THROW(StringVersionToInt("1.1.1.1"), bad_cast); - BOOST_CHECK_THROW(IntVersionToString(0x01010101), bad_cast); - BOOST_CHECK_THROW(IntVersionToString(0), bad_cast); + BOOST_CHECK_THROW(StringVersionToInt("1.1.hgdghfgf"), std::bad_cast); + BOOST_CHECK_THROW(StringVersionToInt("1.1"), std::bad_cast); + BOOST_CHECK_THROW(StringVersionToInt("1.1.1f"), std::bad_cast); + BOOST_CHECK_THROW(StringVersionToInt("1.1.1000"), std::bad_cast); + BOOST_CHECK_THROW(StringVersionToInt("10"), std::bad_cast); + BOOST_CHECK_THROW(StringVersionToInt("1.1.1.1"), std::bad_cast); + BOOST_CHECK_THROW(IntVersionToString(0x01010101), std::bad_cast); + BOOST_CHECK_THROW(IntVersionToString(0), std::bad_cast); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/timedata.cpp b/src/timedata.cpp index 774eff51a832..406542a5261f 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -13,6 +13,7 @@ #include "ui_interface.h" #include "util.h" #include "utilstrencodings.h" +#include "warnings.h" #include @@ -103,8 +104,8 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) if (!fMatch) { fDone = true; - string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME)); - strMiscWarning = strMessage; + std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), _(PACKAGE_NAME)); + SetMiscWarning(strMessage); uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 94713adf14ee..3c64a8db8116 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -21,22 +21,22 @@ using namespace std; -CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, +CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, - bool poolHasNoInputsOf, CAmount _inChainInputValue, + CAmount _inChainInputValue, bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp): - tx(MakeTransactionRef(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), - hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), + tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp) { - nTxSize = ::GetSerializeSize(_tx, SER_NETWORK, PROTOCOL_VERSION); - nModSize = _tx.CalculateModifiedSize(nTxSize); + nTxSize = ::GetSerializeSize(*_tx, SER_NETWORK, PROTOCOL_VERSION); + nModSize = _tx->CalculateModifiedSize(nTxSize); nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); nCountWithDescendants = 1; nSizeWithDescendants = nTxSize; nModFeesWithDescendants = nFee; - CAmount nValueIn = _tx.GetValueOut()+nFee; + CAmount nValueIn = tx->GetValueOut()+nFee; assert(inChainInputValue <= nValueIn); feeDelta = 0; @@ -381,7 +381,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) nTransactionsUpdated += n; } -bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate) +bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate) { // Add to memory pool without checking anything. // Used by main.cpp AcceptToMemoryPool(), which DOES do @@ -431,7 +431,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, nTransactionsUpdated++; totalTxSize += entry.GetTxSize(); - minerPolicyEstimator->processTransaction(entry, fCurrentEstimate); + minerPolicyEstimator->processTransaction(entry, validFeeEstimate); return true; } @@ -726,19 +726,20 @@ void CTxMemPool::removeConflicts(const CTransaction &tx) /** * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ -void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, - bool fCurrentEstimate) +void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight) { LOCK(cs); - std::vector entries; + std::vector entries; for (const auto& tx : vtx) { uint256 hash = tx->GetHash(); indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) - entries.push_back(*i); + entries.push_back(&*i); } + // Before the txs in the new block have been removed from the mempool, update policy estimates + minerPolicyEstimator->processBlock(nBlockHeight, entries); for (const auto& tx : vtx) { txiter it = mapTx.find(tx->GetHash()); @@ -750,8 +751,6 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne removeConflicts(*tx); ClearPrioritisation(tx->GetHash()); } - // After the txs in the new block have been removed from the mempool, update policy estimates - minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); lastRollingFeeUpdate = GetTime(); blockSinceLastRollingFeeBump = true; } @@ -1149,14 +1148,14 @@ int CTxMemPool::Expire(int64_t time) { return stage.size(); } -bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate) +bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool validFeeEstimate) { LOCK(cs); setEntries setAncestors; uint64_t nNoLimit = std::numeric_limits::max(); std::string dummy; CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy); - return addUnchecked(hash, entry, setAncestors, fCurrentEstimate); + return addUnchecked(hash, entry, setAncestors, validFeeEstimate); } void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add) @@ -1211,7 +1210,7 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const { rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife); lastRollingFeeUpdate = time; - if (rollingMinimumFeeRate < minReasonableRelayFee.GetFeePerK() / 2) { + if (rollingMinimumFeeRate < (double)minReasonableRelayFee.GetFeePerK() / 2) { rollingMinimumFeeRate = 0; return CFeeRate(0); } @@ -1277,4 +1276,11 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector* pvNoSpends LogPrint("mempool", "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString()); } +bool CTxMemPool::TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const { + LOCK(cs); + auto it = mapTx.find(txid); + return it == mapTx.end() || (it->GetCountWithAncestors() < chainLimit && + it->GetCountWithDescendants() < chainLimit); +} + SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits::max())), k1(GetRand(std::numeric_limits::max())) {} diff --git a/src/txmempool.h b/src/txmempool.h index 103be6dc87d5..63d16eedcbd1 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -91,7 +91,6 @@ class CTxMemPoolEntry int64_t nTime; //!< Local time when entering the mempool double entryPriority; //!< Priority when entering the mempool unsigned int entryHeight; //!< Chain height when entering the mempool - bool hadNoDependencies; //!< Not dependent on any other txs when it entered the mempool CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain bool spendsCoinbase; //!< keep track of transactions that spend a coinbase unsigned int sigOpCount; //!< Legacy sig ops plus P2SH sig op count @@ -114,10 +113,11 @@ class CTxMemPoolEntry unsigned int nSigOpCountWithAncestors; public: - CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, + CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, - bool poolHasNoInputsOf, CAmount _inChainInputValue, bool spendsCoinbase, + CAmount _inChainInputValue, bool spendsCoinbase, unsigned int nSigOps, LockPoints lp); + CTxMemPoolEntry(const CTxMemPoolEntry& other); const CTransaction& GetTx() const { return *this->tx; } @@ -131,7 +131,6 @@ class CTxMemPoolEntry size_t GetTxSize() const { return nTxSize; } int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return entryHeight; } - bool WasClearAtEntry() const { return hadNoDependencies; } unsigned int GetSigOpCount() const { return sigOpCount; } int64_t GetModifiedFee() const { return nFee + feeDelta; } size_t DynamicMemoryUsage() const { return nUsageSize; } @@ -547,8 +546,8 @@ class CTxMemPool // to track size/count of descendant transactions. First version of // addUnchecked can be used to have it call CalculateMemPoolAncestors(), and // then invoke the second version. - bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true); - bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true); + bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true); + bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true); void addAddressIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view); bool getAddressIndex(std::vector > &addresses, @@ -562,8 +561,7 @@ class CTxMemPool void removeRecursive(const CTransaction &tx); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx); - void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, - bool fCurrentEstimate = true); + void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight); void clear(); void _clear(); //lock free bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb); @@ -638,6 +636,9 @@ class CTxMemPool /** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */ int Expire(int64_t time); + /** Returns false if the transaction is in the mempool and not within the chain limit specified. */ + bool TransactionWithinChainLimit(const uint256& txid, size_t chainLimit) const; + unsigned long size() { LOCK(cs); diff --git a/src/util.cpp b/src/util.cpp index 2e4c723a0ff0..52f5a8b5de58 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -119,12 +119,14 @@ int nWalletBackups = 10; const char * const BITCOIN_CONF_FILENAME = "dash.conf"; const char * const BITCOIN_PID_FILENAME = "dashd.pid"; +CCriticalSection cs_args; map mapArgs; -map > mapMultiArgs; +static map > _mapMultiArgs; +const map >& mapMultiArgs = _mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugLog = true; -string strMiscWarning; + bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; bool fLogThreadNames = DEFAULT_LOGTHREADNAMES; @@ -262,22 +264,26 @@ bool LogAcceptCategory(const char* category) if (ptrCategory.get() == NULL) { - std::string strThreadName = GetThreadName(); - LogPrintf("debug turned on:\n"); - for (int i = 0; i < (int)mapMultiArgs["-debug"].size(); ++i) - LogPrintf(" thread %s category %s\n", strThreadName, mapMultiArgs["-debug"][i]); - const vector& categories = mapMultiArgs["-debug"]; - ptrCategory.reset(new set(categories.begin(), categories.end())); - // thread_specific_ptr automatically deletes the set when the thread ends. - // "dash" is a composite category enabling all Dash-related debug output - if(ptrCategory->count(string("dash"))) { - ptrCategory->insert(string("privatesend")); - ptrCategory->insert(string("instantsend")); - ptrCategory->insert(string("masternode")); - ptrCategory->insert(string("spork")); - ptrCategory->insert(string("keepass")); - ptrCategory->insert(string("mnpayments")); - ptrCategory->insert(string("gobject")); + if (mapMultiArgs.count("-debug")) { + std::string strThreadName = GetThreadName(); + LogPrintf("debug turned on:\n"); + for (int i = 0; i < (int)mapMultiArgs.at("-debug").size(); ++i) + LogPrintf(" thread %s category %s\n", strThreadName, mapMultiArgs.at("-debug")[i]); + const vector& categories = mapMultiArgs.at("-debug"); + ptrCategory.reset(new set(categories.begin(), categories.end())); + // thread_specific_ptr automatically deletes the set when the thread ends. + // "dash" is a composite category enabling all Dash-related debug output + if(ptrCategory->count(string("dash"))) { + ptrCategory->insert(string("privatesend")); + ptrCategory->insert(string("instantsend")); + ptrCategory->insert(string("masternode")); + ptrCategory->insert(string("spork")); + ptrCategory->insert(string("keepass")); + ptrCategory->insert(string("mnpayments")); + ptrCategory->insert(string("gobject")); + } + } else { + ptrCategory.reset(new set()); } } const set& setCategories = *ptrCategory.get(); @@ -403,8 +409,9 @@ static void InterpretNegativeSetting(std::string& strKey, std::string& strValue) void ParseParameters(int argc, const char* const argv[]) { + LOCK(cs_args); mapArgs.clear(); - mapMultiArgs.clear(); + _mapMultiArgs.clear(); for (int i = 1; i < argc; i++) { @@ -432,12 +439,19 @@ void ParseParameters(int argc, const char* const argv[]) InterpretNegativeSetting(str, strValue); mapArgs[str] = strValue; - mapMultiArgs[str].push_back(strValue); + _mapMultiArgs[str].push_back(strValue); } } +bool IsArgSet(const std::string& strArg) +{ + LOCK(cs_args); + return mapArgs.count(strArg); +} + std::string GetArg(const std::string& strArg, const std::string& strDefault) { + LOCK(cs_args); if (mapArgs.count(strArg)) return mapArgs[strArg]; return strDefault; @@ -445,6 +459,7 @@ std::string GetArg(const std::string& strArg, const std::string& strDefault) int64_t GetArg(const std::string& strArg, int64_t nDefault) { + LOCK(cs_args); if (mapArgs.count(strArg)) return atoi64(mapArgs[strArg]); return nDefault; @@ -452,6 +467,7 @@ int64_t GetArg(const std::string& strArg, int64_t nDefault) bool GetBoolArg(const std::string& strArg, bool fDefault) { + LOCK(cs_args); if (mapArgs.count(strArg)) return InterpretBool(mapArgs[strArg]); return fDefault; @@ -459,6 +475,7 @@ bool GetBoolArg(const std::string& strArg, bool fDefault) bool SoftSetArg(const std::string& strArg, const std::string& strValue) { + LOCK(cs_args); if (mapArgs.count(strArg)) return false; mapArgs[strArg] = strValue; @@ -473,6 +490,25 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue) return SoftSetArg(strArg, std::string("0")); } +void ForceSetArg(const std::string& strArg, const std::string& strValue) +{ + LOCK(cs_args); + mapArgs[strArg] = strValue; +} + +void ForceSetMultiArgs(const std::string& strArg, const std::vector& values) +{ + LOCK(cs_args); + _mapMultiArgs[strArg] = values; +} + +void ForceRemoveArg(const std::string& strArg) +{ + LOCK(cs_args); + mapArgs.erase(strArg); + _mapMultiArgs.erase(strArg); +} + static const int screenWidth = 79; static const int optIndent = 2; static const int msgIndent = 7; @@ -555,8 +591,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) if (!path.empty()) return path; - if (mapArgs.count("-datadir")) { - path = fs::system_complete(mapArgs["-datadir"]); + if (IsArgSet("-datadir")) { + path = fs::system_complete(GetArg("-datadir", "")); if (!fs::is_directory(path)) { path = ""; return path; @@ -572,36 +608,20 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) return path; } -static boost::filesystem::path backupsDirCached; -static CCriticalSection csBackupsDirCached; - -const boost::filesystem::path &GetBackupsDir() +boost::filesystem::path GetBackupsDir() { namespace fs = boost::filesystem; - LOCK(csBackupsDirCached); - - fs::path &backupsDir = backupsDirCached; - - if (!backupsDir.empty()) - return backupsDir; - - if (mapArgs.count("-walletbackupsdir")) { - backupsDir = fs::absolute(mapArgs["-walletbackupsdir"]); - // Path must exist - if (fs::is_directory(backupsDir)) return backupsDir; - // Fallback to default path if it doesn't - LogPrintf("%s: Warning: incorrect parameter -walletbackupsdir, path must exist! Using default path.\n", __func__); - strMiscWarning = _("Warning: incorrect parameter -walletbackupsdir, path must exist! Using default path."); - } - // Default path - backupsDir = GetDataDir() / "backups"; + if (!IsArgSet("-walletbackupsdir")) + return GetDataDir() / "backups"; - return backupsDir; + return fs::absolute(GetArg("-walletbackupsdir", "")); } void ClearDatadirCache() { + LOCK(csPathCached); + pathCached = boost::filesystem::path(); pathCachedNetSpecific = boost::filesystem::path(); } @@ -623,9 +643,7 @@ boost::filesystem::path GetMasternodeConfigFile() return pathConfigFile; } -void ReadConfigFile(const std::string& confPath, - map& mapSettingsRet, - map >& mapMultiSettingsRet) +void ReadConfigFile(const std::string& confPath) { boost::filesystem::ifstream streamConfig(GetConfigFile(confPath)); if (!streamConfig.good()){ @@ -636,18 +654,21 @@ void ReadConfigFile(const std::string& confPath, return; // Nothing to read, so just return } - set setOptions; - setOptions.insert("*"); - - for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { - // Don't overwrite existing settings so command line settings override dash.conf - string strKey = string("-") + it->string_key; - string strValue = it->value[0]; - InterpretNegativeSetting(strKey, strValue); - if (mapSettingsRet.count(strKey) == 0) - mapSettingsRet[strKey] = strValue; - mapMultiSettingsRet[strKey].push_back(strValue); + LOCK(cs_args); + set setOptions; + setOptions.insert("*"); + + for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) + { + // Don't overwrite existing settings so command line settings override dash.conf + string strKey = string("-") + it->string_key; + string strValue = it->value[0]; + InterpretNegativeSetting(strKey, strValue); + if (mapArgs.count(strKey) == 0) + mapArgs[strKey] = strValue; + _mapMultiArgs[strKey].push_back(strValue); + } } // If datadir is changed in .conf file: ClearDatadirCache(); diff --git a/src/util.h b/src/util.h index 5ed2912eac5d..739cc8a56c29 100644 --- a/src/util.h +++ b/src/util.h @@ -61,12 +61,11 @@ class CTranslationInterface boost::signals2::signal Translate; }; -extern std::map mapArgs; -extern std::map > mapMultiArgs; +extern const std::map >& mapMultiArgs; extern bool fDebug; extern bool fPrintToConsole; extern bool fPrintToDebugLog; -extern std::string strMiscWarning; + extern bool fLogTimestamps; extern bool fLogTimeMicros; extern bool fLogThreadNames; @@ -95,14 +94,15 @@ bool LogAcceptCategory(const char* category); /** Send a string to the log output */ int LogPrintStr(const std::string &str); -#define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) +#define LogPrint(category, ...) do { \ + if (LogAcceptCategory((category))) { \ + LogPrintStr(tfm::format(__VA_ARGS__)); \ + } \ +} while(0) -template -static inline int LogPrint(const char* category, const char* fmt, const Args&... args) -{ - if(!LogAcceptCategory(category)) return 0; \ - return LogPrintStr(tfm::format(fmt, args...)); -} +#define LogPrintf(...) do { \ + LogPrintStr(tfm::format(__VA_ARGS__)); \ +} while(0) template bool error(const char* fmt, const Args&... args) @@ -121,7 +121,7 @@ bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest); bool TryCreateDirectory(const boost::filesystem::path& p); boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); -const boost::filesystem::path &GetBackupsDir(); +boost::filesystem::path GetBackupsDir(); void ClearDatadirCache(); boost::filesystem::path GetConfigFile(const std::string& confPath); boost::filesystem::path GetMasternodeConfigFile(); @@ -129,7 +129,7 @@ boost::filesystem::path GetMasternodeConfigFile(); boost::filesystem::path GetPidFile(); void CreatePidFile(const boost::filesystem::path &path, pid_t pid); #endif -void ReadConfigFile(const std::string& confPath, std::map& mapSettingsRet, std::map >& mapMultiSettingsRet); +void ReadConfigFile(const std::string& confPath); #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif @@ -146,6 +146,14 @@ inline bool IsSwitchChar(char c) #endif } +/** + * Return true if the given argument has been manually set + * + * @param strArg Argument to get (e.g. "-foo") + * @return true if the argument has been set + */ +bool IsArgSet(const std::string& strArg); + /** * Return string argument or default value * @@ -191,6 +199,11 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue); */ bool SoftSetBoolArg(const std::string& strArg, bool fValue); +// Forces a arg setting, used only in testing +void ForceSetArg(const std::string& strArg, const std::string& strValue); +void ForceSetMultiArgs(const std::string& strArg, const std::vector& values); +void ForceRemoveArg(const std::string& strArg); + /** * Format a string to be used as group of options in help messages * diff --git a/src/validation.cpp b/src/validation.cpp index fcc167c0051e..87d9863f2c45 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -37,6 +37,7 @@ #include "utilstrencodings.h" #include "validationinterface.h" #include "versionbits.h" +#include "warnings.h" #include "instantx.h" #include "masternodeman.h" @@ -566,10 +567,23 @@ std::string FormatStateMessage(const CValidationState &state) state.GetRejectCode()); } -bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransaction& tx, bool fLimitFree, +static bool IsCurrentForFeeEstimation() +{ + AssertLockHeld(cs_main); + if (IsInitialBlockDownload()) + return false; + if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) + return false; + if (chainActive.Height() < pindexBestHeader->nHeight - 1) + return false; + return true; +} + +bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree, bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount& nAbsurdFee, std::vector& coins_to_uncache, bool fDryRun) { + const CTransaction& tx = *ptx; const uint256 hash = tx.GetHash(); AssertLockHeld(cs_main); if (pfMissingInputs) @@ -753,7 +767,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } } - CTxMemPoolEntry entry(tx, nFees, nAcceptTime, dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); + CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(), + inChainInputValue, fSpendsCoinbase, nSigOps, lp); unsigned int nSize = entry.GetTxSize(); // Check that the transaction doesn't have an excessive number of @@ -989,8 +1004,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C } pool.RemoveStaged(allConflicting, false); + // This transaction should only count for fee estimation if + // the node is not behind and it is not dependent on any other + // transactions in the mempool + bool validForFeeEstimation = IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); + // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); + pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation); // Add memory address index if (fAddressIndex) { @@ -1016,13 +1036,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C return true; } -bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, +bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit, const CAmount nAbsurdFee, bool fDryRun) { std::vector coins_to_uncache; bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, nAcceptTime, fOverrideMempoolLimit, nAbsurdFee, coins_to_uncache, fDryRun); if (!res || fDryRun) { - if(!res) LogPrint("mempool", "%s: %s %s\n", __func__, tx.GetHash().ToString(), state.GetRejectReason()); + if(!res) LogPrint("mempool", "%s: %s %s\n", __func__, tx->GetHash().ToString(), state.GetRejectReason()); BOOST_FOREACH(const COutPoint& hashTx, coins_to_uncache) pcoinsTip->Uncache(hashTx); } @@ -1032,7 +1052,7 @@ bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const return res; } -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool* pfMissingInputs, bool fOverrideMempoolLimit, const CAmount nAbsurdFee, bool fDryRun) { return AcceptToMemoryPoolWithTime(pool, state, tx, fLimitFree, pfMissingInputs, GetTime(), fOverrideMempoolLimit, nAbsurdFee, fDryRun); @@ -1327,8 +1347,6 @@ bool IsInitialBlockDownload() return false; } -bool fLargeWorkForkFound = false; -bool fLargeWorkInvalidChainFound = false; CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; void CheckForkWarningConditions() @@ -1346,7 +1364,7 @@ void CheckForkWarningConditions() if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) { - if (!fLargeWorkForkFound && pindexBestForkBase) + if (!GetfLargeWorkForkFound() && pindexBestForkBase) { if(pindexBestForkBase->phashBlock){ std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + @@ -1360,7 +1378,7 @@ void CheckForkWarningConditions() LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); - fLargeWorkForkFound = true; + SetfLargeWorkForkFound(true); } } else @@ -1369,13 +1387,13 @@ void CheckForkWarningConditions() LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); else LogPrintf("%s: Warning: Found invalid chain which has higher work (at least ~6 blocks worth of work) than our best chain.\nChain state database corruption likely.\n", __func__); - fLargeWorkInvalidChainFound = true; + SetfLargeWorkInvalidChainFound(true); } } else { - fLargeWorkForkFound = false; - fLargeWorkInvalidChainFound = false; + SetfLargeWorkForkFound(false); + SetfLargeWorkInvalidChainFound(false); } } @@ -1645,7 +1663,7 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin /** Abort with a message */ bool AbortNode(const std::string& strMessage, const std::string& userMessage="") { - strMiscWarning = strMessage; + SetMiscWarning(strMessage); LogPrintf("*** %s\n", strMessage); uiInterface.ThreadSafeMessageBox( userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, @@ -2468,9 +2486,10 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) { ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { if (state == THRESHOLD_ACTIVE) { - strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); + std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); + SetMiscWarning(strWarning); if (!fWarned) { - CAlert::Notify(strMiscWarning); + CAlert::Notify(strWarning); fWarned = true; } } else { @@ -2490,10 +2509,11 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) { warningMessages.push_back(strprintf("%d of last 100 blocks have unexpected version", nUpgraded)); if (nUpgraded > 100/2) { - // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); + std::string strWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); + // notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user: + SetMiscWarning(strWarning); if (!fWarned) { - CAlert::Notify(strMiscWarning); + CAlert::Notify(strWarning); fWarned = true; } } @@ -2536,7 +2556,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara const CTransaction& tx = *it; // ignore validation errors in resurrected transactions CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, it, false, NULL, true)) { mempool.removeRecursive(tx); } else if (mempool.exists(tx.GetHash())) { vHashUpdate.push_back(tx.GetHash()); @@ -2620,7 +2640,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); // Remove conflicting transactions from the mempool.; - mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight, !IsInitialBlockDownload()); + mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); // Update chainActive & related variables. UpdateTip(pindexNew, chainparams); @@ -3549,7 +3569,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned } -bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool *fNewBlock) +bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, bool *fNewBlock) { { LOCK(cs_main); @@ -3558,7 +3578,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr nPriority) - { - nPriority = alert.nPriority; - strStatusBar = strGUI = alert.strStatusBar; - } - } - } - - if (strFor == "gui") - return strGUI; - else if (strFor == "statusbar") - return strStatusBar; - else if (strFor == "rpc") - return strRPC; - assert(!"GetWarnings(): invalid parameter"); - return "error"; +std::string CBlockFileInfo::ToString() const { + return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); } - std::string CBlockFileInfo::ToString() const { - return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); - } - ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) { AssertLockHeld(cs_main); @@ -4509,15 +4463,16 @@ bool LoadMempool(void) file >> num; double prioritydummy = 0; while (num--) { + CTransactionRef tx; int64_t nTime; int64_t nFeeDelta; - CTransaction tx(deserialize, file); + file >> tx; file >> nTime; file >> nFeeDelta; CAmount amountdelta = nFeeDelta; if (amountdelta) { - mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), prioritydummy, amountdelta); + mempool.PrioritiseTransaction(tx->GetHash(), tx->GetHash().ToString(), prioritydummy, amountdelta); } CValidationState state; if (nTime + nExpiryTimeout > nNow) { @@ -4531,6 +4486,8 @@ bool LoadMempool(void) } else { ++skipped; } + if (ShutdownRequested()) + return false; } std::map mapDeltas; file >> mapDeltas; diff --git a/src/validation.h b/src/validation.h index 203667fff0c0..8ab228e5c5fa 100644 --- a/src/validation.h +++ b/src/validation.h @@ -71,7 +71,7 @@ static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25; /** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101; /** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ -static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72; +static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336; /** The maximum size of a blk?????.dat file (since 0.8) */ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ @@ -123,6 +123,8 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000; static const unsigned int DEFAULT_LIMITFREERELAY = 0; static const bool DEFAULT_RELAYPRIORITY = true; static const int64_t DEFAULT_MAX_TIP_AGE = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin +/** Maximum age of our tip in seconds for us to be considered current for fee estimation */ +static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60; /** Default for -permitbaremultisig */ static const bool DEFAULT_PERMIT_BAREMULTISIG = true; @@ -134,7 +136,6 @@ static const bool DEFAULT_TIMESTAMPINDEX = false; static const bool DEFAULT_SPENTINDEX = false; static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; -static const bool DEFAULT_TESTSAFEMODE = false; /** Default for -mempoolreplacement */ static const bool DEFAULT_ENABLE_REPLACEMENT = false; /** Default for using fee filter */ @@ -238,11 +239,10 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 945 * 1024 * 1024; * * @param[in] pblock The block we want to process. * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. - * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call * @return True if state.IsValid() */ -bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool* fNewBlock); +bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr pblock, bool fForceProcessing, bool* fNewBlock); /** * Process incoming block headers. @@ -323,11 +323,11 @@ void FlushStateToDisk(); void PruneAndFlush(); /** (try to) add transaction to memory pool **/ -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool* pfMissingInputs, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0, bool fDryRun=false); /** (try to) add transaction to memory pool with a specified acceptance time **/ -bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, +bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree, bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit=false, const CAmount nAbsurdFee=0, bool fDryRun=false); bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 773fbc42426a..65697854c311 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -83,7 +83,7 @@ UniValue importprivkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw runtime_error( - "importprivkey \"dashprivkey\" ( \"label\" rescan )\n" + "importprivkey \"dashprivkey\" ( \"label\" ) ( rescan )\n" "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" "\nArguments:\n" "1. \"dashprivkey\" (string, required) The private key (see dumpprivkey)\n" @@ -655,11 +655,11 @@ UniValue dumpprivkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw runtime_error( - "dumpprivkey \"dashaddress\"\n" - "\nReveals the private key corresponding to 'dashaddress'.\n" + "dumpprivkey \"address\"\n" + "\nReveals the private key corresponding to 'address'.\n" "Then the importprivkey can be used with this output\n" "\nArguments:\n" - "1. \"dashaddress\" (string, required) The dash address for the private key\n" + "1. \"address\" (string, required) The dash address for the private key\n" "\nResult:\n" "\"key\" (string) The private key\n" "\nExamples:\n" @@ -1167,10 +1167,10 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) // clang-format off if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) throw runtime_error( - "importmulti '[]' '' \n\n" + "importmulti \"requests\" \"options\"\n\n" "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n" "Arguments:\n" - "1. request array (array, required) Data to be imported\n" + "1. requests (array, required) Data to be imported\n" " [ (array of json objects)\n" " {\n" " \"scriptPubKey\": \"