diff options
42 files changed, 478 insertions, 227 deletions
diff --git a/configure.ac b/configure.ac index 1e894f5767..ec5656814f 100644 --- a/configure.ac +++ b/configure.ac @@ -98,6 +98,11 @@ AC_ARG_ENABLE(tests, [use_tests=$enableval], [use_tests=yes]) +AC_ARG_ENABLE(gui-tests, + AS_HELP_STRING([--disable-gui-tests],[do not compile GUI tests (default is to compile if GUI and tests enabled)]), + [use_gui_tests=$enableval], + [use_gui_tests=$use_tests]) + AC_ARG_ENABLE(bench, AS_HELP_STRING([--disable-bench],[do not compile benchmarks (default is to compile)]), [use_bench=$enableval], @@ -919,8 +924,8 @@ else fi dnl these are only used when qt is enabled +BUILD_TEST_QT="" if test x$bitcoin_enable_qt != xno; then - BUILD_QT=qt dnl enable dbus support AC_MSG_CHECKING([whether to build GUI with support for D-Bus]) if test x$bitcoin_enable_qt_dbus != xno; then @@ -950,9 +955,9 @@ if test x$bitcoin_enable_qt != xno; then fi AC_MSG_CHECKING([whether to build test_bitcoin-qt]) - if test x$use_tests$bitcoin_enable_qt_test = xyesyes; then + if test x$use_gui_tests$bitcoin_enable_qt_test = xyesyes; then AC_MSG_RESULT([yes]) - BUILD_TEST_QT="test" + BUILD_TEST_QT="yes" else AC_MSG_RESULT([no]) fi @@ -963,9 +968,10 @@ AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) AC_MSG_CHECKING([whether to build test_bitcoin]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) - BUILD_TEST="test" + BUILD_TEST="yes" else AC_MSG_RESULT([no]) + BUILD_TEST="" fi AC_MSG_CHECKING([whether to reduce exports]) @@ -983,9 +989,9 @@ AM_CONDITIONAL([TARGET_DARWIN], [test x$TARGET_OS = xdarwin]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows]) AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes]) -AM_CONDITIONAL([ENABLE_TESTS],[test x$use_tests = xyes]) +AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) -AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$use_tests$bitcoin_enable_qt_test = xyesyes]) +AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) @@ -1026,9 +1032,6 @@ AC_SUBST(USE_QRCODE) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) -AC_SUBST(BUILD_TEST) -AC_SUBST(BUILD_QT) -AC_SUBST(BUILD_TEST_QT) AC_SUBST(MINIUPNPC_CPPFLAGS) AC_SUBST(MINIUPNPC_LIBS) AC_CONFIG_FILES([Makefile src/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py index 9a62fccbbb..f82362fe41 100755 --- a/contrib/devtools/github-merge.py +++ b/contrib/devtools/github-merge.py @@ -47,9 +47,9 @@ def git_config_get(option, default=None): except subprocess.CalledProcessError as e: return default -def retrieve_pr_title(repo,pull): +def retrieve_pr_info(repo,pull): ''' - Retrieve pull request title from github. + Retrieve pull request information from github. Return None if no title can be found, or an error happens. ''' try: @@ -57,9 +57,9 @@ def retrieve_pr_title(repo,pull): result = urlopen(req) reader = codecs.getreader('utf-8') obj = json.load(reader(result)) - return obj['title'] + return obj except Exception as e: - print('Warning: unable to retrieve pull title from github: %s' % e) + print('Warning: unable to retrieve pull information from github: %s' % e) return None def ask_prompt(text): @@ -69,13 +69,13 @@ def ask_prompt(text): print("",file=stderr) return reply -def parse_arguments(branch): +def parse_arguments(): epilog = ''' In addition, you can set the following git configuration variables: githubmerge.repository (mandatory), user.signingkey (mandatory), githubmerge.host (default: git@github.com), - githubmerge.branch (default: master), + githubmerge.branch (no default), githubmerge.testcmd (default: none). ''' parser = argparse.ArgumentParser(description='Utility to merge, sign and push github pull requests', @@ -83,14 +83,14 @@ def parse_arguments(branch): parser.add_argument('pull', metavar='PULL', type=int, nargs=1, help='Pull request ID to merge') parser.add_argument('branch', metavar='BRANCH', type=str, nargs='?', - default=branch, help='Branch to merge against (default: '+branch+')') + default=None, help='Branch to merge against (default: githubmerge.branch setting, or base branch for pull, or \'master\')') return parser.parse_args() def main(): # Extract settings from git repo repo = git_config_get('githubmerge.repository') host = git_config_get('githubmerge.host','git@github.com') - branch = git_config_get('githubmerge.branch','master') + opt_branch = git_config_get('githubmerge.branch',None) testcmd = git_config_get('githubmerge.testcmd') signingkey = git_config_get('user.signingkey') if repo is None: @@ -105,9 +105,20 @@ def main(): host_repo = host+":"+repo # shortcut for push/pull target # Extract settings from command line - args = parse_arguments(branch) + args = parse_arguments() pull = str(args.pull[0]) - branch = args.branch + + # Receive pull information from github + info = retrieve_pr_info(repo,pull) + if info is None: + exit(1) + title = info['title'] + # precedence order for destination branch argument: + # - command line argument + # - githubmerge.branch setting + # - base branch for pull (as retrieved from github) + # - 'master' + branch = args.branch or opt_branch or info['base']['ref'] or 'master' # Initialize source branches head_branch = 'pull/'+pull+'/head' @@ -147,7 +158,6 @@ def main(): try: # Create unsigned merge commit. - title = retrieve_pr_title(repo,pull) if title: firstline = 'Merge #%s: %s' % (pull,title) else: @@ -165,7 +175,7 @@ def main(): print("ERROR: Creating merge failed (already merged?).",file=stderr) exit(4) - print('%s#%s%s %s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title)) + print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET)) subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch]) print() # Run test command if configured. diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index 1f2c4f9999..13941f5d55 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -26,7 +26,7 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="i686-pc-linux-gnu x86_64-unknown-linux-gnu" - CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" + CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests LDFLAGS=-static-libstdc++" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="date ar ranlib nm strip" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 6f68ae08ce..c430932f9d 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -36,7 +36,7 @@ files: script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-apple-darwin11" - CONFIGFLAGS="--enable-reduce-exports GENISOIMAGE=$WRAP_DIR/genisoimage" + CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage" FAKETIME_HOST_PROGS="" FAKETIME_PROGS="ar ranlib date dmg genisoimage" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index f0fbff3e10..9f7322f0b5 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -29,7 +29,7 @@ files: [] script: | WRAP_DIR=$HOME/wrapped HOSTS="x86_64-w64-mingw32 i686-w64-mingw32" - CONFIGFLAGS="--enable-reduce-exports" + CONFIGFLAGS="--enable-reduce-exports --disable-gui-tests" FAKETIME_HOST_PROGS="g++ ar ranlib nm windres strip" FAKETIME_PROGS="date makensis zip" diff --git a/contrib/gitian-downloader/jl2012-key.pgp b/contrib/gitian-downloader/jl2012-key.pgp new file mode 100644 index 0000000000..b8aad7fd88 --- /dev/null +++ b/contrib/gitian-downloader/jl2012-key.pgp @@ -0,0 +1,105 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: GPGTools - https://gpgtools.org + +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 +=1irw +-----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/build-unix.md b/doc/build-unix.md index c1e92d8d15..dc754fc733 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -250,6 +250,24 @@ A list of additional configure flags can be displayed with: ./configure --help +Setup and Build Example: Arch Linux +----------------------------------- +This example lists the steps necessary to setup and build a command line only, non-wallet distribution of the latest changes on Arch Linux: + + pacman -S git base-devel boost libevent python + git clone https://github.com/bitcoin/bitcoin.git + cd bitcoin/ + ./autogen.sh + ./configure --disable-wallet --without-gui --without-miniupnpc + make check + +Note: +Enabling wallet support requires either compiling against a Berkeley DB newer than 4.8 (package `db`) using `--with-incompatible-bdb`, +or building and depending on a local version of Berkeley DB 4.8. The readily available Arch Linux packages are currently built using +`--with-incompatible-bdb` according to the [PKGBUILD](https://projects.archlinux.org/svntogit/community.git/tree/bitcoin/trunk/PKGBUILD). +As mentioned above, when maintaining portability of the wallet between the standard Bitcoin Core distributions and independently built +node software is desired, Berkeley DB 4.8 must be used. + ARM Cross-compilation ------------------- @@ -270,4 +288,4 @@ To build executables for ARM: make -For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory.
\ No newline at end of file +For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory. diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 358792251b..8affb2158a 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -71,6 +71,12 @@ To describe a member or variable use: int var; //!< Detailed description after the member ``` +or +```cpp +//! Description before the member +int var; +``` + Also OK: ```c++ /// diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 54993d13a9..3126218518 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -47,7 +47,7 @@ You can also install Gitian on actual hardware instead of using virtualization. Create a new VirtualBox VM --------------------------- -In the VirtualBox GUI click "Create" and choose the following parameters in the wizard: +In the VirtualBox GUI click "New" and choose the following parameters in the wizard: ![](gitian-building/create_new_vm.png) @@ -74,13 +74,6 @@ In the VirtualBox GUI click "Create" and choose the following parameters in the - File location and size: at least 40GB; as low as 20GB *may* be possible, but better to err on the safe side - Click `Create` -Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.3.0/amd64/iso-cd/debian-8.3.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). -This DVD image can be validated using a SHA256 hashing tool, for example on -Unixy OSes by entering the following in a terminal: - - echo "dd25bcdde3c6ea5703cc0f313cde621b13d42ff7d252e2538a11663c93bf8654 debian-8.3.0-amd64-netinst.iso" | sha256sum -c - # (must return OK) - After creating the VM, we need to configure it. - Click the `Settings` button, then go to the `Network` tab. Adapter 1 should be attached to `NAT`. @@ -102,6 +95,13 @@ After creating the VM, we need to configure it. - Click `Ok` twice to save. +Get the [Debian 8.x net installer](http://cdimage.debian.org/debian-cd/8.4.0/amd64/iso-cd/debian-8.4.0-amd64-netinst.iso) (a more recent minor version should also work, see also [Debian Network installation](https://www.debian.org/CD/netinst/)). +This DVD image can be validated using a SHA256 hashing tool, for example on +Unixy OSes by entering the following in a terminal: + + echo "7a6b418e6a4ee3ca75dda04d79ed96c9e2c33bb0c703ca7e40c6374ab4590748 debian-8.4.0-amd64-netinst.iso" | sha256sum -c + # (must return OK) + Then start the VM. On the first launch you will be asked for a CD or DVD image. Choose the downloaded iso. ![](gitian-building/select_startup_disk.png) @@ -160,6 +160,10 @@ To select a different button, press `Tab`. ![](gitian-building/debian_install_12_choose_disk.png) + - Partition Disks -> *All files in one partition* + +![](gitian-building/all_files_in_one_partition.png) + - Finish partitioning and write changes to disk -> *Yes* (`Tab`, `Enter` to select the `Yes` button) ![](gitian-building/debian_install_14_finish.png) @@ -313,7 +317,7 @@ Setting up the Gitian image ------------------------- Gitian needs a virtual image of the operating system to build in. -Currently this is Ubuntu Precise x86_64. +Currently this is Ubuntu Trusty x86_64. This image will be copied and used every time that a build is started to make sure that the build is deterministic. Creating the image will take a while, but only has to be done once. @@ -363,7 +367,7 @@ Output from `gbuild` will look something like Resolving deltas: 100% (41590/41590), done. From https://github.com/bitcoin/bitcoin ... (new tags, new branch etc) - --- Building for precise amd64 --- + --- Building for trusty amd64 --- Stopping target if it is up Making a new image copy stdin: is not a tty @@ -412,14 +416,14 @@ So, if you use LXC: export PATH="$PATH":/path/to/gitian-builder/libexec export USE_LXC=1 cd /path/to/gitian-builder -./libexec/make-clean-vm --suite precise --arch amd64 +./libexec/make-clean-vm --suite trusty --arch amd64 -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root apt-get update -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root \ +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root apt-get update +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root \ -e DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -y install \ $( sed -ne '/^packages:/,/[^-] .*/ {/^- .*/{s/"//g;s/- //;p}}' ../bitcoin/contrib/gitian-descriptors/*|sort|uniq ) -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root apt-get -q -y purge grub -LXC_ARCH=amd64 LXC_SUITE=precise on-target -u root -e DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root apt-get -q -y purge grub +LXC_ARCH=amd64 LXC_SUITE=trusty on-target -u root -e DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade ``` And then set offline mode for apt-cacher-ng: diff --git a/doc/gitian-building/all_files_in_one_partition.png b/doc/gitian-building/all_files_in_one_partition.png Binary files differnew file mode 100644 index 0000000000..8cbb0d8adc --- /dev/null +++ b/doc/gitian-building/all_files_in_one_partition.png diff --git a/doc/gitian-building/create_vm_file_location_size.png b/doc/gitian-building/create_vm_file_location_size.png Binary files differindex 14aef5abae..5f77206b6f 100644 --- a/doc/gitian-building/create_vm_file_location_size.png +++ b/doc/gitian-building/create_vm_file_location_size.png diff --git a/doc/gitian-building/select_startup_disk.png b/doc/gitian-building/select_startup_disk.png Binary files differindex 5acdc3fe10..59bc093e2c 100644 --- a/doc/gitian-building/select_startup_disk.png +++ b/doc/gitian-building/select_startup_disk.png diff --git a/doc/tor.md b/doc/tor.md index be41255449..43e922718b 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -3,7 +3,7 @@ TOR SUPPORT IN BITCOIN It is possible to run Bitcoin as a Tor hidden service, and connect to such services. -The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on a random port. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly +The following directions assume you have a Tor proxy running on port 9050. Many distributions default to having a SOCKS proxy listening on port 9050, but others may not. In particular, the Tor Browser Bundle defaults to listening on port 9150. See [Tor Project FAQ:TBBSocksPort](https://www.torproject.org/docs/faq.html.en#TBBSocksPort) for how to properly configure Tor. diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/qa/rpc-tests/bip68-112-113-p2p.py index f391cb0b7a..35c831cb8b 100755 --- a/qa/rpc-tests/bip68-112-113-p2p.py +++ b/qa/rpc-tests/bip68-112-113-p2p.py @@ -149,13 +149,6 @@ class BIP68_112_113Test(ComparisonTestFramework): block.solve() return block - def get_bip9_status(self, key): - info = self.nodes[0].getblockchaininfo() - for row in info['bip9_softforks']: - if row['id'] == key: - return row - raise IndexError ('key:"%s" not found' % key) - def create_bip68txs(self, bip68inputs, txversion, locktime_delta = 0): txs = [] assert(len(bip68inputs) >= 16) @@ -223,11 +216,11 @@ class BIP68_112_113Test(ComparisonTestFramework): self.tip = int ("0x" + self.nodes[0].getbestblockhash() + "L", 0) self.nodeaddress = self.nodes[0].getnewaddress() - assert_equal(self.get_bip9_status('csv')['status'], 'defined') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined') test_blocks = self.generate_blocks(61, 4) yield TestInstance(test_blocks, sync_every_block=False) # 1 # Advanced from DEFINED to STARTED, height = 143 - assert_equal(self.get_bip9_status('csv')['status'], 'started') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') # Fail to achieve LOCKED_IN 100 out of 144 signal bit 0 # using a variety of bits to simulate multiple parallel softforks @@ -237,7 +230,7 @@ class BIP68_112_113Test(ComparisonTestFramework): test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) # 2 # Failed to advance past STARTED, height = 287 - assert_equal(self.get_bip9_status('csv')['status'], 'started') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started') # 108 out of 144 signal bit 0 to achieve lock-in # using a variety of bits to simulate multiple parallel softforks @@ -247,7 +240,7 @@ class BIP68_112_113Test(ComparisonTestFramework): test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not) yield TestInstance(test_blocks, sync_every_block=False) # 3 # Advanced from STARTED to LOCKED_IN, height = 431 - assert_equal(self.get_bip9_status('csv')['status'], 'locked_in') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') # 140 more version 4 blocks test_blocks = self.generate_blocks(140, 4) @@ -291,7 +284,7 @@ class BIP68_112_113Test(ComparisonTestFramework): test_blocks = self.generate_blocks(2, 4) yield TestInstance(test_blocks, sync_every_block=False) # 5 # Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575) - assert_equal(self.get_bip9_status('csv')['status'], 'locked_in') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in') # Test both version 1 and version 2 transactions for all tests # BIP113 test transaction will be modified before each use to put in appropriate block time @@ -368,7 +361,7 @@ class BIP68_112_113Test(ComparisonTestFramework): # 1 more version 4 block to get us to height 575 so the fork should now be active for the next block test_blocks = self.generate_blocks(1, 4) yield TestInstance(test_blocks, sync_every_block=False) # 8 - assert_equal(self.get_bip9_status('csv')['status'], 'active') + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active') ################################# diff --git a/qa/rpc-tests/bip68-sequence.py b/qa/rpc-tests/bip68-sequence.py index 377a35b687..33e05dfc51 100755 --- a/qa/rpc-tests/bip68-sequence.py +++ b/qa/rpc-tests/bip68-sequence.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Test BIP68 implementation (mempool only) +# Test BIP68 implementation # from test_framework.test_framework import BitcoinTestFramework @@ -26,8 +26,10 @@ class BIP68Test(BitcoinTestFramework): def setup_network(self): self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-blockprioritysize=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"])) self.is_network_split = False self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] + connect_nodes(self.nodes[0], 1) def run_test(self): # Generate some coins @@ -42,10 +44,18 @@ class BIP68Test(BitcoinTestFramework): print "Running test sequence-lock-unconfirmed-inputs" self.test_sequence_lock_unconfirmed_inputs() - # This test needs to change when BIP68 becomes consensus - print "Running test BIP68 not consensus" + print "Running test BIP68 not consensus before versionbits activation" self.test_bip68_not_consensus() + print "Verifying nVersion=2 transactions aren't standard" + self.test_version2_relay(before_activation=True) + + print "Activating BIP68 (and 112/113)" + self.activateCSV() + + print "Verifying nVersion=2 transactions are now standard" + self.test_version2_relay(before_activation=False) + print "Passed\n" # Test that BIP68 is not in effect if tx version is 1, or if @@ -333,8 +343,12 @@ class BIP68Test(BitcoinTestFramework): self.nodes[0].invalidateblock(self.nodes[0].getblockhash(cur_height+1)) self.nodes[0].generate(10) - # Make sure that BIP68 isn't being used to validate blocks. + # Make sure that BIP68 isn't being used to validate blocks, prior to + # versionbits activation. If more blocks are mined prior to this test + # being run, then it's possible the test has activated the soft fork, and + # this test should be moved to run earlier, or deleted. def test_bip68_not_consensus(self): + assert(get_bip9_status(self.nodes[0], 'csv')['status'] != 'active') txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2) tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) @@ -381,6 +395,30 @@ class BIP68Test(BitcoinTestFramework): self.nodes[0].submitblock(ToHex(block)) assert_equal(self.nodes[0].getbestblockhash(), block.hash) + def activateCSV(self): + # activation should happen at block height 432 (3 periods) + min_activation_height = 432 + height = self.nodes[0].getblockcount() + assert(height < 432) + self.nodes[0].generate(432-height) + assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') + sync_blocks(self.nodes) + + # Use self.nodes[1] to test standardness relay policy + def test_version2_relay(self, before_activation): + inputs = [ ] + outputs = { self.nodes[1].getnewaddress() : 1.0 } + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + rawtxfund = self.nodes[1].fundrawtransaction(rawtx)['hex'] + tx = FromHex(CTransaction(), rawtxfund) + tx.nVersion = 2 + tx_signed = self.nodes[1].signrawtransaction(ToHex(tx))["hex"] + try: + tx_id = self.nodes[1].sendrawtransaction(tx_signed) + assert(before_activation == False) + except: + assert(before_activation) + if __name__ == '__main__': BIP68Test().main() diff --git a/qa/rpc-tests/bip9-softforks.py b/qa/rpc-tests/bip9-softforks.py index 98975e7193..e63343d352 100755 --- a/qa/rpc-tests/bip9-softforks.py +++ b/qa/rpc-tests/bip9-softforks.py @@ -79,11 +79,7 @@ class BIP9SoftForksTest(ComparisonTestFramework): def get_bip9_status(self, key): info = self.nodes[0].getblockchaininfo() - for row in info['bip9_softforks']: - if row['id'] == key: - return row - raise IndexError ('key:"%s" not found' % key) - + return info['bip9_softforks'][key] def test_BIP(self, bipName, activated_version, invalidate, invalidatePostSignature): # generate some coins for later diff --git a/qa/rpc-tests/blockchain.py b/qa/rpc-tests/blockchain.py index 272a5dc154..8f59ee741c 100755 --- a/qa/rpc-tests/blockchain.py +++ b/qa/rpc-tests/blockchain.py @@ -82,6 +82,7 @@ class BlockchainTest(BitcoinTestFramework): assert isinstance(header['mediantime'], int) assert isinstance(header['nonce'], int) assert isinstance(header['version'], int) + assert isinstance(int(header['versionHex'], 16), int) assert isinstance(header['difficulty'], Decimal) if __name__ == '__main__': diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py index c231676ec8..eff4c6e808 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/qa/rpc-tests/httpbasics.py @@ -37,13 +37,13 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert('"error":null' in out1) + assert(b'"error":null' in out1) assert(conn.sock!=None) #according to http/1.1 connection must still be open! #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) - out2 = conn.getresponse().read() - assert('"error":null' in out1) #must also response with a correct json-rpc message + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) #must also response with a correct json-rpc message assert(conn.sock!=None) #according to http/1.1 connection must still be open! conn.close() @@ -54,13 +54,13 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert('"error":null' in out1) + assert(b'"error":null' in out1) assert(conn.sock!=None) #according to http/1.1 connection must still be open! #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) - out2 = conn.getresponse().read() - assert('"error":null' in out1) #must also response with a correct json-rpc message + out1 = conn.getresponse().read() + assert(b'"error":null' in out1) #must also response with a correct json-rpc message assert(conn.sock!=None) #according to http/1.1 connection must still be open! conn.close() @@ -71,7 +71,7 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert('"error":null' in out1) + assert(b'"error":null' in out1) assert(conn.sock==None) #now the connection must be closed after the response #node1 (2nd node) is running with disabled keep-alive option @@ -83,7 +83,7 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert('"error":null' in out1) + assert(b'"error":null' in out1) #node2 (third node) is running with standard keep-alive parameters which means keep-alive is on urlNode2 = urlparse.urlparse(self.nodes[2].url) @@ -94,7 +94,7 @@ class HTTPBasicsTest (BitcoinTestFramework): conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read() - assert('"error":null' in out1) + assert(b'"error":null' in out1) assert(conn.sock!=None) #connection must be closed because bitcoind should use keep-alive by default # Check excessive request size diff --git a/qa/rpc-tests/importprunedfunds.py b/qa/rpc-tests/importprunedfunds.py index db875800d4..a9324196ee 100755 --- a/qa/rpc-tests/importprunedfunds.py +++ b/qa/rpc-tests/importprunedfunds.py @@ -83,9 +83,10 @@ class ImportPrunedFundsTest(BitcoinTestFramework): try: result1 = self.nodes[1].importprunedfunds(rawtxn1, proof1, "") except JSONRPCException as e: - errorString = e.error['message'] + assert('No addresses' in e.error['message']) + else: + assert(False) - assert('No addresses' in errorString) balance1 = self.nodes[1].getbalance("", 0, True) assert_equal(balance1, Decimal(0)) @@ -120,9 +121,10 @@ class ImportPrunedFundsTest(BitcoinTestFramework): try: self.nodes[1].removeprunedfunds(txnid1) except JSONRPCException as e: - errorString = e.error['message'] + assert('does not exist' in e.error['message']) + else: + assert(False) - assert('does not exist' in errorString) balance1 = Decimal(self.nodes[1].getbalance("", 0, True)) assert_equal(balance1, Decimal('0.075')) diff --git a/qa/rpc-tests/maxblocksinflight.py b/qa/rpc-tests/maxblocksinflight.py index 0313bce736..ad633f661d 100755 --- a/qa/rpc-tests/maxblocksinflight.py +++ b/qa/rpc-tests/maxblocksinflight.py @@ -41,40 +41,36 @@ class TestManager(NodeConnCB): self.disconnectOkay = False def run(self): - try: - fail = False - self.connection.rpc.generate(1) # Leave IBD - - numBlocksToGenerate = [ 8, 16, 128, 1024 ] - for count in range(len(numBlocksToGenerate)): - current_invs = [] - for i in range(numBlocksToGenerate[count]): - current_invs.append(CInv(2, random.randrange(0, 1<<256))) - if len(current_invs) >= 50000: - self.connection.send_message(msg_inv(current_invs)) - current_invs = [] - if len(current_invs) > 0: + self.connection.rpc.generate(1) # Leave IBD + + numBlocksToGenerate = [8, 16, 128, 1024] + for count in range(len(numBlocksToGenerate)): + current_invs = [] + for i in range(numBlocksToGenerate[count]): + current_invs.append(CInv(2, random.randrange(0, 1 << 256))) + if len(current_invs) >= 50000: self.connection.send_message(msg_inv(current_invs)) - - # Wait and see how many blocks were requested - time.sleep(2) - - total_requests = 0 - with mininode_lock: - for key in self.blockReqCounts: - total_requests += self.blockReqCounts[key] - if self.blockReqCounts[key] > 1: - raise AssertionError("Error, test failed: block %064x requested more than once" % key) - if total_requests > MAX_REQUESTS: - raise AssertionError("Error, too many blocks (%d) requested" % total_requests) - print "Round %d: success (total requests: %d)" % (count, total_requests) - except AssertionError as e: - print "TEST FAILED: ", e.args + current_invs = [] + if len(current_invs) > 0: + self.connection.send_message(msg_inv(current_invs)) + + # Wait and see how many blocks were requested + time.sleep(2) + + total_requests = 0 + with mininode_lock: + for key in self.blockReqCounts: + total_requests += self.blockReqCounts[key] + if self.blockReqCounts[key] > 1: + raise AssertionError("Error, test failed: block %064x requested more than once" % key) + if total_requests > MAX_REQUESTS: + raise AssertionError("Error, too many blocks (%d) requested" % total_requests) + print "Round %d: success (total requests: %d)" % (count, total_requests) self.disconnectOkay = True self.connection.disconnect_node() - + class MaxBlocksInFlightTest(BitcoinTestFramework): def add_options(self, parser): parser.add_option("--testbinary", dest="testbinary", @@ -86,7 +82,7 @@ class MaxBlocksInFlightTest(BitcoinTestFramework): initialize_chain_clean(self.options.tmpdir, 1) def setup_network(self): - self.nodes = start_nodes(1, self.options.tmpdir, + self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[['-debug', '-whitelist=127.0.0.1']], binary=[self.options.testbinary]) diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index 9f660c8bda..762a6d6a30 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -56,13 +56,13 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].signrawtransaction(rawtx) - errorString = "" try: rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) except JSONRPCException as e: - errorString = e.error['message'] + assert("Missing inputs" in e.error['message']) + else: + assert(False) - assert("Missing inputs" in errorString) ######################### # RAW TX MULTISIG TESTS # diff --git a/qa/rpc-tests/test_framework/test_framework.py b/qa/rpc-tests/test_framework/test_framework.py index 19ee472609..3b08cd1384 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/qa/rpc-tests/test_framework/test_framework.py @@ -142,6 +142,9 @@ class BitcoinTestFramework(object): except AssertionError as e: print("Assertion failed: "+ str(e)) traceback.print_tb(sys.exc_info()[2]) + except KeyError as e: + print("key not found: "+ str(e)) + traceback.print_tb(sys.exc_info()[2]) except Exception as e: print("Unexpected exception caught during testing: "+str(e)) traceback.print_tb(sys.exc_info()[2]) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index f069c32a60..acb7f8a6b4 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -545,3 +545,7 @@ def create_lots_of_big_transactions(node, txouts, utxos, fee): txid = node.sendrawtransaction(signresult["hex"], True) txids.append(txid) return txids + +def get_bip9_status(node, key): + info = node.getblockchaininfo() + return info['bip9_softforks'][key] diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index cb876aae5c..8fdcea50b6 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -245,22 +245,20 @@ class WalletTest (BitcoinTestFramework): txObj = self.nodes[0].gettransaction(txId) assert_equal(txObj['amount'], Decimal('-0.0001')) - #this should fail - errorString = "" try: txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4") except JSONRPCException as e: - errorString = e.error['message'] + assert("Invalid amount" in e.error['message']) + else: + raise AssertionError("Must not parse invalid amounts") - assert("Invalid amount" in errorString) - errorString = "" try: - self.nodes[0].generate("2") #use a string to as block amount parameter must fail because it's not interpreted as amount + self.nodes[0].generate("2") + raise AssertionError("Must not accept strings as numeric") except JSONRPCException as e: - errorString = e.error['message'] + assert("not an integer" in e.error['message']) - assert("not an integer" in errorString) # Mine a block from node0 to an address from node1 cbAddr = self.nodes[1].getnewaddress() @@ -269,10 +267,7 @@ class WalletTest (BitcoinTestFramework): self.sync_all() # Check that the txid and balance is found by node1 - try: - self.nodes[1].gettransaction(cbTxId) - except JSONRPCException as e: - assert("Invalid or non-wallet transaction id" not in e.error['message']) + self.nodes[1].gettransaction(cbTxId) #check if wallet or blochchain maintenance changes the balance self.sync_all() diff --git a/src/Makefile.am b/src/Makefile.am index 1e54512cbd..d91e959cff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -479,7 +479,7 @@ endif %.pb.cc %.pb.h: %.proto @test -f $(PROTOC) - $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(<D) $<) + $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(<D) $< if ENABLE_TESTS include Makefile.test.include diff --git a/src/amount.cpp b/src/amount.cpp index 68806ff062..7b8618de33 100644 --- a/src/amount.cpp +++ b/src/amount.cpp @@ -9,20 +9,30 @@ const std::string CURRENCY_UNIT = "BTC"; -CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize) +CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_) { + assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max())); + int64_t nSize = int64_t(nBytes_); + if (nSize > 0) - nSatoshisPerK = nFeePaid*1000/nSize; + nSatoshisPerK = nFeePaid * 1000 / nSize; else nSatoshisPerK = 0; } -CAmount CFeeRate::GetFee(size_t nSize) const +CAmount CFeeRate::GetFee(size_t nBytes_) const { + assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max())); + int64_t nSize = int64_t(nBytes_); + CAmount nFee = nSatoshisPerK * nSize / 1000; - if (nFee == 0 && nSize != 0 && nSatoshisPerK > 0) - nFee = CAmount(1); + if (nFee == 0 && nSize != 0) { + if (nSatoshisPerK > 0) + nFee = CAmount(1); + if (nSatoshisPerK < 0) + nFee = CAmount(-1); + } return nFee; } diff --git a/src/amount.h b/src/amount.h index 9aba6525c7..5e52f37f23 100644 --- a/src/amount.h +++ b/src/amount.h @@ -11,6 +11,7 @@ #include <stdlib.h> #include <string> +/** Amount in satoshis (Can be negative) */ typedef int64_t CAmount; static const CAmount COIN = 100000000; @@ -30,22 +31,24 @@ extern const std::string CURRENCY_UNIT; static const CAmount MAX_MONEY = 21000000 * COIN; inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } -/** Type-safe wrapper class for fee rates - * (how much to pay based on transaction size) +/** + * Fee rate in satoshis per kilobyte: CAmount / kB */ class CFeeRate { private: CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes public: + /** Fee rate of 0 satoshis per kB */ CFeeRate() : nSatoshisPerK(0) { } explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } - CFeeRate(const CAmount& nFeePaid, size_t nSize); + /** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/ + CFeeRate(const CAmount& nFeePaid, size_t nBytes); CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } /** * Return the fee in satoshis for the given size in bytes. */ - CAmount GetFee(size_t size) const; + CAmount GetFee(size_t nBytes) const; /** * Return the fee in satoshis for a size of 1000 bytes */ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 965d131695..5c7d190125 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -266,8 +266,8 @@ public: assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); - vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. - vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. + vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. + vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds. fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; diff --git a/src/main.cpp b/src/main.cpp index 2c0b3bfee7..9b164c7999 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -194,16 +194,11 @@ namespace { /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ struct QueuedBlock { uint256 hash; - CBlockIndex *pindex; //! Optional. - int64_t nTime; //! Time of "getdata" request in microseconds. - bool fValidatedHeaders; //! Whether this block has validated headers at the time of request. - int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer) + CBlockIndex* pindex; //!< Optional. + bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. }; map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; - /** Number of blocks in flight with validated headers. */ - int nQueuedValidatedHeaders = 0; - /** Number of preferable block download peers. */ int nPreferredDownload = 0; @@ -212,6 +207,9 @@ namespace { /** Dirty block file entries. */ set<int> setDirtyFileInfo; + + /** Number of peers from which we're downloading blocks. */ + int nPeersWithValidatedDownloads = 0; } // anon namespace ////////////////////////////////////////////////////////////////////////////// @@ -259,6 +257,8 @@ struct CNodeState { //! Since when we're stalling block download progress (in microseconds), or 0. int64_t nStallingSince; list<QueuedBlock> vBlocksInFlight; + //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty. + int64_t nDownloadingSince; int nBlocksInFlight; int nBlocksInFlightValidHeaders; //! Whether we consider this a preferred download peer. @@ -276,6 +276,7 @@ struct CNodeState { pindexBestHeaderSent = NULL; fSyncStarted = false; nStallingSince = 0; + nDownloadingSince = 0; nBlocksInFlight = 0; nBlocksInFlightValidHeaders = 0; fPreferredDownload = false; @@ -310,12 +311,6 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state) nPreferredDownload += state->fPreferredDownload; } -// Returns time at which to timeout block request (nTime in microseconds) -int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams) -{ - return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore); -} - void InitializeNode(NodeId nodeid, const CNode *pnode) { LOCK(cs_main); CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; @@ -335,13 +330,21 @@ void FinalizeNode(NodeId nodeid) { } BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) { - nQueuedValidatedHeaders -= entry.fValidatedHeaders; mapBlocksInFlight.erase(entry.hash); } EraseOrphansFor(nodeid); nPreferredDownload -= state->fPreferredDownload; + nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); + assert(nPeersWithValidatedDownloads >= 0); mapNodeState.erase(nodeid); + + if (mapNodeState.empty()) { + // Do a consistency check after the last peer is removed. + assert(mapBlocksInFlight.empty()); + assert(nPreferredDownload == 0); + assert(nPeersWithValidatedDownloads == 0); + } } // Requires cs_main. @@ -350,8 +353,15 @@ bool MarkBlockAsReceived(const uint256& hash) { map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); if (itInFlight != mapBlocksInFlight.end()) { CNodeState *state = State(itInFlight->second.first); - nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders; state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; + if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) { + // Last validated block on the queue was received. + nPeersWithValidatedDownloads--; + } + if (state->vBlocksInFlight.begin() == itInFlight->second.second) { + // First block on the queue was received, update the start download time for the next one + state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros()); + } state->vBlocksInFlight.erase(itInFlight->second.second); state->nBlocksInFlight--; state->nStallingSince = 0; @@ -369,12 +379,17 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa // Make sure it's not listed somewhere already. MarkBlockAsReceived(hash); - int64_t nNow = GetTimeMicros(); - QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)}; - nQueuedValidatedHeaders += newentry.fValidatedHeaders; + QueuedBlock newentry = {hash, pindex, pindex != NULL}; list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); state->nBlocksInFlight++; state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; + if (state->nBlocksInFlight == 1) { + // We're starting a block download (batch) from this peer. + state->nDownloadingSince = GetTimeMicros(); + } + if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) { + nPeersWithValidatedDownloads++; + } mapBlocksInFlight[hash] = std::make_pair(nodeid, it); } @@ -1010,6 +1025,14 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C if (fRequireStandard && !IsStandardTx(tx, reason)) return state.DoS(0, false, REJECT_NONSTANDARD, reason); + // Don't relay version 2 transactions until CSV is active, and we can be + // sure that such transactions will be mined (unless we're on + // -testnet/-regtest). + const CChainParams& chainparams = Params(); + if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { + return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); + } + // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. @@ -2877,6 +2900,8 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, CBlockIndex *pindexMostWork = NULL; do { boost::this_thread::interruption_point(); + if (ShutdownRequested()) + break; CBlockIndex *pindexNewTip = NULL; const CBlockIndex *pindexFork; @@ -3894,7 +3919,6 @@ void UnloadBlockIndex() nBlockSequenceId = 1; mapBlockSource.clear(); mapBlocksInFlight.clear(); - nQueuedValidatedHeaders = 0; nPreferredDownload = 0; setDirtyBlockIndex.clear(); setDirtyFileInfo.clear(); @@ -4475,9 +4499,8 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } -bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) +bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams) { - const CChainParams& chainparams = Params(); RandAddSeedPerfmon(); LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) @@ -5487,7 +5510,7 @@ bool ProcessMessages(CNode* pfrom) bool fRet = false; try { - fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); + fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams); boost::this_thread::interruption_point(); } catch (const std::ios_base::failure& e) @@ -5811,24 +5834,15 @@ bool SendMessages(CNode* pto) LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); pto->fDisconnect = true; } - // In case there is a block that has been in flight from this peer for (2 + 0.5 * N) times the block interval - // (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to - // timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link + // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval + // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout. + // We compensate for other peers to prevent killing off peers due to our own downstream link // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes // to unreasonably increase our timeout. - // We also compare the block download timeout originally calculated against the time at which we'd disconnect - // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're - // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a - // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing - // more quickly than once every 5 minutes, then we'll shorten the download window for this block). if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); - int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams); - if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) { - LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow); - queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow; - } - if (queuedBlock.nTimeDisconnect < nNow) { + int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); + if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); pto->fDisconnect = true; } diff --git a/src/main.h b/src/main.h index 0bfcfab213..0962f44e94 100644 --- a/src/main.h +++ b/src/main.h @@ -106,6 +106,10 @@ static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; static const unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; /** Maximum feefilter broadcast delay after significant change. */ static const unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; +/** Block download timeout base, expressed in millionths of the block interval (i.e. 10 min) */ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000; +/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000; static const unsigned int DEFAULT_LIMITFREERELAY = 15; static const bool DEFAULT_RELAYPRIORITY = true; @@ -469,13 +473,13 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, class CBlockFileInfo { public: - unsigned int nBlocks; //! number of blocks stored in file - unsigned int nSize; //! number of used bytes of block file - unsigned int nUndoSize; //! number of used bytes in the undo file - unsigned int nHeightFirst; //! lowest height of block in file - unsigned int nHeightLast; //! highest height of block in file - uint64_t nTimeFirst; //! earliest time of block in file - uint64_t nTimeLast; //! latest time of block in file + unsigned int nBlocks; //!< number of blocks stored in file + unsigned int nSize; //!< number of used bytes of block file + unsigned int nUndoSize; //!< number of used bytes in the undo file + unsigned int nHeightFirst; //!< lowest height of block in file + unsigned int nHeightLast; //!< highest height of block in file + uint64_t nTimeFirst; //!< earliest time of block in file + uint64_t nTimeLast; //!< latest time of block in file ADD_SERIALIZE_METHODS; diff --git a/src/netbase.cpp b/src/netbase.cpp index 7f79dd02c6..281c6bcb7f 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -170,7 +170,8 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign if (aiTrav->ai_family == AF_INET6) { assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6)); - vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr)); + struct sockaddr_in6* s6 = (struct sockaddr_in6*) aiTrav->ai_addr; + vIP.push_back(CNetAddr(s6->sin6_addr, s6->sin6_scope_id)); } aiTrav = aiTrav->ai_next; @@ -629,6 +630,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest void CNetAddr::Init() { memset(ip, 0, sizeof(ip)); + scopeId = 0; } void CNetAddr::SetIP(const CNetAddr& ipIn) @@ -678,9 +680,10 @@ CNetAddr::CNetAddr(const struct in_addr& ipv4Addr) SetRaw(NET_IPV4, (const uint8_t*)&ipv4Addr); } -CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr) +CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr, const uint32_t scope) { SetRaw(NET_IPV6, (const uint8_t*)&ipv6Addr); + scopeId = scope; } CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup) @@ -1099,7 +1102,7 @@ CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), po assert(addr.sin_family == AF_INET); } -CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port)) +CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr, addr.sin6_scope_id), port(ntohs(addr.sin6_port)) { assert(addr.sin6_family == AF_INET6); } @@ -1192,6 +1195,7 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const memset(paddrin6, 0, *addrlen); if (!GetIn6Addr(&paddrin6->sin6_addr)) return false; + paddrin6->sin6_scope_id = scopeId; paddrin6->sin6_family = AF_INET6; paddrin6->sin6_port = htons(port); return true; diff --git a/src/netbase.h b/src/netbase.h index 1db66ac27f..db736154fa 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -44,6 +44,7 @@ class CNetAddr { protected: unsigned char ip[16]; // in network byte order + uint32_t scopeId; // for scoped/link-local ipv6 addresses public: CNetAddr(); @@ -89,7 +90,7 @@ class CNetAddr std::vector<unsigned char> GetGroup() const; int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; - CNetAddr(const struct in6_addr& pipv6Addr); + CNetAddr(const struct in6_addr& pipv6Addr, const uint32_t scope = 0); bool GetIn6Addr(struct in6_addr* pipv6Addr) const; friend bool operator==(const CNetAddr& a, const CNetAddr& b); diff --git a/src/policy/fees.h b/src/policy/fees.h index cdd984de7d..463f62f710 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -265,8 +265,8 @@ public: void Read(CAutoFile& filein); private: - CFeeRate minTrackedFee; //! Passed to constructor to avoid dependency on main - double minTrackedPriority; //! Set to AllowFreeThreshold + CFeeRate minTrackedFee; //!< Passed to constructor to avoid dependency on main + double minTrackedPriority; //!< Set to AllowFreeThreshold unsigned int nBestSeenHeight; struct TxStatsInfo { diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index e3ed7be000..d1a15451dc 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -73,12 +73,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason) BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed - // keys. (remember the 520 byte limit on redeemScript size) That works + // keys (remember the 520 byte limit on redeemScript size). That works // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 // bytes of scriptSig, which we round off to 1650 bytes for some minor // future-proofing. That's also enough to spend a 20-of-20 // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not - // considered standard) + // considered standard. if (txin.scriptSig.size() > 1650) { reason = "scriptsig-size"; return false; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f1c9d9f7ab..7a01a10b7d 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -70,6 +70,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", blockindex->nVersion)); + result.push_back(Pair("versionHex", strprintf("%08x", blockindex->nVersion))); result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); @@ -98,6 +99,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); + result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion))); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction&tx, block.vtx) @@ -316,6 +318,7 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" + " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" @@ -375,6 +378,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" + " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"tx\" : [ (array of string) The transaction ids\n" " \"transactionid\" (string) The transaction id\n" @@ -604,17 +608,23 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* return rv; } -static UniValue BIP9SoftForkDesc(const std::string& name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) +static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id) { UniValue rv(UniValue::VOBJ); - rv.push_back(Pair("id", name)); - switch (VersionBitsTipState(consensusParams, id)) { + const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id); + switch (thresholdState) { case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break; case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break; case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break; case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break; case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break; } + if (THRESHOLD_STARTED == thresholdState) + { + rv.push_back(Pair("bit", consensusParams.vDeployments[id].bit)); + } + rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime)); + rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout)); return rv; } @@ -649,12 +659,14 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" " }, ...\n" " ],\n" - " \"bip9_softforks\": [ (array) status of BIP9 softforks in progress\n" - " {\n" - " \"id\": \"xxxx\", (string) name of the softfork\n" + " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n" + " \"xxxx\" : { (string) name of the softfork\n" " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"lockedin\", \"active\", \"failed\"\n" + " \"bit\": xx, (numeric) the bit, 0-28, in the block version field used to signal this soft fork\n" + " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n" + " \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n" " }\n" - " ]\n" + " }\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") @@ -677,11 +689,11 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) const Consensus::Params& consensusParams = Params().GetConsensus(); CBlockIndex* tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); - UniValue bip9_softforks(UniValue::VARR); + UniValue bip9_softforks(UniValue::VOBJ); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); - bip9_softforks.push_back(BIP9SoftForkDesc("csv", consensusParams, Consensus::DEPLOYMENT_CSV)); + bip9_softforks.push_back(Pair("csv", BIP9SoftForkDesc(consensusParams, Consensus::DEPLOYMENT_CSV))); obj.push_back(Pair("softforks", softforks)); obj.push_back(Pair("bip9_softforks", bip9_softforks)); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b040d2bc80..c89af6bfa7 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -18,8 +18,8 @@ using namespace std; class CRPCConvertParam { public: - std::string methodName; //! method whose params want conversion - int paramIdx; //! 0-based idx of param to convert + std::string methodName; //!< method whose params want conversion + int paramIdx; //!< 0-based idx of param to convert }; static const CRPCConvertParam vRPCConvertParams[] = diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 149a4f0156..9c47f7c6c9 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1015,12 +1015,12 @@ namespace { */ class CTransactionSignatureSerializer { private: - const CTransaction &txTo; //! reference to the spending transaction (the one being serialized) - const CScript &scriptCode; //! output script being consumed - const unsigned int nIn; //! input index of txTo being signed - const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set - const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE - const bool fHashNone; //! whether the hashtype is SIGHASH_NONE + const CTransaction& txTo; //!< reference to the spending transaction (the one being serialized) + const CScript& scriptCode; //!< output script being consumed + const unsigned int nIn; //!< input index of txTo being signed + const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set + const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE + const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE public: CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : diff --git a/src/script/standard.h b/src/script/standard.h index 64bf010ec1..f348da8e19 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -27,7 +27,7 @@ public: CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 83; //! bytes (+1 for OP_RETURN, +2 for the pushdata opcodes) +static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes) extern bool fAcceptDatacarrier; extern unsigned nMaxDatacarrierBytes; diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp index 59dab20633..fd6f88b366 100644 --- a/src/test/amount_tests.cpp +++ b/src/test/amount_tests.cpp @@ -27,6 +27,15 @@ BOOST_AUTO_TEST_CASE(GetFeeTest) BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 1e3); BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 9e3); + feeRate = CFeeRate(-1000); + // Must always just return -1 * arg + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(1), -1); + BOOST_CHECK_EQUAL(feeRate.GetFee(121), -121); + BOOST_CHECK_EQUAL(feeRate.GetFee(999), -999); + BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), -1e3); + BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), -9e3); + feeRate = CFeeRate(123); // Truncates the result, if not integer BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); @@ -37,6 +46,26 @@ BOOST_AUTO_TEST_CASE(GetFeeTest) BOOST_CHECK_EQUAL(feeRate.GetFee(999), 122); BOOST_CHECK_EQUAL(feeRate.GetFee(1e3), 123); BOOST_CHECK_EQUAL(feeRate.GetFee(9e3), 1107); + + feeRate = CFeeRate(-123); + // Truncates the result, if not integer + BOOST_CHECK_EQUAL(feeRate.GetFee(0), 0); + BOOST_CHECK_EQUAL(feeRate.GetFee(8), -1); // Special case: returns -1 instead of 0 + BOOST_CHECK_EQUAL(feeRate.GetFee(9), -1); + + // Check full constructor + // default value + BOOST_CHECK(CFeeRate(CAmount(-1), 1000) == CFeeRate(-1)); + BOOST_CHECK(CFeeRate(CAmount(0), 1000) == CFeeRate(0)); + BOOST_CHECK(CFeeRate(CAmount(1), 1000) == CFeeRate(1)); + // lost precision (can only resolve satoshis per kB) + BOOST_CHECK(CFeeRate(CAmount(1), 1001) == CFeeRate(0)); + BOOST_CHECK(CFeeRate(CAmount(2), 1001) == CFeeRate(1)); + // some more integer checks + BOOST_CHECK(CFeeRate(CAmount(26), 789) == CFeeRate(32)); + BOOST_CHECK(CFeeRate(CAmount(27), 789) == CFeeRate(34)); + // Maximum size in bytes, should not crash + CFeeRate(MAX_MONEY, std::numeric_limits<size_t>::max() >> 1).GetFeePerK(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txmempool.h b/src/txmempool.h index 9dbb37dad0..de4ba0b371 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -74,28 +74,28 @@ class CTxMemPoolEntry { private: CTransaction tx; - CAmount nFee; //! Cached to avoid expensive parent-transaction lookups - size_t nTxSize; //! ... and avoid recomputing tx size - size_t nModSize; //! ... and modified size for priority - size_t nUsageSize; //! ... and total memory usage - 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 - int64_t feeDelta; //! Used for determining the priority of the transaction for mining in a block - LockPoints lockPoints; //! Track the height and time at which tx was final + CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups + size_t nTxSize; //!< ... and avoid recomputing tx size + size_t nModSize; //!< ... and modified size for priority + size_t nUsageSize; //!< ... and total memory usage + 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 + int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block + LockPoints lockPoints; //!< Track the height and time at which tx was final // Information about descendants of this transaction that are in the // mempool; if we remove this transaction we must remove all of these // descendants as well. if nCountWithDescendants is 0, treat this entry as // dirty, and nSizeWithDescendants and nModFeesWithDescendants will not be // correct. - uint64_t nCountWithDescendants; //! number of descendant transactions - uint64_t nSizeWithDescendants; //! ... and size - CAmount nModFeesWithDescendants; //! ... and total fees (all including us) + uint64_t nCountWithDescendants; //!< number of descendant transactions + uint64_t nSizeWithDescendants; //!< ... and size + CAmount nModFeesWithDescendants; //!< ... and total fees (all including us) // Analogous statistics for ancestor transactions uint64_t nCountWithAncestors; @@ -399,18 +399,18 @@ public: class CTxMemPool { private: - uint32_t nCheckFrequency; //! Value n means that n times in 2^32 we check. + uint32_t nCheckFrequency; //!< Value n means that n times in 2^32 we check. unsigned int nTransactionsUpdated; CBlockPolicyEstimator* minerPolicyEstimator; - uint64_t totalTxSize; //! sum of all mempool tx' byte sizes - uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves) + uint64_t totalTxSize; //!< sum of all mempool tx' byte sizes + uint64_t cachedInnerUsage; //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves) CFeeRate minReasonableRelayFee; mutable int64_t lastRollingFeeUpdate; mutable bool blockSinceLastRollingFeeBump; - mutable double rollingMinimumFeeRate; //! minimum fee to get into the pool, decreases exponentially + mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially void trackPackageRemoved(const CFeeRate& rate); diff --git a/src/utiltime.cpp b/src/utiltime.cpp index 91b40d9991..da590f8889 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -14,7 +14,7 @@ using namespace std; -static int64_t nMockTime = 0; //! For unit testing +static int64_t nMockTime = 0; //!< For unit testing int64_t GetTime() { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 867f33a7b5..96d5d4e1e0 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -228,11 +228,11 @@ public: mapValue_t mapValue; std::vector<std::pair<std::string, std::string> > vOrderForm; unsigned int fTimeReceivedIsTxTime; - unsigned int nTimeReceived; //! time received by this node + unsigned int nTimeReceived; //!< time received by this node unsigned int nTimeSmart; char fFromMe; std::string strFromAccount; - int64_t nOrderPos; //! position in ordered transaction list + int64_t nOrderPos; //!< position in ordered transaction list // memory only mutable bool fDebitCached; @@ -324,7 +324,7 @@ public: } READWRITE(*(CMerkleTx*)this); - std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev + std::vector<CMerkleTx> vUnused; //!< Used to be vtxPrev READWRITE(vUnused); READWRITE(mapValue); READWRITE(vOrderForm); @@ -465,7 +465,7 @@ public: std::string strOtherAccount; std::string strComment; mapValue_t mapValue; - int64_t nOrderPos; //! position in ordered transaction list + int64_t nOrderPos; //!< position in ordered transaction list uint64_t nEntryNo; CAccountingEntry() |