aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE.md32
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml9
-rw-r--r--CONTRIBUTING.md12
-rw-r--r--Makefile.am6
-rw-r--r--configure.ac4
-rw-r--r--contrib/debian/bitcoin-qt.desktop3
-rwxr-xr-xcontrib/devtools/git-subtree-check.sh37
-rwxr-xr-xcontrib/gitian-build.sh1
-rw-r--r--contrib/gitian-keys/sjors-key.pgp76
-rw-r--r--contrib/init/bitcoind.openrc2
-rw-r--r--contrib/init/bitcoind.service27
-rw-r--r--contrib/valgrind.supp43
-rwxr-xr-xcontrib/verify-commits/gpg.sh5
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh8
-rwxr-xr-xcontrib/verifybinaries/verify.sh2
-rw-r--r--doc/build-openbsd.md103
-rw-r--r--doc/build-windows.md87
-rw-r--r--doc/developer-notes.md52
-rw-r--r--doc/release-notes.md16
-rw-r--r--doc/release-notes/release-notes-0.15.1.md277
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.qt.include4
-rw-r--r--src/Makefile.test.include2
-rw-r--r--src/addrdb.cpp22
-rw-r--r--src/addrdb.h4
-rw-r--r--src/addrman.cpp8
-rw-r--r--src/addrman.h13
-rw-r--r--src/arith_uint256.cpp8
-rw-r--r--src/arith_uint256.h2
-rw-r--r--src/base58.cpp12
-rw-r--r--src/base58.h10
-rw-r--r--src/bech32.cpp2
-rw-r--r--src/bench/Examples.cpp6
-rw-r--r--src/bench/base58.cpp6
-rw-r--r--src/bench/bench.cpp41
-rw-r--r--src/bench/bench.h35
-rw-r--r--src/bench/bench_bitcoin.cpp12
-rw-r--r--src/bench/ccoins_caching.cpp8
-rw-r--r--src/bench/checkblock.cpp12
-rw-r--r--src/bench/checkqueue.cpp12
-rw-r--r--src/bench/coin_selection.cpp4
-rw-r--r--src/bench/crypto_hash.cpp20
-rw-r--r--src/bench/lockedpool.cpp4
-rw-r--r--src/bench/mempool_eviction.cpp6
-rw-r--r--src/bench/perf.cpp2
-rw-r--r--src/bench/prevector_destructor.cpp4
-rw-r--r--src/bench/rollingbloom.cpp11
-rw-r--r--src/bench/verify_script.cpp12
-rw-r--r--src/bitcoin-cli.cpp18
-rw-r--r--src/bitcoin-tx.cpp49
-rw-r--r--src/bitcoind.cpp36
-rw-r--r--src/blockencodings.cpp20
-rw-r--r--src/blockencodings.h2
-rw-r--r--src/bloom.cpp16
-rw-r--r--src/bloom.h2
-rw-r--r--src/chain.cpp2
-rw-r--r--src/chain.h12
-rw-r--r--src/chainparams.cpp24
-rw-r--r--src/chainparams.h8
-rw-r--r--src/chainparamsbase.cpp6
-rw-r--r--src/checkpoints.cpp12
-rw-r--r--src/checkpoints.h2
-rw-r--r--src/checkqueue.h2
-rw-r--r--src/clientversion.cpp6
-rw-r--r--src/clientversion.h2
-rw-r--r--src/coins.cpp102
-rw-r--r--src/coins.h14
-rw-r--r--src/compat.h4
-rw-r--r--src/compat/byteswap.h2
-rw-r--r--src/compat/endian.h4
-rw-r--r--src/compat/glibc_compat.cpp2
-rw-r--r--src/compat/glibc_sanity.cpp2
-rw-r--r--src/compat/strnlen.cpp2
-rw-r--r--src/compressor.cpp8
-rw-r--r--src/compressor.h6
-rw-r--r--src/consensus/consensus.h11
-rw-r--r--src/consensus/merkle.cpp6
-rw-r--r--src/consensus/merkle.h6
-rw-r--r--src/consensus/params.h14
-rw-r--r--src/consensus/tx_verify.cpp16
-rw-r--r--src/consensus/tx_verify.h2
-rw-r--r--src/consensus/validation.h8
-rw-r--r--src/core_io.h2
-rw-r--r--src/core_memusage.h6
-rw-r--r--src/core_read.cpp18
-rw-r--r--src/core_write.cpp24
-rw-r--r--src/crypto/aes.cpp6
-rw-r--r--src/crypto/aes.h2
-rw-r--r--src/crypto/chacha20.cpp4
-rw-r--r--src/crypto/common.h4
-rw-r--r--src/crypto/hmac_sha256.cpp2
-rw-r--r--src/crypto/hmac_sha256.h2
-rw-r--r--src/crypto/hmac_sha512.cpp2
-rw-r--r--src/crypto/hmac_sha512.h2
-rw-r--r--src/crypto/ripemd160.cpp4
-rw-r--r--src/crypto/sha1.cpp4
-rw-r--r--src/crypto/sha256.cpp4
-rw-r--r--src/crypto/sha512.cpp4
-rw-r--r--src/dbwrapper.cpp8
-rw-r--r--src/dbwrapper.h14
-rw-r--r--src/fs.cpp2
-rw-r--r--src/hash.cpp8
-rw-r--r--src/hash.h12
-rw-r--r--src/httprpc.cpp37
-rw-r--r--src/httpserver.cpp50
-rw-r--r--src/init.cpp135
-rw-r--r--src/key.cpp12
-rw-r--r--src/key.h8
-rw-r--r--src/keystore.cpp35
-rw-r--r--src/keystore.h44
-rw-r--r--src/memusage.h2
-rw-r--r--src/merkleblock.cpp8
-rw-r--r--src/merkleblock.h8
-rw-r--r--src/miner.cpp46
-rw-r--r--src/miner.h4
-rw-r--r--src/net.cpp191
-rw-r--r--src/net.h70
-rw-r--r--src/net_processing.cpp732
-rw-r--r--src/net_processing.h28
-rw-r--r--src/netaddress.cpp10
-rw-r--r--src/netaddress.h6
-rw-r--r--src/netbase.cpp18
-rw-r--r--src/netbase.h8
-rw-r--r--src/netmessagemaker.h4
-rw-r--r--src/noui.cpp6
-rw-r--r--src/policy/feerate.cpp4
-rw-r--r--src/policy/feerate.h4
-rw-r--r--src/policy/fees.cpp46
-rw-r--r--src/policy/fees.h16
-rw-r--r--src/policy/policy.cpp16
-rw-r--r--src/policy/policy.h8
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/pow.cpp10
-rw-r--r--src/pow.h2
-rw-r--r--src/primitives/block.cpp10
-rw-r--r--src/primitives/block.h6
-rw-r--r--src/primitives/transaction.cpp8
-rw-r--r--src/primitives/transaction.h8
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h62
-rw-r--r--src/pubkey.cpp2
-rw-r--r--src/pubkey.h6
-rw-r--r--src/qt/addressbookpage.cpp18
-rw-r--r--src/qt/addresstablemodel.cpp10
-rw-r--r--src/qt/askpassphrasedialog.cpp22
-rw-r--r--src/qt/askpassphrasedialog.h1
-rw-r--r--src/qt/bantablemodel.cpp12
-rw-r--r--src/qt/bantablemodel.h2
-rw-r--r--src/qt/bitcoin.cpp50
-rw-r--r--src/qt/bitcoinaddressvalidator.cpp4
-rw-r--r--src/qt/bitcoinamountfield.cpp10
-rw-r--r--src/qt/bitcoinamountfield.h2
-rw-r--r--src/qt/bitcoingui.cpp46
-rw-r--r--src/qt/bitcoingui.h4
-rw-r--r--src/qt/bitcoinunits.cpp4
-rw-r--r--src/qt/bitcoinunits.h2
-rw-r--r--src/qt/clientmodel.cpp34
-rw-r--r--src/qt/coincontroldialog.cpp39
-rw-r--r--src/qt/coincontroldialog.h2
-rw-r--r--src/qt/coincontroltreewidget.cpp4
-rw-r--r--src/qt/csvmodelwriter.cpp2
-rw-r--r--src/qt/editaddressdialog.cpp8
-rw-r--r--src/qt/forms/askpassphrasedialog.ui7
-rw-r--r--src/qt/forms/coincontroldialog.ui2
-rw-r--r--src/qt/forms/debugwindow.ui2
-rw-r--r--src/qt/forms/editaddressdialog.ui2
-rw-r--r--src/qt/forms/modaloverlay.ui2
-rw-r--r--src/qt/forms/openuridialog.ui2
-rw-r--r--src/qt/forms/optionsdialog.ui4
-rw-r--r--src/qt/forms/receivecoinsdialog.ui24
-rw-r--r--src/qt/forms/receiverequestdialog.ui2
-rw-r--r--src/qt/forms/sendcoinsdialog.ui4
-rw-r--r--src/qt/forms/sendcoinsentry.ui13
-rw-r--r--src/qt/forms/signverifymessagedialog.ui2
-rw-r--r--src/qt/guiutil.cpp48
-rw-r--r--src/qt/guiutil.h6
-rw-r--r--src/qt/intro.cpp14
-rw-r--r--src/qt/modaloverlay.cpp8
-rw-r--r--src/qt/networkstyle.cpp4
-rw-r--r--src/qt/notificator.cpp4
-rw-r--r--src/qt/notificator.h2
-rw-r--r--src/qt/openuridialog.cpp8
-rw-r--r--src/qt/optionsdialog.cpp18
-rw-r--r--src/qt/optionsmodel.cpp26
-rw-r--r--src/qt/optionsmodel.h2
-rw-r--r--src/qt/overviewpage.cpp26
-rw-r--r--src/qt/overviewpage.h2
-rw-r--r--src/qt/paymentrequestplus.cpp7
-rw-r--r--src/qt/paymentrequestplus.h4
-rw-r--r--src/qt/paymentserver.cpp23
-rw-r--r--src/qt/paymentserver.h4
-rw-r--r--src/qt/peertablemodel.cpp32
-rw-r--r--src/qt/peertablemodel.h10
-rw-r--r--src/qt/platformstyle.cpp4
-rw-r--r--src/qt/qvalidatedlineedit.cpp6
-rw-r--r--src/qt/qvaluecombobox.cpp2
-rw-r--r--src/qt/receivecoinsdialog.cpp46
-rw-r--r--src/qt/receivecoinsdialog.h2
-rw-r--r--src/qt/receiverequestdialog.cpp16
-rw-r--r--src/qt/receiverequestdialog.h2
-rw-r--r--src/qt/recentrequeststablemodel.cpp12
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rw-r--r--src/qt/rpcconsole.cpp46
-rw-r--r--src/qt/rpcconsole.h7
-rw-r--r--src/qt/sendcoinsdialog.cpp68
-rw-r--r--src/qt/sendcoinsdialog.h3
-rw-r--r--src/qt/sendcoinsentry.cpp32
-rw-r--r--src/qt/sendcoinsentry.h6
-rw-r--r--src/qt/signverifymessagedialog.cpp24
-rw-r--r--src/qt/splashscreen.cpp18
-rw-r--r--src/qt/test/compattests.cpp6
-rw-r--r--src/qt/test/paymentservertests.cpp18
-rw-r--r--src/qt/test/paymentservertests.h2
-rw-r--r--src/qt/test/rpcnestedtests.cpp24
-rw-r--r--src/qt/test/rpcnestedtests.h7
-rw-r--r--src/qt/test/test_main.cpp16
-rw-r--r--src/qt/test/uritests.cpp6
-rw-r--r--src/qt/test/wallettests.cpp41
-rw-r--r--src/qt/trafficgraphwidget.cpp4
-rw-r--r--src/qt/transactiondesc.cpp32
-rw-r--r--src/qt/transactiondescdialog.cpp6
-rw-r--r--src/qt/transactionfilterproxy.cpp6
-rw-r--r--src/qt/transactionfilterproxy.h2
-rw-r--r--src/qt/transactionrecord.cpp14
-rw-r--r--src/qt/transactionrecord.h4
-rw-r--r--src/qt/transactiontablemodel.cpp36
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp34
-rw-r--r--src/qt/transactionview.h2
-rw-r--r--src/qt/utilitydialog.cpp24
-rw-r--r--src/qt/walletframe.cpp6
-rw-r--r--src/qt/walletmodel.cpp98
-rw-r--r--src/qt/walletmodel.h6
-rw-r--r--src/qt/walletmodeltransaction.cpp8
-rw-r--r--src/qt/walletmodeltransaction.h2
-rw-r--r--src/qt/walletview.cpp40
-rw-r--r--src/qt/walletview.h2
-rw-r--r--src/qt/winshutdownmonitor.cpp6
-rw-r--r--src/random.cpp12
-rw-r--r--src/random.h6
-rw-r--r--src/rest.cpp45
-rw-r--r--src/rpc/blockchain.cpp114
-rw-r--r--src/rpc/client.cpp8
-rw-r--r--src/rpc/mining.cpp54
-rw-r--r--src/rpc/mining.h2
-rw-r--r--src/rpc/misc.cpp40
-rw-r--r--src/rpc/net.cpp44
-rw-r--r--src/rpc/protocol.cpp16
-rw-r--r--src/rpc/protocol.h2
-rw-r--r--src/rpc/rawtransaction.cpp71
-rw-r--r--src/rpc/safemode.cpp8
-rw-r--r--src/rpc/server.cpp20
-rw-r--r--src/rpc/server.h6
-rw-r--r--src/scheduler.cpp6
-rw-r--r--src/scheduler.h2
-rw-r--r--src/script/bitcoinconsensus.cpp10
-rw-r--r--src/script/bitcoinconsensus.h2
-rw-r--r--src/script/interpreter.cpp18
-rw-r--r--src/script/interpreter.h4
-rw-r--r--src/script/ismine.cpp12
-rw-r--r--src/script/ismine.h2
-rw-r--r--src/script/script.cpp6
-rw-r--r--src/script/script.h6
-rw-r--r--src/script/script_error.cpp2
-rw-r--r--src/script/sigcache.cpp14
-rw-r--r--src/script/sigcache.h2
-rw-r--r--src/script/sign.cpp16
-rw-r--r--src/script/sign.h2
-rw-r--r--src/script/standard.cpp10
-rw-r--r--src/script/standard.h4
-rw-r--r--src/serialize.h4
-rw-r--r--src/streams.h16
-rw-r--r--src/support/allocators/secure.h4
-rw-r--r--src/support/allocators/zeroafterfree.h2
-rw-r--r--src/support/cleanse.cpp2
-rw-r--r--src/support/lockedpool.cpp6
-rw-r--r--src/sync.cpp16
-rw-r--r--src/sync.h51
-rw-r--r--src/test/DoS_tests.cpp206
-rw-r--r--src/test/addrman_tests.cpp10
-rw-r--r--src/test/allocator_tests.cpp6
-rw-r--r--src/test/amount_tests.cpp6
-rw-r--r--src/test/arith_uint256_tests.cpp8
-rw-r--r--src/test/base32_tests.cpp4
-rw-r--r--src/test/base58_tests.cpp24
-rw-r--r--src/test/base64_tests.cpp4
-rw-r--r--src/test/bech32_tests.cpp4
-rw-r--r--src/test/bip32_tests.cpp12
-rw-r--r--src/test/blockencodings_tests.cpp13
-rw-r--r--src/test/bloom_tests.cpp28
-rw-r--r--src/test/bswap_tests.cpp4
-rw-r--r--src/test/checkqueue_tests.cpp45
-rw-r--r--src/test/coins_tests.cpp16
-rw-r--r--src/test/compress_tests.cpp6
-rw-r--r--src/test/crypto_tests.cpp22
-rw-r--r--src/test/cuckoocache_tests.cpp8
-rw-r--r--src/test/dbwrapper_tests.cpp18
-rw-r--r--src/test/getarg_tests.cpp4
-rw-r--r--src/test/hash_tests.cpp6
-rw-r--r--src/test/key_tests.cpp16
-rw-r--r--src/test/limitedmap_tests.cpp4
-rw-r--r--src/test/main_tests.cpp8
-rw-r--r--src/test/mempool_tests.cpp10
-rw-r--r--src/test/merkle_tests.cpp4
-rw-r--r--src/test/merkleblock_tests.cpp6
-rw-r--r--src/test/miner_tests.cpp69
-rw-r--r--src/test/multisig_tests.cpp20
-rw-r--r--src/test/net_tests.cpp18
-rw-r--r--src/test/netbase_tests.cpp6
-rw-r--r--src/test/pmt_tests.cpp16
-rw-r--r--src/test/policyestimator_tests.cpp12
-rw-r--r--src/test/pow_tests.cpp12
-rw-r--r--src/test/prevector_tests.cpp10
-rw-r--r--src/test/raii_event_tests.cpp4
-rw-r--r--src/test/random_tests.cpp4
-rw-r--r--src/test/reverselock_tests.cpp4
-rw-r--r--src/test/rpc_tests.cpp12
-rw-r--r--src/test/sanity_tests.cpp6
-rw-r--r--src/test/scheduler_tests.cpp6
-rw-r--r--src/test/script_P2SH_tests.cpp22
-rw-r--r--src/test/script_standard_tests.cpp14
-rw-r--r--src/test/script_tests.cpp26
-rw-r--r--src/test/scriptnum10.h2
-rw-r--r--src/test/scriptnum_tests.cpp6
-rw-r--r--src/test/serialize_tests.cpp8
-rw-r--r--src/test/sighash_tests.cpp24
-rw-r--r--src/test/sigopcount_tests.cpp16
-rw-r--r--src/test/skiplist_tests.cpp6
-rw-r--r--src/test/streams_tests.cpp6
-rw-r--r--src/test/test_bitcoin.cpp74
-rw-r--r--src/test/test_bitcoin.h23
-rw-r--r--src/test/test_bitcoin_fuzzy.cpp51
-rw-r--r--src/test/test_bitcoin_main.cpp2
-rw-r--r--src/test/timedata_tests.cpp4
-rw-r--r--src/test/torcontrol_tests.cpp4
-rw-r--r--src/test/transaction_tests.cpp36
-rw-r--r--src/test/txvalidationcache_tests.cpp52
-rw-r--r--src/test/uint256_tests.cpp8
-rw-r--r--src/test/univalue_tests.cpp2
-rw-r--r--src/test/util_tests.cpp16
-rw-r--r--src/test/versionbits_tests.cpp27
-rw-r--r--src/threadinterrupt.cpp2
-rw-r--r--src/timedata.cpp16
-rw-r--r--src/tinyformat.h14
-rw-r--r--src/torcontrol.cpp12
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/txdb.cpp20
-rw-r--r--src/txdb.h6
-rw-r--r--src/txmempool.cpp30
-rw-r--r--src/txmempool.h19
-rw-r--r--src/ui_interface.cpp4
-rw-r--r--src/uint256.cpp4
-rw-r--r--src/uint256.h4
-rw-r--r--src/undo.h8
-rw-r--r--src/util.cpp16
-rw-r--r--src/util.h19
-rw-r--r--src/utilmoneystr.cpp8
-rw-r--r--src/utilmoneystr.h2
-rw-r--r--src/utilstrencodings.cpp4
-rw-r--r--src/utiltime.cpp4
-rw-r--r--src/validation.cpp222
-rw-r--r--src/validation.h27
-rw-r--r--src/validationinterface.cpp63
-rw-r--r--src/validationinterface.h70
-rw-r--r--src/versionbits.cpp14
-rw-r--r--src/versionbits.h2
-rw-r--r--src/wallet/coincontrol.h8
-rw-r--r--src/wallet/crypter.cpp151
-rw-r--r--src/wallet/crypter.h50
-rw-r--r--src/wallet/db.cpp108
-rw-r--r--src/wallet/db.h14
-rw-r--r--src/wallet/feebumper.cpp244
-rw-r--r--src/wallet/feebumper.h67
-rw-r--r--src/wallet/fees.cpp14
-rw-r--r--src/wallet/fees.h2
-rw-r--r--src/wallet/init.cpp32
-rw-r--r--src/wallet/rpcdump.cpp49
-rw-r--r--src/wallet/rpcwallet.cpp312
-rw-r--r--src/wallet/test/accounting_tests.cpp8
-rw-r--r--src/wallet/test/crypto_tests.cpp6
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp19
-rw-r--r--src/wallet/test/wallet_test_fixture.h2
-rw-r--r--src/wallet/test/wallet_tests.cpp25
-rw-r--r--src/wallet/wallet.cpp175
-rw-r--r--src/wallet/wallet.h58
-rw-r--r--src/wallet/walletdb.cpp26
-rw-r--r--src/wallet/walletdb.h8
-rw-r--r--src/warnings.cpp8
-rw-r--r--src/zmq/zmqabstractnotifier.cpp4
-rw-r--r--src/zmq/zmqabstractnotifier.h2
-rw-r--r--src/zmq/zmqconfig.h6
-rw-r--r--src/zmq/zmqnotificationinterface.cpp12
-rw-r--r--src/zmq/zmqnotificationinterface.h2
-rw-r--r--src/zmq/zmqpublishnotifier.cpp14
-rw-r--r--src/zmq/zmqpublishnotifier.h2
-rwxr-xr-xtest/functional/assumevalid.py46
-rwxr-xr-xtest/functional/bip65-cltv-p2p.py39
-rwxr-xr-xtest/functional/bipdersig-p2p.py40
-rwxr-xr-xtest/functional/blockchain.py2
-rwxr-xr-xtest/functional/example_test.py23
-rwxr-xr-xtest/functional/importmulti.py12
-rwxr-xr-xtest/functional/listsinceblock.py35
-rwxr-xr-xtest/functional/maxuploadtarget.py72
-rwxr-xr-xtest/functional/minchainwork.py8
-rwxr-xr-xtest/functional/multiwallet.py6
-rwxr-xr-xtest/functional/nulldummy.py4
-rwxr-xr-xtest/functional/p2p-acceptblock.py300
-rwxr-xr-xtest/functional/p2p-compactblocks.py21
-rwxr-xr-xtest/functional/p2p-feefilter.py26
-rwxr-xr-xtest/functional/p2p-fingerprint.py7
-rwxr-xr-xtest/functional/p2p-fullblocktest.py2
-rwxr-xr-xtest/functional/p2p-leaktests.py35
-rwxr-xr-xtest/functional/p2p-mempool.py12
-rwxr-xr-xtest/functional/p2p-segwit.py33
-rwxr-xr-xtest/functional/p2p-timeouts.py43
-rwxr-xr-xtest/functional/p2p-versionbits-warning.py12
-rwxr-xr-xtest/functional/receivedby.py124
-rwxr-xr-xtest/functional/replace-by-fee.py13
-rwxr-xr-xtest/functional/segwit.py7
-rwxr-xr-xtest/functional/sendheaders.py54
-rw-r--r--test/functional/test_framework/authproxy.py59
-rw-r--r--test/functional/test_framework/blockstore.py8
-rwxr-xr-xtest/functional/test_framework/comptool.py22
-rw-r--r--test/functional/test_framework/coverage.py2
-rw-r--r--test/functional/test_framework/key.py2
-rwxr-xr-xtest/functional/test_framework/mininode.py311
-rw-r--r--test/functional/test_framework/script.py2
-rw-r--r--test/functional/test_framework/socks5.py8
-rwxr-xr-xtest/functional/test_framework/test_framework.py5
-rwxr-xr-xtest/functional/test_framework/test_node.py50
-rwxr-xr-xtest/functional/test_runner.py5
-rwxr-xr-xtest/functional/uacomment.py35
-rwxr-xr-xtest/functional/wallet-accounts.py137
-rwxr-xr-xtest/functional/wallet-hd.py23
-rwxr-xr-xtest/functional/walletbackup.py10
-rwxr-xr-xtest/functional/zmq_test.py177
438 files changed, 6046 insertions, 4276 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 28c1814998..811a246df1 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,37 +1,23 @@
<!--- Remove sections that do not apply -->
-This issue tracker is only for technical issues related to bitcoin-core.
+This issue tracker is only for technical issues related to Bitcoin Core.
-General bitcoin questions and/or support requests and are best directed to the [Bitcoin StackExchange](https://bitcoin.stackexchange.com).
+General bitcoin questions and/or support requests are best directed to the [Bitcoin StackExchange](https://bitcoin.stackexchange.com).
For reporting security issues, please read instructions at [https://bitcoincore.org/en/contact/](https://bitcoincore.org/en/contact/).
-### Describe the issue
-
-### Can you reliably reproduce the issue?
-#### If so, please list the steps to reproduce below:
-1.
-2.
-3.
+If the node is "stuck" during sync or giving "block checksum mismatch" errors, please ensure your hardware is stable by running memtest and observe CPU temperature with a load-test tool such as linpack before creating an issue!
-### Expected behaviour
-Tell us what should happen
+### Describe the issue
+#### What behavior did you expect?
-### Actual behaviour
-Tell us what happens instead
+#### What was the actual behavior (provide screenshots if the issue is GUI-related)?
-### Screenshots.
-If the issue is related to the GUI, screenshots can be added to this issue via drag & drop.
+#### How reliably can you reproduce the issue, what are the steps to do so?
-### What version of bitcoin-core are you using?
-List the version number/commit ID, and if it is an official binary, self compiled or a distribution package such as PPA.
+### What version of Bitcoin Core are you using, where did you get it (website, self-compiled, etc)?
-### Machine specs:
-- OS:
-- CPU:
-- RAM:
-- Disk size:
-- Disk Type (HD/SDD):
+### What type of machine are you observing the error on (OS/CPU and disk type)?
### Any extra information that might be useful in the debugging process.
This is normally the contents of a `debug.log` or `config.log` file. Raw text or a link to a pastebin type site are preferred.
diff --git a/.gitignore b/.gitignore
index 60c26dae8b..ff297fbeca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@ src/qt/test/moc*.cpp
Makefile
bitcoin-qt
Bitcoin-Qt.app
+background.tiff*
# Unit-tests
Makefile.test
diff --git a/.travis.yml b/.travis.yml
index 0de7ca6f75..a643d2ff5d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,7 @@
sudo: required
dist: trusty
os: linux
-language: generic
+language: minimal
cache:
directories:
- depends/built
@@ -40,16 +40,19 @@ env:
before_install:
- export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/python/d' | tr "\n" ":" | sed "s|::|:|g")
- - export PATH=$(echo $PATH | tr ':' "\n" | sed '/\/opt\/pyenv/d' | tr "\n" ":" | sed "s|::|:|g")
install:
- if [ -n "$DPKG_ADD_ARCH" ]; then sudo dpkg --add-architecture "$DPKG_ADD_ARCH" ; fi
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi
before_script:
- if [ "$CHECK_DOC" = 1 -a "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then contrib/devtools/commit-script-check.sh $TRAVIS_COMMIT_RANGE; fi
+ - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/git-subtree-check.sh src/crypto/ctaes; fi
+ - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/git-subtree-check.sh src/secp256k1; fi
+ - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/git-subtree-check.sh src/univalue; fi
+ - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/git-subtree-check.sh src/leveldb; fi
- if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-doc.py; fi
- if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/check-rpc-mappings.py .; fi
- - if [ "$CHECK_DOC" = 1 ]; then contrib/devtools/lint-all.sh; fi
+ - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then contrib/devtools/lint-all.sh; fi
- unset CC; unset CXX
- mkdir -p depends/SDKs depends/sdk-sources
- if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index aed6d79542..9f95d3f818 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,9 +24,9 @@ facilitates social contribution, easy testing and peer review.
To contribute a patch, the workflow is as follows:
- - Fork repository
- - Create topic branch
- - Commit patches
+ 1. Fork repository
+ 1. Create topic branch
+ 1. Commit patches
The project coding conventions in the [developer notes](doc/developer-notes.md)
must be adhered to.
@@ -42,8 +42,8 @@ in init.cpp") in which case a single title line is sufficient. Commit messages s
helpful to people reading your code in the future, so explain the reasoning for
your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
-If a particular commit references another issue, please add the reference, for
-example `refs #1234`, or `fixes #4321`. Using the `fixes` or `closes` keywords
+If a particular commit references another issue, please add the reference. For
+example: `refs #1234` or `fixes #4321`. Using the `fixes` or `closes` keywords
will cause the corresponding issue to be closed when the pull request is merged.
Please refer to the [Git manual](https://git-scm.com/doc) for more information
@@ -85,7 +85,7 @@ Note that translations should not be submitted as pull requests, please see
[Translation Process](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md)
for more information on helping with translations.
-If a pull request is specifically not to be considered for merging (yet) please
+If a pull request is not to be considered for merging (yet), please
prefix the title with [WIP] or use [Tasks Lists](https://help.github.com/articles/basic-writing-and-formatting-syntax/#task-lists)
in the body of the pull request to indicate tasks are pending.
diff --git a/Makefile.am b/Makefile.am
index 3b62a10603..a7092bb334 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,6 @@ SUBDIRS += doc/man
endif
.PHONY: deploy FORCE
-GZIP_ENV="-9n"
export PYTHONPATH
if BUILD_BITCOIN_LIBS
@@ -44,6 +43,9 @@ DIST_CONTRIB = $(top_srcdir)/contrib/bitcoin-cli.bash-completion \
$(top_srcdir)/contrib/bitcoind.bash-completion \
$(top_srcdir)/contrib/init \
$(top_srcdir)/contrib/rpm
+DIST_SHARE = \
+ $(top_srcdir)/share/genbuild.sh \
+ $(top_srcdir)/share/rpcuser
BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \
$(top_srcdir)/contrib/devtools/security-check.py
@@ -213,7 +215,7 @@ endif
dist_noinst_SCRIPTS = autogen.sh
-EXTRA_DIST = $(top_srcdir)/share/genbuild.sh test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
+EXTRA_DIST = $(DIST_SHARE) test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS)
EXTRA_DIST += \
test/util/bitcoin-util-test.py \
diff --git a/configure.ac b/configure.ac
index 81c84a8af4..8e5561243a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -162,7 +162,7 @@ AC_ARG_ENABLE([ccache],
AC_ARG_ENABLE([lcov],
[AS_HELP_STRING([--enable-lcov],
[enable lcov testing (default is no)])],
- [use_lcov=yes],
+ [use_lcov=$enableval],
[use_lcov=no])
AC_ARG_ENABLE([lcov-branch-coverage],
@@ -241,6 +241,7 @@ if test "x$enable_werror" = "xyes"; then
AC_MSG_ERROR("enable-werror set but -Werror is not usable")
fi
AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Werror=thread-safety-analysis],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=thread-safety-analysis"],,[[$CXXFLAG_WERROR]])
fi
if test "x$CXXFLAGS_overridden" = "xno"; then
@@ -249,6 +250,7 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS="$CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[CXXFLAGS="$CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]])
## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all
## unknown options if any other warning is produced. Test the -Wfoo case, and
diff --git a/contrib/debian/bitcoin-qt.desktop b/contrib/debian/bitcoin-qt.desktop
index 593d7584ab..204cdf99d0 100644
--- a/contrib/debian/bitcoin-qt.desktop
+++ b/contrib/debian/bitcoin-qt.desktop
@@ -1,5 +1,5 @@
[Desktop Entry]
-Encoding=UTF-8
+Version=1.0
Name=Bitcoin Core
Comment=Connect to the Bitcoin P2P Network
Comment[de]=Verbinde mit dem Bitcoin peer-to-peer Netzwerk
@@ -11,3 +11,4 @@ Type=Application
Icon=bitcoin128
MimeType=x-scheme-handler/bitcoin;
Categories=Office;Finance;
+StartupWMClass=Bitcoin-qt
diff --git a/contrib/devtools/git-subtree-check.sh b/contrib/devtools/git-subtree-check.sh
index 2384d66cad..184951715e 100755
--- a/contrib/devtools/git-subtree-check.sh
+++ b/contrib/devtools/git-subtree-check.sh
@@ -18,7 +18,7 @@ find_latest_squash()
sub=
git log --grep="^git-subtree-dir: $dir/*\$" \
--pretty=format:'START %H%n%s%n%n%b%nEND%n' "$COMMIT" |
- while read a b junk; do
+ while read a b _; do
case "$a" in
START) sq="$b" ;;
git-subtree-mainline:) main="$b" ;;
@@ -41,21 +41,17 @@ find_latest_squash()
done
}
+# find latest subtree update
latest_squash="$(find_latest_squash "$DIR")"
if [ -z "$latest_squash" ]; then
echo "ERROR: $DIR is not a subtree" >&2
exit 2
fi
-
set $latest_squash
old=$1
rev=$2
-if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then
- echo "ERROR: subtree commit $rev unavailable. Fetch/update the subtree repository" >&2
- exit 2
-fi
-tree_subtree=$(git show -s --format="%T" $rev)
-echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)"
+
+# get the tree in the current commit
tree_actual=$(git ls-tree -d "$COMMIT" "$DIR" | head -n 1)
if [ -z "$tree_actual" ]; then
echo "FAIL: subtree directory $DIR not found in $COMMIT" >&2
@@ -69,9 +65,30 @@ if [ "d$tree_actual_type" != "dtree" ]; then
echo "FAIL: subtree directory $DIR is not a tree in $COMMIT" >&2
exit 1
fi
+
+# get the tree at the time of the last subtree update
+tree_commit=$(git show -s --format="%T" $old)
+echo "$DIR in $COMMIT was last updated in commit $old (tree $tree_commit)"
+
+# ... and compare the actual tree with it
+if [ "$tree_actual_tree" != "$tree_commit" ]; then
+ git diff $tree_commit $tree_actual_tree >&2
+ echo "FAIL: subtree directory was touched without subtree merge" >&2
+ exit 1
+fi
+
+# get the tree in the subtree commit referred to
+if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then
+ echo "subtree commit $rev unavailable: cannot compare" >&2
+ exit
+fi
+tree_subtree=$(git show -s --format="%T" $rev)
+echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)"
+
+# ... and compare the actual tree with it
if [ "$tree_actual_tree" != "$tree_subtree" ]; then
- git diff-tree $tree_actual_tree $tree_subtree >&2
- echo "FAIL: subtree directory tree doesn't match subtree commit tree" >&2
+ echo "FAIL: subtree update commit differs from upstream tree!" >&2
exit 1
fi
+
echo "GOOD"
diff --git a/contrib/gitian-build.sh b/contrib/gitian-build.sh
index 8fdec21b0e..511c1a4c48 100755
--- a/contrib/gitian-build.sh
+++ b/contrib/gitian-build.sh
@@ -6,7 +6,6 @@
sign=false
verify=false
build=false
-setupenv=false
# Systems to build
linux=true
diff --git a/contrib/gitian-keys/sjors-key.pgp b/contrib/gitian-keys/sjors-key.pgp
new file mode 100644
index 0000000000..2b5acc82aa
--- /dev/null
+++ b/contrib/gitian-keys/sjors-key.pgp
@@ -0,0 +1,76 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBFWSwMoBEADG31O8+ex+xpgzVKQgF4iVRE5uBPT0+GM6FnwqIIhXVKiBLQh8
+YDhhgk6joh+vsLrFzKZ9kXwoiHN8y/AiNCQ0xjAUdpznD5xvHAaGIAlT/sodRNT+
+869WgT9G1uiVp0P4ucEeilmhCn9o51LqkS3roXkj0ec52b1pslUl2WKdu1ZD+Bj4
+3/oVZm7mmjkDwl0RHJQmqlK0bunq0jlVlgH5sdQfmLbCZaq3LhVPf73zt5qHH+J6
+ZbU7A4cqm2eN5SyH+Nno+cq3+vXmvVI+x/jPe/dPDCXaGWf5fWI/Lbk/mMP7JAl1
+6X44CN+hZHUnNuzeZt2/ROWZ0s0JJcjQkSe9noUQedjBAHX82s886vsFzOHvDtul
+EuV/XAjUlkhMbhZkZaIq9ucqHmUBI4+OcFEIbbKc9TrKtJe+CYuWTNlomVk/iFr8
+zSm/S64NiqKi/BeQGgcsDZIaJDYfDP83esOOaaxFswHnJNtHnU1PwntrJtXft0dK
+ydtlQZ6r96SYxLDTeGfC2SNk0zbnKAGvjj04vzQeN+JSRZ75tNKmgdbJdNL8wvPh
+879TpCwMhNDvSRG+YqCe6whaJV76a+Doxg48HCJYaj6bnRn41/QGJEyL31I8l/7S
+YsLLmAEbqwG7erYi7WZS3cRrGJI8RwohGMZf7yraqoaOgMKmtE/Sq0tLtwARAQAB
+tCNTam9ycyBQcm92b29zdCA8c2pvcnNAc3Byb3Zvb3N0Lm5sPokCQAQTAQoAKgIb
+AwUJB4YfgAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUCWWXcoAIZAQAKCRBX/5vb
+zDAQCeYJD/47XDMfEMg4g4spo7k92XsNkvjlAhWvvxd+kxow/V8c64WQXody32FZ
+HRSmK8dVjf9mIJMKkX4lpKpim7cQxsdTcorcdu+yk4TK+Wah61vsMhbSSllfHs1U
++q8jYMGnXTD+CY0aeTMrTfJcR2yN98jmNSWIL1qWmJ51RSTL6BQKb6eYtR7pWRkW
+uMR6oFC09Db4fiKa4zhH81+/t0g+6pMY391gSluaS+OfNqGORCo+/IdG5IDzh5Vp
+f19qXjd5oMsZQf6/P4b4XUktgl8RVRcNzdYGoXpcd8LpeHtEOh5I93ODmCwqd67b
+YDlhDNN7iGhPndPEF6P4CNO/rXLPCZyMhRyt1dflu0KPCr+0AgR31cdhH/p7eCyj
+FTE9gUgUHOG9OHdRoVXrwHYXwAiDBr2pp2giLpBsAwa4d2hXNDJ6wfMMCSOXKQlS
+lHq06y/v/049DammkqW0XnEsU4qvsdteZ0jQu7Ob3LyGoytBIj8fn1OioT21W7wc
+ns3/Tt4cQsn2ICBYB4PzqwkvGUp7fDwwHYw7rq6kvCEVDUDWMtVgQ8kjsh2OoU75
+eeteM1Q1fV06Wfn2Qct9bn0NKRGrA8mm3lrCWYCeGqJeBvC6kna1QgV53vYRLJod
+w3Ql4+M9tUIi9uiGLvVaGZWO9wU1EwL+EAO+6D85h6QiJN7H8gcwUokCPQQTAQoA
+JwUCVZLAygIbAwUJB4YfgAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRBX/5vb
+zDAQCauuD/9IDWhf/fTseA1Rt5i4gwK+8dCQjTlRS2cZtGc2aMX8w5XruDWnna1P
+Mj/aVUncDrprRx9rxgEqIDyPheuJ6r7v6D8GjrpAjcG/BPNFtPaxQccbZbAYdzoj
+Rrs+ttVIqS+wO7qLmQkKA4oGRMmgYh3VX8EBZNcvxaGCcJx0PfoqS8cPXTnCRHcg
+Wx6kaFyuWtrTX+kCpDraB1KGtxedR4rzuOtUOLoqFOOfsQuOxPlKNNr9Zjc8x2o4
+5TtwbuoEog8FIEttY6NOywpsSsvYvNB4gq1fxO49H0pQopmJlOMatMH6IRT7BJJZ
+cOoHOh4X/zItOJZtuCOT4u+Y2XOuyLcW83X5ymIR3ZCxedsLzjyiCWm61/znJVON
+Ws8I+gShbvauahBCB9rOHqwM0QioJMc36hUPB21KghQS8RJpGwmtk1WhFFMtAsSJ
+w+wRfy2d6u+lSGdlA+2hEyKVm/DNQMDCQVFx3lQ6YBwAwkSiLMylrPKvs56fUjRr
+74qoPyDxuRMC+q+TThHsy5O9r31G+Dc3+H5k4iTk354Jshjltx/k2O732e9Vxyar
+/U5P7UZqHHuJKXDihUFrcJZq+gk8sGEWzGG/wocce7ezrTnHqR8YA04BTA4PXQqZ
+4N42f422YYGIH/3Nm6drQkbigekLw6wx+NrxtTsYg4eCtSsaUd/RjLQhU2pvcnMg
+UHJvdm9vc3QgPHNqb3JzQGZyZWVkb20ubmw+iQI9BBMBCgAnBQJZZdyfAhsDBQkH
+hh+ABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEFf/m9vMMBAJEsIQAK4ihgRB
+05QqETpWNeV/XSGBHQINuwwEDz/k8dAJ5Uo6OoSpDULa16fs/EgAV46wTSxfWuci
+n2Fc1AWLeLDWOax/NlycL00VDHEwT2PCjcc5uMuwR4RUTciKyByT1u7BFToZ6PyL
+mbU6u6whcQejl6Ci2kw0Mu4n4bKTS7OL4/w/EbdfMSpRi8wWmTPMB/aMjtS2Mxi/
+N+yQhJ9pReHADeCBoAjq0cUy+QbzvBwDCK4XWRzF7kiFuA7UW2r7/dX6l31mPfi/
+GLA5+ftPxJ6EH8cxToF70OWiSfhOTleaqZaHUOG0V7wV2lr/bwAYzpVlxeZSCIta
+lAA9ZLzUD2hiHYcei6kc/YjIhmlml7O0FK1eBk7+bt5wr0nvWt4Lbha4y5LxBX8C
+d7InvB3xUYHz+S5Ul4vp0Rzx97MBL4oX2ltBEDpc1CcOgzv4dcWMG9bbh9/SaI/G
+RehAzwkbpVUl9AEUNKO0dNlZUdu8CkehHdPdz5sJyS/9zE0A7yIECDFP9Nrht0nK
+MahBijm4K+jOiLOZ2xyfOX1pVWLqIXGQHKjfcD3oI3qvGrQYtxB5Dffb9ACFMpZO
+z3jM8h2UAa2/KqA4MZiZG9N6uWHKkIAMMuXWs1s439WePvbQ+5aw/qPUAMyqA3XZ
+dkfn8QWaJPR4nRM+McYBYuS4fKK9HRJWQgcQuQINBFWSwMoBEACzmkabZ8oHWJUE
+beU7rJF/TMbwV1IFtFxJ/QlY8rE4VnHekPMvkLi/gjx3WY5nmMe+d4JYoK/uPNdt
+y5u0QYgH2MB/jebk4gYXCAHIPpU38h9UgHRb6qV8OaqHhmoXvKwyz+1QPzyJpmgg
+oCUN+OAroNjl7zhunE7w7EEddFQftfPoGKEUnTjv84QOCuAb46JsYyiNAc3h6okq
+74hY7PKCv8IRGclMPjemhBT2LEenn1t4yi7a8W/hjIe44PmQiqQEXR17keqcP/ls
+EH9xSST1v/70ieiPqb6zbHGWzjQxqpFUJxRU6OluBCy5pHVd8wfFGYrrbTpoxaUC
+jyA2SLr1oZZ9gaGprt6X7FC5gpE5LV9essq3O5wwvoPbyMe1F5uFaxIPhlt55oEu
+rwVWecFJ8tSjniF/WSkTcILrOmiQZ4mylXfOP9Wk38seZReCs799KEfKFlXHk89a
+Sj3ZvaJQxwVCnvsAsbVKmmHZ5wPt+G2KfhOkkv2A1I/UyeTT7aXvt2vxDqGuG0su
+Eo6QknM/2Sr5Uv7BwBeSIQ6llH5ZnqKz34+HjriP8YPWzvsC959GXsxS01dCSvUM
+92j5PvTZzf5dt1CWHMeufAY5XIH+nftkRniuScRhJ7xK3tJ7wngg7UvdeZwJWqmK
+lJ7GI38V8HIMnd2x28yiGpj1ue6T+QARAQABiQIlBBgBCgAPBQJVksDKAhsMBQkH
+hh+AAAoJEFf/m9vMMBAJjeIP/1UBCi6gSXzpGJBLD2u4PcZJjXBJAImZdf1aCqfS
+YZBCaA65UrM3uaVa7h8MGAJc9kDjpqHurjDmG3YWf33KvHWYmReQvX43pZmfF12s
+X7FZgcCfgZJKKj+ri6oHQonZzUMrecEcAJLLaQoD3Du3iZpETiyRLL7sJ1lZSaCJ
+gYKnN4WV5GypvdFvb8vSUBST2h0D6AewGKMNh8ruRlkIxI+YSlywgYIH+O0qNKqW
+wBlZc/5f+JZ3hu+cjx/+Zn+w+saIb6SgySg0UzN35b2WM2YzrfQep4ah3NIxuC7e
+qzmfV6GnRtuUrBLVJ8qyjif1JSM9tZfinnmAB4/U5Qfc+YYViIXMTljmHWvbokas
+tTBfVAw74yWnkv4ZuXf5SkTmGwEMJUOat0TSr085Ck5y394bRepdI1Y+1cdqpwMQ
+QmkKyvcBlREQ7Xk1UnDDR3o/2ieVuGGHRp8jmoWBWGq4Cm43fYOlVe+PcaX0tDns
+Tmmh2uwEU/TXe5qGil51OlSM7qhAMqhWUIYphSOcdvApNXuiWMfnTdjsNygE4HVh
+Jq4efJ/nlx5N+PNAK2GpzeUJQGyxiVsXybq+h8UlvytBsdz1X6ZYzBv1yYwANThU
+rMB1s4tMaEugX0aNByLcsxuS4ixd2qzwkYVz25Aeko/U1v2/j2cIRtrTNgja3BKE
+N5Ug
+=80Es
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/contrib/init/bitcoind.openrc b/contrib/init/bitcoind.openrc
index 50377c0995..86222295db 100644
--- a/contrib/init/bitcoind.openrc
+++ b/contrib/init/bitcoind.openrc
@@ -1,4 +1,4 @@
-#!/sbin/runscript
+#!/sbin/openrc-run
# backward compatibility for existing gentoo layout
#
diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service
index 9132957c38..ee113d7615 100644
--- a/contrib/init/bitcoind.service
+++ b/contrib/init/bitcoind.service
@@ -1,22 +1,25 @@
+# It is not recommended to modify this file in-place, because it will
+# be overwritten during package upgrades. If you want to add further
+# options or overwrite existing ones then use
+# $ systemctl edit bitcoind.service
+# See "man systemd.service" for details.
+
+# Note that almost all daemon options could be specified in
+# /etc/bitcoin/bitcoin.conf
+
[Unit]
-Description=Bitcoin's distributed currency daemon
+Description=Bitcoin daemon
After=network.target
[Service]
+ExecStart=/usr/bin/bitcoind -daemon -conf=/etc/bitcoin/bitcoin.conf -pid=/run/bitcoind/bitcoind.pid
+# Creates /run/bitcoind owned by bitcoin
+RuntimeDirectory=bitcoind
User=bitcoin
-Group=bitcoin
-
Type=forking
-PIDFile=/var/lib/bitcoind/bitcoind.pid
-ExecStart=/usr/bin/bitcoind -daemon -pid=/var/lib/bitcoind/bitcoind.pid \
--conf=/etc/bitcoin/bitcoin.conf -datadir=/var/lib/bitcoind -disablewallet
-
-Restart=always
+PIDFile=/run/bitcoind/bitcoind.pid
+Restart=on-failure
PrivateTmp=true
-TimeoutStopSec=60s
-TimeoutStartSec=2s
-StartLimitInterval=120s
-StartLimitBurst=5
[Install]
WantedBy=multi-user.target
diff --git a/contrib/valgrind.supp b/contrib/valgrind.supp
new file mode 100644
index 0000000000..0f6d993fd2
--- /dev/null
+++ b/contrib/valgrind.supp
@@ -0,0 +1,43 @@
+# Valgrind suppressions file for Bitcoin.
+#
+# Includes known Valgrind warnings in our dependencies that cannot be fixed
+# in-tree.
+#
+# Example use:
+# $ valgrind --suppressions=contrib/valgrind.supp src/test/test_bitcoin
+# $ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \
+# --show-leak-kinds=all src/test/test_bitcoin --log_level=test_suite
+{
+ Suppress libstdc++ warning - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65434
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:malloc
+ obj:*/libstdc++.*
+ fun:call_init.part.0
+ fun:call_init
+ fun:_dl_init
+ obj:*/ld-*.so
+}
+{
+ Suppress libdb warning - https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=662917
+ Memcheck:Cond
+ obj:*/libdb_cxx-*.so
+ fun:__log_put
+ obj:*/libdb_cxx-*.so
+ fun:__log_put_record
+}
+{
+ Suppress leveldb warning (leveldb::InitModule()) - https://github.com/google/leveldb/issues/113
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:_Znwm
+ fun:_ZN7leveldbL10InitModuleEv
+}
+{
+ Suppress leveldb warning (leveldb::Env::Default()) - https://github.com/google/leveldb/issues/113
+ Memcheck:Leak
+ match-leak-kinds: reachable
+ fun:_Znwm
+ ...
+ fun:_ZN7leveldbL14InitDefaultEnvEv
+}
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
index b01e2a6d39..abd8f5fd9f 100755
--- a/contrib/verify-commits/gpg.sh
+++ b/contrib/verify-commits/gpg.sh
@@ -46,6 +46,11 @@ for LINE in $(echo "$GPG_RES"); do
REVSIG=true
GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
;;
+ "[GNUPG:] EXPKEYSIG "*)
+ [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
+ REVSIG=true
+ GOODREVSIG="[GNUPG:] GOODSIG ${LINE#* * *}"
+ ;;
esac
done
if ! $VALID; then
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
index 74b7f38375..a1ef715fb3 100755
--- a/contrib/verify-commits/verify-commits.sh
+++ b/contrib/verify-commits/verify-commits.sh
@@ -12,8 +12,6 @@ VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root")
VERIFIED_SHA512_ROOT=$(cat "${DIR}/trusted-sha512-root-commit")
REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits")
-HAVE_FAILED=false
-
HAVE_GNU_SHA512=1
[ ! -x "$(which sha512sum)" ] && HAVE_GNU_SHA512=0
@@ -39,7 +37,7 @@ PREV_COMMIT=""
while true; do
if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then
echo "There is a valid path from "$CURRENT_COMMIT" to $VERIFIED_ROOT where all commits are signed!"
- exit 0;
+ exit 0
fi
if [ "$CURRENT_COMMIT" = $VERIFIED_SHA512_ROOT ]; then
@@ -95,9 +93,9 @@ while true; do
FILE_HASHES=""
for FILE in $(git ls-tree --full-tree -r --name-only "$CURRENT_COMMIT" | LC_ALL=C sort); do
if [ "$HAVE_GNU_SHA512" = 1 ]; then
- HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } )
+ HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST _; echo $FIRST; } )
else
- HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST OTHER; echo $FIRST; } )
+ HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST _; echo $FIRST; } )
fi
[ "$FILE_HASHES" != "" ] && FILE_HASHES="$FILE_HASHES"'
'
diff --git a/contrib/verifybinaries/verify.sh b/contrib/verifybinaries/verify.sh
index 409f517c9f..320add64d0 100755
--- a/contrib/verifybinaries/verify.sh
+++ b/contrib/verifybinaries/verify.sh
@@ -76,8 +76,6 @@ if [ -n "$1" ]; then
BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSION/"
fi
fi
-
- SIGNATUREFILE="$BASEDIR$SIGNATUREFILENAME"
else
echo "Error: need to specify a version on the command line"
exit 2
diff --git a/doc/build-openbsd.md b/doc/build-openbsd.md
index 4ea8e30b53..760bb69b15 100644
--- a/doc/build-openbsd.md
+++ b/doc/build-openbsd.md
@@ -1,10 +1,10 @@
OpenBSD build guide
======================
-(updated for OpenBSD 6.1)
+(updated for OpenBSD 6.2)
This guide describes how to build bitcoind and command-line utilities on OpenBSD.
-As OpenBSD is most common as a server OS, we will not bother with the GUI.
+OpenBSD is most commonly used as a server OS, so this guide does not contain instructions for building the GUI.
Preparation
-------------
@@ -12,10 +12,13 @@ Preparation
Run the following as root to install the base dependencies for building:
```bash
-pkg_add gmake libtool libevent
+pkg_add git gmake libevent libtool
pkg_add autoconf # (select highest version, e.g. 2.69)
pkg_add automake # (select highest version, e.g. 1.15)
-pkg_add python # (select highest version, e.g. 3.5)
+pkg_add python # (select highest version, e.g. 3.6)
+pkg_add boost
+
+git clone https://github.com/bitcoin/bitcoin.git
```
See [dependencies.md](dependencies.md) for a complete overview.
@@ -23,54 +26,19 @@ See [dependencies.md](dependencies.md) for a complete overview.
GCC
-------
-The default C++ compiler that comes with OpenBSD 5.9 is g++ 4.2. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core, primarily as it has no C++11 support, but even before there were issues. So here we will be installing a newer compiler:
+The default C++ compiler that comes with OpenBSD 6.2 is g++ 4.2.1. This version is old (from 2007), and is not able to compile the current version of Bitcoin Core because it has no C++11 support. We'll install a newer version of GCC:
```bash
-pkg_add g++ # (select newest 4.x version, e.g. 4.9.3)
-```
-
-This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`.
-
-### Building boost
-
-Do not use `pkg_add boost`! The boost version installed thus is compiled using the `g++` compiler not `eg++`, which will result in a conflict between `/usr/local/lib/libestdc++.so.XX.0` and `/usr/lib/libstdc++.so.XX.0`, resulting in a test crash:
-
- test_bitcoin:/usr/lib/libstdc++.so.57.0: /usr/local/lib/libestdc++.so.17.0 : WARNING: symbol(_ZN11__gnu_debug17_S_debug_me ssagesE) size mismatch, relink your program
- ...
- Segmentation fault (core dumped)
+ pkg_add g++
+ ```
-This makes it necessary to build boost, or at least the parts used by Bitcoin Core, manually:
-
-```
-# Pick some path to install boost to, here we create a directory within the bitcoin directory
-BITCOIN_ROOT=$(pwd)
-BOOST_PREFIX="${BITCOIN_ROOT}/boost"
-mkdir -p $BOOST_PREFIX
-
-# Fetch the source and verify that it is not tampered with
-curl -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2
-echo '7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 boost_1_64_0.tar.bz2' | sha256 -c
-# MUST output: (SHA256) boost_1_64_0.tar.bz2: OK
-tar -xjf boost_1_64_0.tar.bz2
-
-# Boost 1.64 needs one small patch for OpenBSD
-cd boost_1_64_0
-# Also here: https://gist.githubusercontent.com/laanwj/bf359281dc319b8ff2e1/raw/92250de8404b97bb99d72ab898f4a8cb35ae1ea3/patch-boost_test_impl_execution_monitor_ipp.patch
-patch -p0 < /usr/ports/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp
-
-# Build w/ minimum configuration necessary for bitcoin
-echo 'using gcc : : eg++ : <cxxflags>"-fvisibility=hidden -fPIC" <linkflags>"" <archiver>"ar" <striper>"strip" <ranlib>"ranlib" <rc>"" : ;' > user-config.jam
-config_opts="runtime-link=shared threadapi=pthread threading=multi link=static variant=release --layout=tagged --build-type=complete --user-config=user-config.jam -sNO_BZIP2=1"
-./bootstrap.sh --without-icu --with-libraries=chrono,filesystem,program_options,system,thread,test
-./b2 -d2 -j2 -d1 ${config_opts} --prefix=${BOOST_PREFIX} stage
-./b2 -d0 -j4 ${config_opts} --prefix=${BOOST_PREFIX} install
-```
+ This compiler will not overwrite the system compiler, it will be installed as `egcc` and `eg++` in `/usr/local/bin`.
### Building BerkeleyDB
BerkeleyDB is only necessary for the wallet functionality. To skip this, pass `--disable-wallet` to `./configure`.
-See "Berkeley DB" in [build_unix.md](build_unix.md) for instructions on how to build BerkeleyDB 4.8.
+See "Berkeley DB" in [build-unix.md](build-unix.md#berkeley-db) for instructions on how to build BerkeleyDB 4.8.
You cannot use the BerkeleyDB library from ports, for the same reason as boost above (g++/libstd++ incompatibility).
```bash
@@ -98,8 +66,8 @@ The standard ulimit restrictions in OpenBSD are very strict:
data(kbytes) 1572864
-This is, unfortunately, no longer enough to compile some `.cpp` files in the project,
-at least with gcc 4.9.3 (see issue https://github.com/bitcoin/bitcoin/issues/6658).
+This, unfortunately, may no longer be enough to compile some `.cpp` files in the project,
+at least with GCC 4.9.4 (see issue [#6658](https://github.com/bitcoin/bitcoin/issues/6658)).
If your user is in the `staff` group the limit can be raised with:
ulimit -d 3000000
@@ -118,59 +86,32 @@ export AUTOCONF_VERSION=2.69 # replace this with the autoconf version that you i
export AUTOMAKE_VERSION=1.15 # replace this with the automake version that you installed
./autogen.sh
```
-Make sure `BDB_PREFIX` and `BOOST_PREFIX` are set to the appropriate paths from the above steps.
+Make sure `BDB_PREFIX` is set to the appropriate path from the above steps.
To configure with wallet:
```bash
-./configure --with-gui=no --with-boost=$BOOST_PREFIX \
- CC=egcc CXX=eg++ CPP=ecpp \
+./configure --with-gui=no CC=egcc CXX=eg++ CPP=ecpp \
BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include"
```
To configure without wallet:
```bash
-./configure --disable-wallet --with-gui=no --with-boost=$BOOST_PREFIX \
- CC=egcc CXX=eg++ CPP=ecpp
+./configure --disable-wallet --with-gui=no CC=egcc CXX=eg++ CPP=ecpp
```
Build and run the tests:
```bash
-gmake # can use -jX here for parallelism
+gmake # use -jX here for parallelism
gmake check
```
-Clang (not currently working)
+Clang
------------------------------
-WARNING: This is outdated, needs to be updated for OpenBSD 6.0 and re-tried.
-
-Using a newer g++ results in linking the new code to a new libstdc++.
-Libraries built with the old g++, will still import the old library.
-This gives conflicts, necessitating rebuild of all C++ dependencies of the application.
-
-With clang this can - at least theoretically - be avoided because it uses the
-base system's libstdc++.
-
```bash
-pkg_add llvm boost
-```
+pkg_add llvm
-```bash
./configure --disable-wallet --with-gui=no CC=clang CXX=clang++
-gmake
+gmake # use -jX here for parallelism
+gmake check
```
-
-However, this does not appear to work. Compilation succeeds, but link fails
-with many 'local symbol discarded' errors:
-
- local symbol 150: discarded in section `.text._ZN10tinyformat6detail14FormatIterator6finishEv' from libbitcoin_util.a(libbitcoin_util_a-random.o)
- local symbol 151: discarded in section `.text._ZN10tinyformat6detail14FormatIterator21streamStateFromFormatERSoRjPKcii' from libbitcoin_util.a(libbitcoin_util_a-random.o)
- local symbol 152: discarded in section `.text._ZN10tinyformat6detail12convertToIntIA13_cLb0EE6invokeERA13_Kc' from libbitcoin_util.a(libbitcoin_util_a-random.o)
-
-According to similar reported errors this is a binutils (ld) issue in 2.15, the
-version installed by OpenBSD 5.7:
-
-- http://openbsd-archive.7691.n7.nabble.com/UPDATE-cppcheck-1-65-td248900.html
-- https://llvm.org/bugs/show_bug.cgi?id=9758
-
-There is no known workaround for this.
diff --git a/doc/build-windows.md b/doc/build-windows.md
index 0d96af26a2..9e3e38d188 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -4,11 +4,14 @@ WINDOWS BUILD NOTES
Below are some notes on how to build Bitcoin Core for Windows.
Most developers use cross-compilation from Ubuntu to build executables for
-Windows. Cross-compilation is also used to build the release binaries.
+Windows. This is also used to build the release binaries.
-Currently only building on Ubuntu Trusty 14.04 or Ubuntu Zesty 17.04 or later is supported.
-Building on Ubuntu Xenial 16.04 is known to be broken, see extensive discussion in issue [8732](https://github.com/bitcoin/bitcoin/issues/8732).
-While it may be possible to do so with work arounds, it's potentially dangerous and not recommended.
+Building on Ubuntu Trusty 14.04 is recommended.
+At the time of writing the Windows Subsystem for Linux installs Ubuntu Xenial 16.04. The default cross
+compiler package for Ubuntu Xenial does not produce working executables for some of the bitcoin applications.
+It is possible to build on Ubuntu Xenial by installing the cross compiler packages from
+Ubuntu Zesty, see the steps below.
+Building on Ubuntu Zesty 17.04 up to 17.10 has been verified to work.
While there are potentially a number of ways to build on Windows (for example using msys / mingw-w64),
using the Windows Subsystem For Linux is the most straightforward. If you are building with
@@ -19,7 +22,7 @@ Compiling with Windows Subsystem For Linux
-------------------------------------------
With Windows 10, Microsoft has released a new feature named the [Windows
-Subsystem for Linux](https://msdn.microsoft.com/commandline/wsl/about). This
+Subsystem for Linux (WSL)](https://msdn.microsoft.com/commandline/wsl/about). This
feature allows you to run a bash shell directly on Windows in an Ubuntu-based
environment. Within this environment you can cross compile for Windows without
the need for a separate Linux VM or server.
@@ -28,20 +31,19 @@ This feature is not supported in versions of Windows prior to Windows 10 or on
Windows Server SKUs. In addition, it is available [only for 64-bit versions of
Windows](https://msdn.microsoft.com/en-us/commandline/wsl/install_guide).
-To get the bash shell, you must first activate the feature in Windows.
+Full instructions to install WSL are available on the above link.
+To install WSL on Windows 10 with Fall Creators Update installed (version >= 16215.0) do the following:
-1. Turn on Developer Mode
- * Open Settings -> Update and Security -> For developers
- * Select the Developer Mode radio button
- * Restart if necessary
-2. Enable the Windows Subsystem for Linux feature
+1. Enable the Windows Subsystem for Linux feature
* From Start, search for "Turn Windows features on or off" (type 'turn')
- * Select Windows Subsystem for Linux (beta)
+ * Select Windows Subsystem for Linux
* Click OK
* Restart if necessary
+2. Install Ubuntu
+ * Open Microsoft Store and search for Ubuntu or use [this link](https://www.microsoft.com/store/productId/9NBLGGH4MSV6)
+ * Click Install
3. Complete Installation
- * Open a cmd prompt and type "bash"
- * Accept the license
+ * Open a cmd prompt and type "Ubuntu"
* Create a new UNIX user account (this is a separate account from your Windows account)
After the bash shell is active, you can follow the instructions below, starting
@@ -57,7 +59,7 @@ installing the toolchain will be different.
First, install the general dependencies:
- sudo apt-get install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl
+ sudo apt install build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git
A host toolchain (`build-essential`) is necessary because some dependency
packages (such as `protobuf`) need to build host utilities that are used in the
@@ -65,20 +67,32 @@ build process.
See also: [dependencies.md](dependencies.md).
-If you're building on Ubuntu 17.04 or later, run these two commands, selecting the 'posix' variant for both,
-to work around issues with mingw-w64. See issue [8732](https://github.com/bitcoin/bitcoin/issues/8732) for more information.
-```
-sudo update-alternatives --config x86_64-w64-mingw32-g++
-sudo update-alternatives --config x86_64-w64-mingw32-gcc
-```
-
## Building for 64-bit Windows
-To build executables for Windows 64-bit, install the following dependencies:
+The first step is to install the mingw-w64 cross-compilation tool chain. Due to different Ubuntu
+packages for each distribution and problems with the Xenial packages the steps for each are different.
- sudo apt-get install g++-mingw-w64-x86-64 mingw-w64-x86-64-dev
+Common steps to install mingw32 cross compiler tool chain:
-Then build using:
+ sudo apt install g++-mingw-w64-x86-64
+
+Ubuntu Trusty 14.04:
+
+ No further steps required
+
+Ubuntu Xenial 16.04 and Windows Subsystem for Linux <sup>[1](#footnote1),[2](#footnote2)</sup>:
+
+ sudo apt install software-properties-common
+ sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu zesty universe"
+ sudo apt update
+ sudo apt upgrade
+ sudo update-alternatives --config x86_64-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix.
+
+Ubuntu Zesty 17.04 <sup>[2](#footnote2)</sup>:
+
+ sudo update-alternatives --config x86_64-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix.
+
+Once the tool chain is installed the build steps are common:
PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var
cd depends
@@ -92,7 +106,11 @@ Then build using:
To build executables for Windows 32-bit, install the following dependencies:
- sudo apt-get install g++-mingw-w64-i686 mingw-w64-i686-dev
+ sudo apt install g++-mingw-w64-i686 mingw-w64-i686-dev
+
+For Ubuntu Xenial 16.04, Ubuntu Zesty 17.04 and Windows Subsystem for Linux <sup>[2](#footnote2)</sup>:
+
+ sudo update-alternatives --config i686-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix.
Then build using:
@@ -117,3 +135,20 @@ as they appear in the release `.zip` archive. This can be done in the following
way. This will install to `c:\workspace\bitcoin`, for example:
make install DESTDIR=/mnt/c/workspace/bitcoin
+
+Footnotes
+---------
+
+<a name="footnote1">1</a>: There is currently a bug in the 64 bit mingw-w64 cross compiler packaged for WSL/Ubuntu Xenial 16.04 that
+causes two of the bitcoin executables to crash shortly after start up. The bug is related to the
+-fstack-protector-all g++ compiler flag which is used to mitigate buffer overflows.
+Installing the mingw-w64 packages from the Ubuntu 17 distribution solves the issue, however, this is not
+an officially supported approach and it's only recommended if you are prepared to reinstall WSL/Ubuntu should
+something break.
+
+<a name="footnote2">2</a>: Starting from Ubuntu Xenial 16.04 both the 32 and 64 bit mingw-w64 packages install two different
+compiler options to allow a choice between either posix or win32 threads. The default option is win32 threads which is the more
+efficient since it will result in binary code that links directly with the Windows kernel32.lib. Unfortunately, the headers
+required to support win32 threads conflict with some of the classes in the C++11 standard library in particular std::mutex.
+It's not possible to build the bitcoin code using the win32 version of the mingw-w64 cross compilers (at least not without
+modifying headers in the bitcoin source code).
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 33c6ab9cb3..7f34b07d15 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -167,6 +167,37 @@ can be very difficult to track down. Compiling with -DDEBUG_LOCKORDER (configure
CXXFLAGS="-DDEBUG_LOCKORDER -g") inserts run-time checks to keep track of which locks
are held, and adds warnings to the debug.log file if inconsistencies are detected.
+**Valgrind suppressions file**
+
+Valgrind is a programming tool for memory debugging, memory leak detection, and
+profiling. The repo contains a Valgrind suppressions file
+([`valgrind.supp`](https://github.com/bitcoin/bitcoin/blob/master/contrib/valgrind.supp))
+which includes known Valgrind warnings in our dependencies that cannot be fixed
+in-tree. Example use:
+
+```shell
+$ valgrind --suppressions=contrib/valgrind.supp src/test/test_bitcoin
+$ valgrind --suppressions=contrib/valgrind.supp --leak-check=full \
+ --show-leak-kinds=all src/test/test_bitcoin --log_level=test_suite
+$ valgrind -v --leak-check=full src/bitcoind -printtoconsole
+```
+
+**compiling for test coverage**
+
+LCOV can be used to generate a test coverage report based upon `make check`
+execution. LCOV must be installed on your system (e.g. the `lcov` package
+on Debian/Ubuntu).
+
+To enable LCOV report generation during test runs:
+
+```shell
+./configure --enable-lcov
+make
+make cov
+
+# A coverage report will now be accessible at `./test_bitcoin.coverage/index.html`.
+```
+
Locking/mutex usage notes
-------------------------
@@ -461,6 +492,14 @@ namespace {
- *Rationale*: Avoids confusion about the namespace context
+- Prefer `#include <primitives/transaction.h>` bracket syntax instead of
+ `#include "primitives/transactions.h"`` quote syntax when possible.
+
+ - *Rationale*: Bracket syntax is less ambiguous because the preprocessor
+ searches a fixed list of include directories without taking location of the
+ source file into account. This allows quoted includes to stand out more when
+ the location of the source file actually is relevant.
+
GUI
-----
@@ -644,3 +683,16 @@ A few guidelines for introducing and reviewing new RPC interfaces:
- *Rationale*: If a RPC response is not a JSON object then it is harder to avoid API breakage if
new data in the response is needed.
+
+- Wallet RPCs call BlockUntilSyncedToCurrentChain to maintain consistency with
+ `getblockchaininfo`'s state immediately prior to the call's execution. Wallet
+ RPCs whose behavior does *not* depend on the current chainstate may omit this
+ call.
+
+ - *Rationale*: In previous versions of Bitcoin Core, the wallet was always
+ in-sync with the chainstate (by virtue of them all being updated in the
+ same cs_main lock). In order to maintain the behavior that wallet RPCs
+ return results as of at least the highest best-known block an RPC
+ client may be aware of prior to entering a wallet RPC call, we must block
+ until the wallet is caught up to the chainstate as of the RPC call's entry.
+ This also makes the API much easier for RPC clients to reason about.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 4ecca7897c..6e4fed0a2d 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -56,18 +56,6 @@ frequently tested on them.
Notable changes
===============
-Miner block size limiting deprecated
-------------------------------------
-
-Though blockmaxweight has been preferred for limiting the size of blocks returned by
-getblocktemplate since 0.13.0, blockmaxsize remained as an option for those who wished
-to limit their block size directly. Using this option resulted in a few UI issues as
-well as non-optimal fee selection and ever-so-slightly worse performance, and has thus
-now been deprecated. Further, the blockmaxsize option is now used only to calculate an
-implied blockmaxweight, instead of limiting block size directly. Any miners who wish
-to limit their blocks by size, instead of by weight, will have to do so manually by
-removing transactions from their block template directly.
-
HD-wallets by default
---------------------
Due to a backward-incompatible change in the wallet database, wallets created
@@ -76,15 +64,13 @@ will only create hierarchical deterministic (HD) wallets.
Low-level RPC changes
----------------------
-- The "currentblocksize" value in getmininginfo has been removed.
- The deprecated RPC `getinfo` was removed. It is recommended that the more specific RPCs are used:
* `getblockchaininfo`
* `getnetworkinfo`
* `getwalletinfo`
* `getmininginfo`
+- The wallet RPC `getreceivedbyaddress` will return an error if called with an address not in the wallet.
-- `dumpwallet` no longer allows overwriting files. This is a security measure
- as well as prevents dangerous user mistakes.
Credits
=======
diff --git a/doc/release-notes/release-notes-0.15.1.md b/doc/release-notes/release-notes-0.15.1.md
new file mode 100644
index 0000000000..75d2e09714
--- /dev/null
+++ b/doc/release-notes/release-notes-0.15.1.md
@@ -0,0 +1,277 @@
+Bitcoin Core version *0.15.1* is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-0.15.1/>
+
+or
+
+ <https://bitcoin.org/bin/bitcoin-core-0.15.1/>
+
+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:
+
+ <https://github.com/bitcoin/bitcoin/issues>
+
+To receive security and update notifications, please subscribe to:
+
+ <https://bitcoincore.org/en/list/announcements/join/>
+
+How to Upgrade
+==============
+
+If you are running an older version, shut it down. Wait until it has completely
+shut down (which might take a few minutes for older versions), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+The first time you run version 0.15.0 or higher, your chainstate database will
+be converted to a new format, which will take anywhere from a few minutes to
+half an hour, depending on the speed of your machine.
+
+The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a
+downgrade from version 0.15 or upgrade to version 0.15 will cause all fee
+estimates to be discarded.
+
+Note that the block database format also changed in version 0.8.0 and there is no
+automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading
+directly from 0.7.x and earlier without redownloading the blockchain is not supported.
+However, as usual, old wallet versions are still supported.
+
+Downgrading warning
+-------------------
+
+The chainstate database for this release is not compatible with previous
+releases, so if you run 0.15 and then decide to switch back to any
+older version, you will need to run the old release with the `-reindex-chainstate`
+option to rebuild the chainstate data structures in the old format.
+
+If your node has pruning enabled, this will entail re-downloading and
+processing the entire blockchain.
+
+Compatibility
+==============
+
+Bitcoin Core is extensively tested on multiple operating systems using
+the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+frequently tested on them.
+
+
+Notable changes
+===============
+
+Network fork safety enhancements
+--------------------------------
+
+A number of changes to the way Bitcoin Core deals with peer connections and invalid blocks
+have been made, as a safety precaution against blockchain forks and misbehaving peers.
+
+- Unrequested blocks with less work than the minimum-chain-work are now no longer processed even
+if they have more work than the tip (a potential issue during IBD where the tip may have low-work).
+This prevents peers wasting the resources of a node.
+
+- Peers which provide a chain with less work than the minimum-chain-work during IBD will now be disconnected.
+
+- For a given outbound peer, we now check whether their best known block has at least as much work as our tip. If it
+doesn't, and if we still haven't heard about a block with sufficient work after a 20 minute timeout, then we send
+a single getheaders message, and wait 2 more minutes. If after two minutes their best known block has insufficient
+work, we disconnect that peer. We protect 4 of our outbound peers from being disconnected by this logic to prevent
+excessive network topology changes as a result of this algorithm, while still ensuring that we have a reasonable
+number of nodes not known to be on bogus chains.
+
+- Outbound (non-manual) peers that serve us block headers that are already known to be invalid (other than compact
+block announcements, because BIP 152 explicitly permits nodes to relay compact blocks before fully validating them)
+will now be disconnected.
+
+- If the chain tip has not been advanced for over 30 minutes, we now assume the tip may be stale and will try to connect
+to an additional outbound peer. A periodic check ensures that if this extra peer connection is in use, we will disconnect
+the peer that least recently announced a new block.
+
+- The set of all known invalid-themselves blocks (i.e. blocks which we attempted to connect but which were found to be
+invalid) are now tracked and used to check if new headers build on an invalid chain. This ensures that everything that
+descends from an invalid block is marked as such.
+
+
+Miner block size limiting deprecated
+------------------------------------
+
+Though blockmaxweight has been preferred for limiting the size of blocks returned by
+getblocktemplate since 0.13.0, blockmaxsize remained as an option for those who wished
+to limit their block size directly. Using this option resulted in a few UI issues as
+well as non-optimal fee selection and ever-so-slightly worse performance, and has thus
+now been deprecated. Further, the blockmaxsize option is now used only to calculate an
+implied blockmaxweight, instead of limiting block size directly. Any miners who wish
+to limit their blocks by size, instead of by weight, will have to do so manually by
+removing transactions from their block template directly.
+
+
+GUI settings backed up on reset
+-------------------------------
+
+The GUI settings will now be written to `guisettings.ini.bak` in the data directory before wiping them when
+the `-resetguisettings` argument is used. This can be used to retroactively troubleshoot issues due to the
+GUI settings.
+
+
+Duplicate wallets disallowed
+----------------------------
+
+Previously, it was possible to open the same wallet twice by manually copying the wallet file, causing
+issues when both were opened simultaneously. It is no longer possible to open copies of the same wallet.
+
+
+Debug `-minimumchainwork` argument added
+----------------------------------------
+
+A hidden debug argument `-minimumchainwork` has been added to allow a custom minimum work value to be used
+when validating a chain.
+
+
+Low-level RPC changes
+----------------------
+
+- The "currentblocksize" value in getmininginfo has been removed.
+
+- `dumpwallet` no longer allows overwriting files. This is a security measure
+ as well as prevents dangerous user mistakes.
+
+- `backupwallet` will now fail when attempting to backup to source file, rather than
+ destroying the wallet.
+
+- `listsinceblock` will now throw an error if an unknown `blockhash` argument
+ value is passed, instead of returning a list of all wallet transactions since
+ the genesis block. The behaviour is unchanged when an empty string is provided.
+
+0.15.1 Change log
+=================
+
+### Mining
+- #11100 `7871a7d` Fix confusing blockmax{size,weight} options, dont default to throwing away money (TheBlueMatt)
+
+### RPC and other APIs
+- #10859 `2a5d099` gettxout: Slightly improve doc and tests (jtimon)
+- #11267 `b1a6c94` update cli for estimate\*fee argument rename (laanwj)
+- #11483 `20cdc2b` Fix importmulti bug when importing an already imported key (pedrobranco)
+- #9937 `a43be5b` Prevent `dumpwallet` from overwriting files (laanwj)
+- #11465 `405e069` Update named args documentation for importprivkey (dusty-wil)
+- #11131 `b278a43` Write authcookie atomically (laanwj)
+- #11565 `7d4546f` Make listsinceblock refuse unknown block hash (ryanofsky)
+- #11593 `8195cb0` Work-around an upstream libevent bug (theuni)
+
+### P2P protocol and network code
+- #11397 `27e861a` Improve and document SOCKS code (laanwj)
+- #11252 `0fe2a9a` When clearing addrman clear mapInfo and mapAddr (instagibbs)
+- #11527 `a2bd86a` Remove my testnet DNS seed (schildbach)
+- #10756 `0a5477c` net processing: swap out signals for an interface class (theuni)
+- #11531 `55b7abf` Check that new headers are not a descendant of an invalid block (more effeciently) (TheBlueMatt)
+- #11560 `49bf090` Connect to a new outbound peer if our tip is stale (sdaftuar)
+- #11568 `fc966bb` Disconnect outbound peers on invalid chains (sdaftuar)
+- #11578 `ec8dedf` Add missing lock in ProcessHeadersMessage(...) (practicalswift)
+- #11456 `6f27965` Replace relevant services logic with a function suite (TheBlueMatt)
+- #11490 `bf191a7` Disconnect from outbound peers with bad headers chains (sdaftuar)
+
+### Validation
+- #10357 `da4908c` Allow setting nMinimumChainWork on command line (sdaftuar)
+- #11458 `2df65ee` Don't process unrequested, low-work blocks (sdaftuar)
+
+### Build system
+- #11440 `b6c0209` Fix validationinterface build on super old boost/clang (TheBlueMatt)
+- #11530 `265bb21` Add share/rpcuser to dist. source code archive (MarcoFalke)
+
+### GUI
+- #11334 `19d63e8` Remove custom fee radio group and remove nCustomFeeRadio setting (achow101)
+- #11198 `7310f1f` Fix display of package name on 'open config file' tooltip (esotericnonsense)
+- #11015 `6642558` Add delay before filtering transactions (lclc)
+- #11338 `6a62c74` Backup former GUI settings on `-resetguisettings` (laanwj)
+- #11335 `8d13b42` Replace save|restoreWindowGeometry with Qt functions (MeshCollider)
+- #11237 `2e31b1d` Fixing division by zero in time remaining (MeshCollider)
+- #11247 `47c02a8` Use IsMine to validate custom change address (MarcoFalke)
+
+### Wallet
+- #11017 `9e8aae3` Close DB on error (kallewoof)
+- #11225 `6b4d9f2` Update stored witness in AddToWallet (sdaftuar)
+- #11126 `2cb720a` Acquire cs_main lock before cs_wallet during wallet initialization (ryanofsky)
+- #11476 `9c8006d` Avoid opening copied wallet databases simultaneously (ryanofsky)
+- #11492 `de7053f` Fix leak in CDB constructor (promag)
+- #11376 `fd79ed6` Ensure backupwallet fails when attempting to backup to source file (tomasvdw)
+- #11326 `d570aa4` Fix crash on shutdown with invalid wallet (MeshCollider)
+
+### Tests and QA
+- #11399 `a825d4a` Fix bip68-sequence rpc test (jl2012)
+- #11150 `847c75e` Add getmininginfo test (mess110)
+- #11407 `806c78f` add functional test for mempoolreplacement command line arg (instagibbs)
+- #11433 `e169349` Restore bitcoin-util-test py2 compatibility (MarcoFalke)
+- #11308 `2e1ac70` zapwallettxes: Wait up to 3s for mempool reload (MarcoFalke)
+- #10798 `716066d` test bitcoin-cli (jnewbery)
+- #11443 `019c492` Allow "make cov" out-of-tree; Fix rpc mapping check (MarcoFalke)
+- #11445 `51bad91` 0.15.1 Backports (MarcoFalke)
+- #11319 `2f0b30a` Fix error introduced into p2p-segwit.py, and prevent future similar errors (sdaftuar)
+- #10552 `e4605d9` Tests for zmqpubrawtx and zmqpubrawblock (achow101)
+- #11067 `eeb24a3` TestNode: Add wait_until_stopped helper method (MarcoFalke)
+- #11068 `5398f20` Move wait_until to util (MarcoFalke)
+- #11125 `812c870` Add bitcoin-cli -stdin and -stdinrpcpass functional tests (promag)
+- #11077 `1d80d1e` fix timeout issues from TestNode (jnewbery)
+- #11078 `f1ced0d` Make p2p-leaktests.py more robust (jnewbery)
+- #11210 `f3f7891` Stop test_bitcoin-qt touching ~/.bitcoin (MeshCollider)
+- #11234 `f0b6795` Remove redundant testutil.cpp|h files (MeshCollider)
+- #11215 `cef0319` fixups from set_test_params() (jnewbery)
+- #11345 `f9cf7b5` Check connectivity before sending in assumevalid.py (jnewbery)
+- #11091 `c276c1e` Increase initial RPC timeout to 60 seconds (laanwj)
+- #10711 `fc2aa09` Introduce TestNode (jnewbery)
+- #11230 `d8dd8e7` Fixup dbcrash interaction with add_nodes() (jnewbery)
+- #11241 `4424176` Improve signmessages functional test (mess110)
+- #11116 `2c4ff35` Unit tests for script/standard and IsMine functions (jimpo)
+- #11422 `a36f332` Verify DBWrapper iterators are taking snapshots (TheBlueMatt)
+- #11121 `bb5e7cb` TestNode tidyups (jnewbery)
+- #11521 `ca0f3f7` travis: move back to the minimal image (theuni)
+- #11538 `adbc9d1` Fix race condition failures in replace-by-fee.py, sendheaders.py (sdaftuar)
+- #11472 `4108879` Make tmpdir option an absolute path, misc cleanup (MarcoFalke)
+- #10853 `5b728c8` Fix RPC failure testing (again) (jnewbery)
+- #11310 `b6468d3` Test listwallets RPC (mess110)
+
+### Miscellaneous
+- #11377 `75997c3` Disallow uncompressed pubkeys in bitcoin-tx [multisig] output adds (TheBlueMatt)
+- #11437 `dea3b87` [Docs] Update Windows build instructions for using WSL and Ubuntu 17.04 (fanquake)
+- #11318 `8b61aee` Put back inadvertently removed copyright notices (gmaxwell)
+- #11442 `cf18f42` [Docs] Update OpenBSD Build Instructions for OpenBSD 6.2 (fanquake)
+- #10957 `50bd3f6` Avoid returning a BIP9Stats object with uninitialized values (practicalswift)
+- #11539 `01223a0` [verify-commits] Allow revoked keys to expire (TheBlueMatt)
+
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- Andreas Schildbach
+- Andrew Chow
+- Chris Moore
+- Cory Fields
+- Cristian Mircea Messel
+- Daniel Edgecumbe
+- Donal OConnor
+- Dusty Williams
+- fanquake
+- Gregory Sanders
+- Jim Posen
+- John Newbery
+- Johnson Lau
+- João Barbosa
+- Jorge Timón
+- Karl-Johan Alm
+- Lucas Betschart
+- MarcoFalke
+- Matt Corallo
+- Paul Berg
+- Pedro Branco
+- Pieter Wuille
+- practicalswift
+- Russell Yanofsky
+- Samuel Dobson
+- Suhas Daftuar
+- Tomas van der Wansem
+- Wladimir J. van der Laan
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/src/Makefile.am b/src/Makefile.am
index 90deff48b0..29e4ae56d0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,7 @@ else
LIBUNIVALUE = $(UNIVALUE_LIBS)
endif
-BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
BITCOIN_INCLUDES += $(UNIVALUE_CFLAGS)
@@ -500,10 +500,6 @@ clean-local:
## FIXME: How to get the appropriate modulename_CPPFLAGS in here?
$(AM_V_GEN) $(WINDRES) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) -DWINDRES_PREPROC -i $< -o $@
-.mm.o:
- $(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
- $(CPPFLAGS) $(AM_CXXFLAGS) $(QT_INCLUDES) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $<
-
check-symbols: $(bin_PROGRAMS)
if GLIBC_BACK_COMPAT
@echo "Checking glibc back compat..."
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index e4b64c1ca7..cbf3960cc7 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -362,12 +362,12 @@ RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png)
BITCOIN_RC = qt/res/bitcoin-qt-res.rc
-BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \
- -I$(builddir)/qt/forms -DQT_NO_KEYWORDS
+BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS
qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
+qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
$(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index d3e7b5da12..f037705aaf 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -96,7 +96,7 @@ BITCOIN_TESTS += \
endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
-test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
+test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD =
if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 7f85c16585..0f9ccf1e9a 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -3,17 +3,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addrdb.h"
-
-#include "addrman.h"
-#include "chainparams.h"
-#include "clientversion.h"
-#include "fs.h"
-#include "hash.h"
-#include "random.h"
-#include "streams.h"
-#include "tinyformat.h"
-#include "util.h"
+#include <addrdb.h>
+
+#include <addrman.h>
+#include <chainparams.h>
+#include <clientversion.h>
+#include <fs.h>
+#include <hash.h>
+#include <random.h>
+#include <streams.h>
+#include <tinyformat.h>
+#include <util.h>
namespace {
diff --git a/src/addrdb.h b/src/addrdb.h
index d930de204d..098da4240e 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_ADDRDB_H
#define BITCOIN_ADDRDB_H
-#include "fs.h"
-#include "serialize.h"
+#include <fs.h>
+#include <serialize.h>
#include <string>
#include <map>
diff --git a/src/addrman.cpp b/src/addrman.cpp
index a56bb4f9c1..ddcdf4c2f4 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addrman.h"
+#include <addrman.h>
-#include "hash.h"
-#include "serialize.h"
-#include "streams.h"
+#include <hash.h>
+#include <serialize.h>
+#include <streams.h>
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
diff --git a/src/addrman.h b/src/addrman.h
index 18f3062287..b06b272962 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_ADDRMAN_H
#define BITCOIN_ADDRMAN_H
-#include "netaddress.h"
-#include "protocol.h"
-#include "random.h"
-#include "sync.h"
-#include "timedata.h"
-#include "util.h"
+#include <netaddress.h>
+#include <protocol.h>
+#include <random.h>
+#include <sync.h>
+#include <timedata.h>
+#include <util.h>
#include <map>
#include <set>
@@ -455,6 +455,7 @@ public:
void Clear()
{
+ LOCK(cs);
std::vector<int>().swap(vRandom);
nKey = GetRandHash();
for (size_t bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index b4952af6f4..738224fb70 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "arith_uint256.h"
+#include <arith_uint256.h>
-#include "uint256.h"
-#include "utilstrencodings.h"
-#include "crypto/common.h"
+#include <uint256.h>
+#include <utilstrencodings.h>
+#include <crypto/common.h>
#include <stdio.h>
#include <string.h>
diff --git a/src/arith_uint256.h b/src/arith_uint256.h
index 5fd4fe96cf..1009fe1cc8 100644
--- a/src/arith_uint256.h
+++ b/src/arith_uint256.h
@@ -25,7 +25,7 @@ template<unsigned int BITS>
class base_uint
{
protected:
- enum { WIDTH=BITS/32 };
+ static constexpr int WIDTH = BITS / 32;
uint32_t pn[WIDTH];
public:
diff --git a/src/base58.cpp b/src/base58.cpp
index 9d5a2f4964..cd087e7997 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
+#include <base58.h>
-#include "bech32.h"
-#include "hash.h"
-#include "script/script.h"
-#include "uint256.h"
-#include "utilstrencodings.h"
+#include <bech32.h>
+#include <hash.h>
+#include <script/script.h>
+#include <uint256.h>
+#include <utilstrencodings.h>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
diff --git a/src/base58.h b/src/base58.h
index 9dc4234248..fee79f02bf 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -14,11 +14,11 @@
#ifndef BITCOIN_BASE58_H
#define BITCOIN_BASE58_H
-#include "chainparams.h"
-#include "key.h"
-#include "pubkey.h"
-#include "script/standard.h"
-#include "support/allocators/zeroafterfree.h"
+#include <chainparams.h>
+#include <key.h>
+#include <pubkey.h>
+#include <script/standard.h>
+#include <support/allocators/zeroafterfree.h>
#include <string>
#include <vector>
diff --git a/src/bech32.cpp b/src/bech32.cpp
index 573eac58bb..274782e467 100644
--- a/src/bech32.cpp
+++ b/src/bech32.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bech32.h"
+#include <bech32.h>
namespace
{
diff --git a/src/bench/Examples.cpp b/src/bench/Examples.cpp
index 314947d48c..536e450940 100644
--- a/src/bench/Examples.cpp
+++ b/src/bench/Examples.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "validation.h"
-#include "utiltime.h"
+#include <bench/bench.h>
+#include <validation.h>
+#include <utiltime.h>
// Sanity test: this should loop ten times, and
// min/max/average should be close to 100ms.
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 65e27a615d..8f6d07ac16 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "validation.h"
-#include "base58.h"
+#include <validation.h>
+#include <base58.h>
#include <array>
#include <vector>
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 7b307d6f42..1482452814 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -2,35 +2,31 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "perf.h"
+#include <bench/bench.h>
+#include <bench/perf.h>
#include <assert.h>
#include <iostream>
#include <iomanip>
-#include <sys/time.h>
benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
return benchmarks_map;
}
-static double gettimedouble(void) {
- struct timeval tv;
- gettimeofday(&tv, nullptr);
- return tv.tv_usec * 0.000001 + tv.tv_sec;
-}
-
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
{
benchmarks().insert(std::make_pair(name, func));
}
void
-benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
+benchmark::BenchRunner::RunAll(benchmark::duration elapsedTimeForOne)
{
perf_init();
- std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
+ if (std::ratio_less_equal<benchmark::clock::period, std::micro>::value) {
+ std::cerr << "WARNING: Clock precision is worse than microsecond - benchmarks may be less accurate!\n";
+ }
+ std::cout << "#Benchmark" << "," << "count" << "," << "min(ns)" << "," << "max(ns)" << "," << "average(ns)" << ","
<< "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
for (const auto &p: benchmarks()) {
@@ -46,16 +42,17 @@ bool benchmark::State::KeepRunning()
++count;
return true;
}
- double now;
+ time_point now;
+
uint64_t nowCycles;
if (count == 0) {
- lastTime = beginTime = now = gettimedouble();
+ lastTime = beginTime = now = clock::now();
lastCycles = beginCycles = nowCycles = perf_cpucycles();
}
else {
- now = gettimedouble();
- double elapsed = now - lastTime;
- double elapsedOne = elapsed / (countMask + 1);
+ now = clock::now();
+ auto elapsed = now - lastTime;
+ auto elapsedOne = elapsed / (countMask + 1);
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;
@@ -70,8 +67,8 @@ bool benchmark::State::KeepRunning()
// The restart avoids including the overhead of this code in the measurement.
countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
count = 0;
- minTime = std::numeric_limits<double>::max();
- maxTime = std::numeric_limits<double>::min();
+ minTime = duration::max();
+ maxTime = duration::zero();
minCycles = std::numeric_limits<uint64_t>::max();
maxCycles = std::numeric_limits<uint64_t>::min();
return true;
@@ -94,9 +91,13 @@ bool benchmark::State::KeepRunning()
assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
// Output results
- double average = (now-beginTime)/count;
+ // Duration casts are only necessary here because hardware with sub-nanosecond clocks
+ // will lose precision.
+ int64_t min_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(minTime).count();
+ int64_t max_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(maxTime).count();
+ int64_t avg_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>((now-beginTime)/count).count();
int64_t averageCycles = (nowCycles-beginCycles)/count;
- std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
+ std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << min_elapsed << "," << max_elapsed << "," << avg_elapsed << ","
<< minCycles << "," << maxCycles << "," << averageCycles << "\n";
std::cout.copyfmt(std::ios(nullptr));
diff --git a/src/bench/bench.h b/src/bench/bench.h
index 79109eaa56..071a5dc9c7 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -9,6 +9,7 @@
#include <limits>
#include <map>
#include <string>
+#include <chrono>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
@@ -36,12 +37,21 @@ BENCHMARK(CODE_TO_TIME);
*/
namespace benchmark {
+ // In case high_resolution_clock is steady, prefer that, otherwise use steady_clock.
+ struct best_clock {
+ using hi_res_clock = std::chrono::high_resolution_clock;
+ using steady_clock = std::chrono::steady_clock;
+ using type = std::conditional<hi_res_clock::is_steady, hi_res_clock, steady_clock>::type;
+ };
+ using clock = best_clock::type;
+ using time_point = clock::time_point;
+ using duration = clock::duration;
class State {
std::string name;
- double maxElapsed;
- double beginTime;
- double lastTime, minTime, maxTime;
+ duration maxElapsed;
+ time_point beginTime, lastTime;
+ duration minTime, maxTime;
uint64_t count;
uint64_t countMask;
uint64_t beginCycles;
@@ -49,12 +59,17 @@ namespace benchmark {
uint64_t minCycles;
uint64_t maxCycles;
public:
- State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
- minTime = std::numeric_limits<double>::max();
- maxTime = std::numeric_limits<double>::min();
- minCycles = std::numeric_limits<uint64_t>::max();
- maxCycles = std::numeric_limits<uint64_t>::min();
- countMask = 1;
+ State(std::string _name, duration _maxElapsed) :
+ name(_name),
+ maxElapsed(_maxElapsed),
+ minTime(duration::max()),
+ maxTime(duration::zero()),
+ count(0),
+ countMask(1),
+ beginCycles(0),
+ lastCycles(0),
+ minCycles(std::numeric_limits<uint64_t>::max()),
+ maxCycles(std::numeric_limits<uint64_t>::min()) {
}
bool KeepRunning();
};
@@ -69,7 +84,7 @@ namespace benchmark {
public:
BenchRunner(std::string name, BenchFunction func);
- static void RunAll(double elapsedTimeForOne=1.0);
+ static void RunAll(duration elapsedTimeForOne = std::chrono::seconds(1));
};
}
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 37fd772435..84e51d809a 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "crypto/sha256.h"
-#include "key.h"
-#include "validation.h"
-#include "util.h"
-#include "random.h"
+#include <crypto/sha256.h>
+#include <key.h>
+#include <validation.h>
+#include <util.h>
+#include <random.h>
int
main(int argc, char** argv)
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index 5aab3381fd..89ba3d3d21 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "coins.h"
-#include "policy/policy.h"
-#include "wallet/crypter.h"
+#include <bench/bench.h>
+#include <coins.h>
+#include <policy/policy.h>
+#include <wallet/crypter.h>
#include <vector>
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 7bb1b93668..9533b3c711 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -2,15 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "chainparams.h"
-#include "validation.h"
-#include "streams.h"
-#include "consensus/validation.h"
+#include <chainparams.h>
+#include <validation.h>
+#include <streams.h>
+#include <consensus/validation.h>
namespace block_bench {
-#include "bench/data/block413567.raw.h"
+#include <bench/data/block413567.raw.h>
} // namespace block_bench
// These are the two major time-sinks which happen after we have fully received
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index b7ae5c2d57..7e63e820db 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "util.h"
-#include "validation.h"
-#include "checkqueue.h"
-#include "prevector.h"
+#include <bench/bench.h>
+#include <util.h>
+#include <validation.h>
+#include <checkqueue.h>
+#include <prevector.h>
#include <vector>
#include <boost/thread/thread.hpp>
-#include "random.h"
+#include <random.h>
// This Benchmark tests the CheckQueue with the lightest
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index f8956508f6..ff57f88170 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "wallet/wallet.h"
+#include <bench/bench.h>
+#include <wallet/wallet.h>
#include <set>
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 410a08e512..b37b5cad62 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -4,16 +4,16 @@
#include <iostream>
-#include "bench.h"
-#include "bloom.h"
-#include "hash.h"
-#include "random.h"
-#include "uint256.h"
-#include "utiltime.h"
-#include "crypto/ripemd160.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/sha512.h"
+#include <bench/bench.h>
+#include <bloom.h>
+#include <hash.h>
+#include <random.h>
+#include <uint256.h>
+#include <utiltime.h>
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <crypto/sha512.h>
/* Number of bytes to hash per iteration */
static const uint64_t BUFFER_SIZE = 1000*1000;
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
index c6a05567be..b0bfa95144 100644
--- a/src/bench/lockedpool.cpp
+++ b/src/bench/lockedpool.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
+#include <bench/bench.h>
-#include "support/lockedpool.h"
+#include <support/lockedpool.h>
#include <iostream>
#include <vector>
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index 073bbde016..eda6edbb23 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "policy/policy.h"
-#include "txmempool.h"
+#include <bench/bench.h>
+#include <policy/policy.h>
+#include <txmempool.h>
#include <list>
#include <vector>
diff --git a/src/bench/perf.cpp b/src/bench/perf.cpp
index a549ec29ea..4045670a31 100644
--- a/src/bench/perf.cpp
+++ b/src/bench/perf.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "perf.h"
+#include <bench/perf.h>
#if defined(__i386__) || defined(__x86_64__)
diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp
index 55af3de4fe..de7ecab737 100644
--- a/src/bench/prevector_destructor.cpp
+++ b/src/bench/prevector_destructor.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "prevector.h"
+#include <bench/bench.h>
+#include <prevector.h>
static void PrevectorDestructor(benchmark::State& state)
{
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 73c02cf718..452099b800 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -4,9 +4,8 @@
#include <iostream>
-#include "bench.h"
-#include "bloom.h"
-#include "utiltime.h"
+#include <bench/bench.h>
+#include <bloom.h>
static void RollingBloom(benchmark::State& state)
{
@@ -23,10 +22,10 @@ static void RollingBloom(benchmark::State& state)
data[2] = count >> 16;
data[3] = count >> 24;
if (countnow == nEntriesPerGeneration) {
- int64_t b = GetTimeMicros();
+ auto b = benchmark::clock::now();
filter.insert(data);
- int64_t e = GetTimeMicros();
- std::cout << "RollingBloom-refresh,1," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "," << (e-b)*0.000001 << "\n";
+ auto total = std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark::clock::now() - b).count();
+ std::cout << "RollingBloom-refresh,1," << total << "," << total << "," << total << "\n";
countnow = 0;
} else {
filter.insert(data);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index ef7381c120..bfa5806c9d 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bench.h"
-#include "key.h"
+#include <bench/bench.h>
+#include <key.h>
#if defined(HAVE_CONSENSUS_LIB)
-#include "script/bitcoinconsensus.h"
+#include <script/bitcoinconsensus.h>
#endif
-#include "script/script.h"
-#include "script/sign.h"
-#include "streams.h"
+#include <script/script.h>
+#include <script/sign.h>
+#include <streams.h>
#include <array>
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index e21a269221..5e3b76a295 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -4,22 +4,22 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparamsbase.h"
-#include "clientversion.h"
-#include "fs.h"
-#include "rpc/client.h"
-#include "rpc/protocol.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <chainparamsbase.h>
+#include <clientversion.h>
+#include <fs.h>
+#include <rpc/client.h>
+#include <rpc/protocol.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <stdio.h>
#include <event2/buffer.h>
#include <event2/keyvalq_struct.h>
-#include "support/events.h"
+#include <support/events.h>
#include <univalue.h>
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index e4f44435ba..c9223dbf10 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -3,24 +3,24 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "base58.h"
-#include "clientversion.h"
-#include "coins.h"
-#include "consensus/consensus.h"
-#include "core_io.h"
-#include "keystore.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "script/sign.h"
+#include <base58.h>
+#include <clientversion.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <core_io.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <script/sign.h>
#include <univalue.h>
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
#include <stdio.h>
@@ -387,6 +387,10 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
+ if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ throw std::runtime_error(strprintf(
+ "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
+ }
// Get the ID for the script, and then construct a P2SH destination for it.
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
@@ -447,10 +451,19 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
bScriptHash = (flags.find("S") != std::string::npos);
}
+ if (scriptPubKey.size() > MAX_SCRIPT_SIZE) {
+ throw std::runtime_error(strprintf(
+ "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE));
+ }
+
if (bSegWit) {
scriptPubKey = GetScriptForWitness(scriptPubKey);
}
if (bScriptHash) {
+ if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ throw std::runtime_error(strprintf(
+ "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
+ }
scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
}
@@ -690,10 +703,10 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
else if (command == "outpubkey") {
- if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ ecc.reset(new Secp256k1Init());
MutateTxAddOutPubKey(tx, commandVal);
} else if (command == "outmultisig") {
- if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ ecc.reset(new Secp256k1Init());
MutateTxAddOutMultiSig(tx, commandVal);
} else if (command == "outscript")
MutateTxAddOutScript(tx, commandVal);
@@ -701,7 +714,7 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
MutateTxAddOutData(tx, commandVal);
else if (command == "sign") {
- if (!ecc) { ecc.reset(new Secp256k1Init()); }
+ ecc.reset(new Secp256k1Init());
MutateTxSign(tx, commandVal);
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 543eba0e69..bc23912d2b 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -4,21 +4,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparams.h"
-#include "clientversion.h"
-#include "compat.h"
-#include "fs.h"
-#include "rpc/server.h"
-#include "init.h"
-#include "noui.h"
-#include "scheduler.h"
-#include "util.h"
-#include "httpserver.h"
-#include "httprpc.h"
-#include "utilstrencodings.h"
+#include <chainparams.h>
+#include <clientversion.h>
+#include <compat.h>
+#include <fs.h>
+#include <rpc/server.h>
+#include <init.h>
+#include <noui.h>
+#include <scheduler.h>
+#include <util.h>
+#include <httpserver.h>
+#include <httprpc.h>
+#include <utilstrencodings.h>
#include <boost/thread.hpp>
@@ -120,7 +120,7 @@ bool AppInit(int argc, char* argv[])
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
- exit(EXIT_FAILURE);
+ return false;
}
}
@@ -132,17 +132,17 @@ bool AppInit(int argc, char* argv[])
if (!AppInitBasicSetup())
{
// InitError will have been called with detailed error, which ends up on console
- exit(EXIT_FAILURE);
+ return false;
}
if (!AppInitParameterInteraction())
{
// InitError will have been called with detailed error, which ends up on console
- exit(EXIT_FAILURE);
+ return false;
}
if (!AppInitSanityChecks())
{
// InitError will have been called with detailed error, which ends up on console
- exit(EXIT_FAILURE);
+ return false;
}
if (gArgs.GetBoolArg("-daemon", false))
{
@@ -163,7 +163,7 @@ bool AppInit(int argc, char* argv[])
if (!AppInitLockDataDirectory())
{
// If locking the data directory failed, exit immediately
- exit(EXIT_FAILURE);
+ return false;
}
fRet = AppInitMain(threadGroup, scheduler);
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 6f27b7b9dc..6ff4d97bf4 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -2,16 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "blockencodings.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "chainparams.h"
-#include "hash.h"
-#include "random.h"
-#include "streams.h"
-#include "txmempool.h"
-#include "validation.h"
-#include "util.h"
+#include <blockencodings.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <chainparams.h>
+#include <hash.h>
+#include <random.h>
+#include <streams.h>
+#include <txmempool.h>
+#include <validation.h>
+#include <util.h>
#include <unordered_map>
diff --git a/src/blockencodings.h b/src/blockencodings.h
index 50478f9f32..d034bb3080 100644
--- a/src/blockencodings.h
+++ b/src/blockencodings.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_BLOCK_ENCODINGS_H
#define BITCOIN_BLOCK_ENCODINGS_H
-#include "primitives/block.h"
+#include <primitives/block.h>
#include <memory>
diff --git a/src/bloom.cpp b/src/bloom.cpp
index fa884f0bf3..11ea099637 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bloom.h"
-
-#include "primitives/transaction.h"
-#include "hash.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "random.h"
-#include "streams.h"
+#include <bloom.h>
+
+#include <primitives/transaction.h>
+#include <hash.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <random.h>
+#include <streams.h>
#include <math.h>
#include <stdlib.h>
diff --git a/src/bloom.h b/src/bloom.h
index 7ca9682239..d29a8dcd6f 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_BLOOM_H
#define BITCOIN_BLOOM_H
-#include "serialize.h"
+#include <serialize.h>
#include <vector>
diff --git a/src/chain.cpp b/src/chain.cpp
index 5e3dd9b31b..9f40c41fde 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
+#include <chain.h>
/**
* CChain implementation
diff --git a/src/chain.h b/src/chain.h
index f1036e5d92..ca1900c22b 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_CHAIN_H
#define BITCOIN_CHAIN_H
-#include "arith_uint256.h"
-#include "primitives/block.h"
-#include "pow.h"
-#include "tinyformat.h"
-#include "uint256.h"
+#include <arith_uint256.h>
+#include <primitives/block.h>
+#include <pow.h>
+#include <tinyformat.h>
+#include <uint256.h>
#include <vector>
@@ -304,7 +304,7 @@ public:
return (int64_t)nTimeMax;
}
- enum { nMedianTimeSpan=11 };
+ static constexpr int nMedianTimeSpan = 11;
int64_t GetMedianTimePast() const
{
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 85c9cd6934..e753c5ccff 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparams.h"
-#include "consensus/merkle.h"
+#include <chainparams.h>
+#include <consensus/merkle.h>
-#include "tinyformat.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <tinyformat.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <assert.h>
-#include "chainparamsseeds.h"
+#include <chainparamsseeds.h>
static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
{
@@ -75,6 +75,7 @@ public:
CMainParams() {
strNetworkID = "main";
consensus.nSubsidyHalvingInterval = 210000;
+ consensus.BIP16Height = 173805; // 00000000000000ce80a7e057163a4db1d5ad7b20fb6f598c9597b9665c8fb0d4 - April 1, 2012
consensus.BIP34Height = 227931;
consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
@@ -181,6 +182,7 @@ public:
CTestNetParams() {
strNetworkID = "test";
consensus.nSubsidyHalvingInterval = 210000;
+ consensus.BIP16Height = 514; // 00000000040b4e986385315e14bee30ad876d8b47f748025b26683116d21aa65
consensus.BIP34Height = 21111;
consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
@@ -230,7 +232,6 @@ public:
vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch", true);
vSeeds.emplace_back("seed.tbtc.petertodd.org", true);
vSeeds.emplace_back("testnet-seed.bluematt.me", false);
- vSeeds.emplace_back("testnet-seed.bitcoin.schildbach.de", false);
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -271,6 +272,7 @@ public:
CRegTestParams() {
strNetworkID = "regtest";
consensus.nSubsidyHalvingInterval = 150;
+ consensus.BIP16Height = 0; // always enforce P2SH BIP16 on regtest
consensus.BIP34Height = 100000000; // BIP34 has not activated on regtest (far in the future so block v1 are not rejected in tests)
consensus.BIP34Hash = uint256();
consensus.BIP65Height = 1351; // BIP65 activated on regtest (Used in rpc activation tests)
@@ -284,13 +286,13 @@ public:
consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL;
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");
diff --git a/src/chainparams.h b/src/chainparams.h
index 3948c9163f..0d82a998b1 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_CHAINPARAMS_H
#define BITCOIN_CHAINPARAMS_H
-#include "chainparamsbase.h"
-#include "consensus/params.h"
-#include "primitives/block.h"
-#include "protocol.h"
+#include <chainparamsbase.h>
+#include <consensus/params.h>
+#include <primitives/block.h>
+#include <protocol.h>
#include <memory>
#include <vector>
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index c966683b72..a7e87faee3 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparamsbase.h"
+#include <chainparamsbase.h>
-#include "tinyformat.h"
-#include "util.h"
+#include <tinyformat.h>
+#include <util.h>
#include <assert.h>
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 5afe3e66b6..2ef4dd8330 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "checkpoints.h"
+#include <checkpoints.h>
-#include "chain.h"
-#include "chainparams.h"
-#include "reverse_iterator.h"
-#include "validation.h"
-#include "uint256.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <reverse_iterator.h>
+#include <validation.h>
+#include <uint256.h>
#include <stdint.h>
diff --git a/src/checkpoints.h b/src/checkpoints.h
index 7449d1063b..df97a674a8 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CHECKPOINTS_H
#define BITCOIN_CHECKPOINTS_H
-#include "uint256.h"
+#include <uint256.h>
#include <map>
diff --git a/src/checkqueue.h b/src/checkqueue.h
index 6377fbe942..08de336079 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CHECKQUEUE_H
#define BITCOIN_CHECKQUEUE_H
-#include "sync.h"
+#include <sync.h>
#include <algorithm>
#include <vector>
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index 8a4b408831..f7ded63e6a 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "clientversion.h"
+#include <clientversion.h>
-#include "tinyformat.h"
+#include <tinyformat.h>
#include <string>
@@ -39,7 +39,7 @@ const std::string CLIENT_NAME("Satoshi");
//! First, include build.h if requested
#ifdef HAVE_BUILD_INFO
-#include "build.h"
+#include <obj/build.h>
#endif
//! git will put "#define GIT_ARCHIVE 1" on the next line inside archives. $Format:%n#define GIT_ARCHIVE 1$
diff --git a/src/clientversion.h b/src/clientversion.h
index 3d5392619b..3a3d117d53 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -6,7 +6,7 @@
#define BITCOIN_CLIENTVERSION_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif //HAVE_CONFIG_H
// Check that required client information is defined
diff --git a/src/coins.cpp b/src/coins.cpp
index b45dfc3342..03138ef878 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coins.h"
+#include <coins.h>
-#include "consensus/consensus.h"
-#include "memusage.h"
-#include "random.h"
+#include <consensus/consensus.h>
+#include <memusage.h>
+#include <random.h>
#include <assert.h>
@@ -146,56 +146,58 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
}
bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
- for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
- if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
- CCoinsMap::iterator itUs = cacheCoins.find(it->first);
- if (itUs == cacheCoins.end()) {
- // The parent cache does not have an entry, while the child does
- // We can ignore it if it's both FRESH and pruned in the child
- if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
- // Otherwise we will need to create it in the parent
- // and move the data up and mark it as dirty
- CCoinsCacheEntry& entry = cacheCoins[it->first];
- entry.coin = std::move(it->second.coin);
- cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
- entry.flags = CCoinsCacheEntry::DIRTY;
- // We can mark it FRESH in the parent if it was FRESH in the child
- // Otherwise it might have just been flushed from the parent's cache
- // and already exist in the grandparent
- if (it->second.flags & CCoinsCacheEntry::FRESH)
- entry.flags |= CCoinsCacheEntry::FRESH;
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
+ // Ignore non-dirty entries (optimization).
+ if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
+ continue;
+ }
+ CCoinsMap::iterator itUs = cacheCoins.find(it->first);
+ if (itUs == cacheCoins.end()) {
+ // The parent cache does not have an entry, while the child does
+ // We can ignore it if it's both FRESH and pruned in the child
+ if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
+ // Otherwise we will need to create it in the parent
+ // and move the data up and mark it as dirty
+ CCoinsCacheEntry& entry = cacheCoins[it->first];
+ entry.coin = std::move(it->second.coin);
+ cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
+ entry.flags = CCoinsCacheEntry::DIRTY;
+ // We can mark it FRESH in the parent if it was FRESH in the child
+ // Otherwise it might have just been flushed from the parent's cache
+ // and already exist in the grandparent
+ if (it->second.flags & CCoinsCacheEntry::FRESH) {
+ entry.flags |= CCoinsCacheEntry::FRESH;
}
- } else {
- // Assert that the child cache entry was not marked FRESH if the
- // parent cache entry has unspent outputs. If this ever happens,
- // it means the FRESH flag was misapplied and there is a logic
- // error in the calling code.
- if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
- throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
+ }
+ } else {
+ // Assert that the child cache entry was not marked FRESH if the
+ // parent cache entry has unspent outputs. If this ever happens,
+ // it means the FRESH flag was misapplied and there is a logic
+ // error in the calling code.
+ if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
+ throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");
+ }
- // Found the entry in the parent cache
- if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
- // The grandparent does not have an entry, and the child is
- // modified and being pruned. This means we can just delete
- // it from the parent.
- cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
- cacheCoins.erase(itUs);
- } else {
- // A normal modification.
- cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
- itUs->second.coin = std::move(it->second.coin);
- cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
- itUs->second.flags |= CCoinsCacheEntry::DIRTY;
- // NOTE: It is possible the child has a FRESH flag here in
- // the event the entry we found in the parent is pruned. But
- // we must not copy that FRESH flag to the parent as that
- // pruned state likely still needs to be communicated to the
- // grandparent.
- }
+ // Found the entry in the parent cache
+ if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
+ // The grandparent does not have an entry, and the child is
+ // modified and being pruned. This means we can just delete
+ // it from the parent.
+ cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
+ cacheCoins.erase(itUs);
+ } else {
+ // A normal modification.
+ cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
+ itUs->second.coin = std::move(it->second.coin);
+ cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
+ itUs->second.flags |= CCoinsCacheEntry::DIRTY;
+ // NOTE: It is possible the child has a FRESH flag here in
+ // the event the entry we found in the parent is pruned. But
+ // we must not copy that FRESH flag to the parent as that
+ // pruned state likely still needs to be communicated to the
+ // grandparent.
}
}
- CCoinsMap::iterator itOld = it++;
- mapCoins.erase(itOld);
}
hashBlock = hashBlockIn;
return true;
diff --git a/src/coins.h b/src/coins.h
index 181b2fd4b9..0280abb56c 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -6,13 +6,13 @@
#ifndef BITCOIN_COINS_H
#define BITCOIN_COINS_H
-#include "primitives/transaction.h"
-#include "compressor.h"
-#include "core_memusage.h"
-#include "hash.h"
-#include "memusage.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <primitives/transaction.h>
+#include <compressor.h>
+#include <core_memusage.h>
+#include <hash.h>
+#include <memusage.h>
+#include <serialize.h>
+#include <uint256.h>
#include <assert.h>
#include <stdint.h>
diff --git a/src/compat.h b/src/compat.h
index e022659c01..2d699159b7 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -7,7 +7,7 @@
#define BITCOIN_COMPAT_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#ifdef WIN32
@@ -49,7 +49,7 @@
#ifndef WIN32
typedef unsigned int SOCKET;
-#include "errno.h"
+#include <errno.h>
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
#define WSAEALREADY EALREADY
diff --git a/src/compat/byteswap.h b/src/compat/byteswap.h
index d93ff7413a..8930534721 100644
--- a/src/compat/byteswap.h
+++ b/src/compat/byteswap.h
@@ -6,7 +6,7 @@
#define BITCOIN_COMPAT_BYTESWAP_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <stdint.h>
diff --git a/src/compat/endian.h b/src/compat/endian.h
index dbf178f53c..9fabbd0bfb 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -6,10 +6,10 @@
#define BITCOIN_COMPAT_ENDIAN_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat/byteswap.h"
+#include <compat/byteswap.h>
#include <stdint.h>
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index 3b9c70df7f..6633658c16 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <cstddef>
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
index b4d1c90992..20d2ad3cb6 100644
--- a/src/compat/glibc_sanity.cpp
+++ b/src/compat/glibc_sanity.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <cstddef>
diff --git a/src/compat/strnlen.cpp b/src/compat/strnlen.cpp
index 1ac266c2d1..313435a222 100644
--- a/src/compat/strnlen.cpp
+++ b/src/compat/strnlen.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <cstring>
diff --git a/src/compressor.cpp b/src/compressor.cpp
index f4c12f38d2..a729e28f07 100644
--- a/src/compressor.cpp
+++ b/src/compressor.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compressor.h"
+#include <compressor.h>
-#include "hash.h"
-#include "pubkey.h"
-#include "script/standard.h"
+#include <hash.h>
+#include <pubkey.h>
+#include <script/standard.h>
bool CScriptCompressor::IsToKeyID(CKeyID &hash) const
{
diff --git a/src/compressor.h b/src/compressor.h
index 094c1bcfe1..8731eef9f7 100644
--- a/src/compressor.h
+++ b/src/compressor.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_COMPRESSOR_H
#define BITCOIN_COMPRESSOR_H
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "serialize.h"
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <serialize.h>
class CKeyID;
class CPubKey;
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index ddd4ee9fab..6e3bac2d0e 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -24,12 +24,9 @@ static const size_t MIN_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 60; // 60 is
static const size_t MIN_SERIALIZABLE_TRANSACTION_WEIGHT = WITNESS_SCALE_FACTOR * 10; // 10 is the lower bound for the size of a serialized CTransaction
/** Flags for nSequence and nLockTime locks */
-enum {
- /* Interpret sequence numbers as relative lock-time constraints. */
- LOCKTIME_VERIFY_SEQUENCE = (1 << 0),
-
- /* Use GetMedianTimePast() instead of nTime for end point timestamp. */
- LOCKTIME_MEDIAN_TIME_PAST = (1 << 1),
-};
+/** Interpret sequence numbers as relative lock-time constraints. */
+static constexpr unsigned int LOCKTIME_VERIFY_SEQUENCE = (1 << 0);
+/** Use GetMedianTimePast() instead of nTime for end point timestamp. */
+static constexpr unsigned int LOCKTIME_MEDIAN_TIME_PAST = (1 << 1);
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index 798ce4b5fd..fef4a5d560 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "merkle.h"
-#include "hash.h"
-#include "utilstrencodings.h"
+#include <consensus/merkle.h>
+#include <hash.h>
+#include <utilstrencodings.h>
/* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind
diff --git a/src/consensus/merkle.h b/src/consensus/merkle.h
index 33764c7460..c1573cc214 100644
--- a/src/consensus/merkle.h
+++ b/src/consensus/merkle.h
@@ -8,9 +8,9 @@
#include <stdint.h>
#include <vector>
-#include "primitives/transaction.h"
-#include "primitives/block.h"
-#include "uint256.h"
+#include <primitives/transaction.h>
+#include <primitives/block.h>
+#include <uint256.h>
uint256 ComputeMerkleRoot(const std::vector<uint256>& leaves, bool* mutated = nullptr);
std::vector<uint256> ComputeMerkleBranch(const std::vector<uint256>& leaves, uint32_t position);
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 6240e82857..c9fbba12a2 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -6,7 +6,8 @@
#ifndef BITCOIN_CONSENSUS_PARAMS_H
#define BITCOIN_CONSENSUS_PARAMS_H
-#include "uint256.h"
+#include <uint256.h>
+#include <limits>
#include <map>
#include <string>
@@ -31,6 +32,15 @@ struct BIP9Deployment {
int64_t nStartTime;
/** Timeout/expiry MedianTime for the deployment attempt. */
int64_t nTimeout;
+
+ /** Constant for nTimeout very far in the future. */
+ static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max();
+
+ /** Special value for nStartTime indicating that the deployment is always active.
+ * This is useful for testing, as it means tests don't need to deal with the activation
+ * process (which takes at least 3 BIP9 intervals). Only tests that specifically test the
+ * behaviour during activation cannot use this. */
+ static constexpr int64_t ALWAYS_ACTIVE = -1;
};
/**
@@ -39,6 +49,8 @@ struct BIP9Deployment {
struct Params {
uint256 hashGenesisBlock;
int nSubsidyHalvingInterval;
+ /** Block height at which BIP16 becomes active */
+ int BIP16Height;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 70aa9d7006..be73d0a2f9 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "tx_verify.h"
+#include <consensus/tx_verify.h>
-#include "consensus.h"
-#include "primitives/transaction.h"
-#include "script/interpreter.h"
-#include "validation.h"
+#include <consensus/consensus.h>
+#include <primitives/transaction.h>
+#include <script/interpreter.h>
+#include <consensus/validation.h>
// TODO remove the following dependencies
-#include "chain.h"
-#include "coins.h"
-#include "utilmoneystr.h"
+#include <chain.h>
+#include <coins.h>
+#include <utilmoneystr.h>
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 288892462d..a4836ceda4 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CONSENSUS_TX_VERIFY_H
#define BITCOIN_CONSENSUS_TX_VERIFY_H
-#include "amount.h"
+#include <amount.h>
#include <stdint.h>
#include <vector>
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index b6740c9d9f..55f6c363fc 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -7,10 +7,10 @@
#define BITCOIN_CONSENSUS_VALIDATION_H
#include <string>
-#include "version.h"
-#include "consensus/consensus.h"
-#include "primitives/transaction.h"
-#include "primitives/block.h"
+#include <version.h>
+#include <consensus/consensus.h>
+#include <primitives/transaction.h>
+#include <primitives/block.h>
/** "reject" message codes */
static const unsigned char REJECT_MALFORMED = 0x01;
diff --git a/src/core_io.h b/src/core_io.h
index ccc72ebb32..7ed84d6665 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CORE_IO_H
#define BITCOIN_CORE_IO_H
-#include "amount.h"
+#include <amount.h>
#include <string>
#include <vector>
diff --git a/src/core_memusage.h b/src/core_memusage.h
index f038e7b154..d234f0a9d0 100644
--- a/src/core_memusage.h
+++ b/src/core_memusage.h
@@ -5,9 +5,9 @@
#ifndef BITCOIN_CORE_MEMUSAGE_H
#define BITCOIN_CORE_MEMUSAGE_H
-#include "primitives/transaction.h"
-#include "primitives/block.h"
-#include "memusage.h"
+#include <primitives/transaction.h>
+#include <primitives/block.h>
+#include <memusage.h>
static inline size_t RecursiveDynamicUsage(const CScript& script) {
return memusage::DynamicUsage(script);
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 7018131a13..2f5b67b5c7 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core_io.h"
+#include <core_io.h>
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "streams.h"
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <serialize.h>
+#include <streams.h>
#include <univalue.h>
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
diff --git a/src/core_write.cpp b/src/core_write.cpp
index e16db13650..e97876bef3 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -2,19 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "core_io.h"
-
-#include "base58.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "serialize.h"
-#include "streams.h"
+#include <core_io.h>
+
+#include <base58.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <serialize.h>
+#include <streams.h>
#include <univalue.h>
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
UniValue ValueFromAmount(const CAmount& amount)
{
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
index 5e70d25eee..baba8bcad0 100644
--- a/src/crypto/aes.cpp
+++ b/src/crypto/aes.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "aes.h"
-#include "crypto/common.h"
+#include <crypto/aes.h>
+#include <crypto/common.h>
#include <assert.h>
#include <string.h>
extern "C" {
-#include "crypto/ctaes/ctaes.c"
+#include <crypto/ctaes/ctaes.c>
}
AES128Encrypt::AES128Encrypt(const unsigned char key[16])
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index a7b63b19df..7dda94d291 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -8,7 +8,7 @@
#define BITCOIN_CRYPTO_AES_H
extern "C" {
-#include "crypto/ctaes/ctaes.h"
+#include <crypto/ctaes/ctaes.h>
}
static const int AES_BLOCKSIZE = 16;
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
index 4038ae9f86..ac4470f04f 100644
--- a/src/crypto/chacha20.cpp
+++ b/src/crypto/chacha20.cpp
@@ -5,8 +5,8 @@
// Based on the public domain implementation 'merged' by D. J. Bernstein
// See https://cr.yp.to/chacha.html.
-#include "crypto/common.h"
-#include "crypto/chacha20.h"
+#include <crypto/common.h>
+#include <crypto/chacha20.h>
#include <string.h>
diff --git a/src/crypto/common.h b/src/crypto/common.h
index bd9bc9420b..5a193a4e64 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -6,13 +6,13 @@
#define BITCOIN_CRYPTO_COMMON_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <stdint.h>
#include <string.h>
-#include "compat/endian.h"
+#include <compat/endian.h>
uint16_t static inline ReadLE16(const unsigned char* ptr)
{
diff --git a/src/crypto/hmac_sha256.cpp b/src/crypto/hmac_sha256.cpp
index 3c791625d0..9366e216c2 100644
--- a/src/crypto/hmac_sha256.cpp
+++ b/src/crypto/hmac_sha256.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/hmac_sha256.h"
+#include <crypto/hmac_sha256.h>
#include <string.h>
diff --git a/src/crypto/hmac_sha256.h b/src/crypto/hmac_sha256.h
index 8c42fcfe14..40d40f9fb2 100644
--- a/src/crypto/hmac_sha256.h
+++ b/src/crypto/hmac_sha256.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CRYPTO_HMAC_SHA256_H
#define BITCOIN_CRYPTO_HMAC_SHA256_H
-#include "crypto/sha256.h"
+#include <crypto/sha256.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/src/crypto/hmac_sha512.cpp b/src/crypto/hmac_sha512.cpp
index 5939c6ec47..f984201f6a 100644
--- a/src/crypto/hmac_sha512.cpp
+++ b/src/crypto/hmac_sha512.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/hmac_sha512.h"
+#include <crypto/hmac_sha512.h>
#include <string.h>
diff --git a/src/crypto/hmac_sha512.h b/src/crypto/hmac_sha512.h
index 17dee61ea8..6d3fd59f27 100644
--- a/src/crypto/hmac_sha512.h
+++ b/src/crypto/hmac_sha512.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CRYPTO_HMAC_SHA512_H
#define BITCOIN_CRYPTO_HMAC_SHA512_H
-#include "crypto/sha512.h"
+#include <crypto/sha512.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp
index 77c9acfc26..4afa9abd1e 100644
--- a/src/crypto/ripemd160.cpp
+++ b/src/crypto/ripemd160.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/ripemd160.h"
+#include <crypto/ripemd160.h>
-#include "crypto/common.h"
+#include <crypto/common.h>
#include <string.h>
diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp
index 0b895b33a2..8ccc5e112a 100644
--- a/src/crypto/sha1.cpp
+++ b/src/crypto/sha1.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/sha1.h"
+#include <crypto/sha1.h>
-#include "crypto/common.h"
+#include <crypto/common.h>
#include <string.h>
diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp
index 29afe86ec7..9a21aec20e 100644
--- a/src/crypto/sha256.cpp
+++ b/src/crypto/sha256.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/sha256.h"
-#include "crypto/common.h"
+#include <crypto/sha256.h>
+#include <crypto/common.h>
#include <assert.h>
#include <string.h>
diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp
index 564127cc31..aa46e7ba86 100644
--- a/src/crypto/sha512.cpp
+++ b/src/crypto/sha512.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/sha512.h"
+#include <crypto/sha512.h>
-#include "crypto/common.h"
+#include <crypto/common.h>
#include <string.h>
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index dfc90f3ab9..92c4fe363c 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "dbwrapper.h"
+#include <dbwrapper.h>
-#include "fs.h"
-#include "util.h"
-#include "random.h"
+#include <fs.h>
+#include <util.h>
+#include <random.h>
#include <leveldb/cache.h>
#include <leveldb/env.h>
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index e19fde51c1..9f4d4814eb 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -5,13 +5,13 @@
#ifndef BITCOIN_DBWRAPPER_H
#define BITCOIN_DBWRAPPER_H
-#include "clientversion.h"
-#include "fs.h"
-#include "serialize.h"
-#include "streams.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <clientversion.h>
+#include <fs.h>
+#include <serialize.h>
+#include <streams.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <leveldb/db.h>
#include <leveldb/write_batch.h>
diff --git a/src/fs.cpp b/src/fs.cpp
index a5e12f1cfc..570ed3e2ee 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -1,4 +1,4 @@
-#include "fs.h"
+#include <fs.h>
namespace fsbridge {
diff --git a/src/hash.cpp b/src/hash.cpp
index 5a15600be5..1363d32cf4 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "hash.h"
-#include "crypto/common.h"
-#include "crypto/hmac_sha512.h"
-#include "pubkey.h"
+#include <hash.h>
+#include <crypto/common.h>
+#include <crypto/hmac_sha512.h>
+#include <pubkey.h>
inline uint32_t ROTL32(uint32_t x, int8_t r)
diff --git a/src/hash.h b/src/hash.h
index 474b13d65b..55724fb636 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_HASH_H
#define BITCOIN_HASH_H
-#include "crypto/ripemd160.h"
-#include "crypto/sha256.h"
-#include "prevector.h"
-#include "serialize.h"
-#include "uint256.h"
-#include "version.h"
+#include <crypto/ripemd160.h>
+#include <crypto/sha256.h>
+#include <prevector.h>
+#include <serialize.h>
+#include <uint256.h>
+#include <version.h>
#include <vector>
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 93f0a18668..6b6849e59b 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -2,19 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "httprpc.h"
-
-#include "base58.h"
-#include "chainparams.h"
-#include "httpserver.h"
-#include "rpc/protocol.h"
-#include "rpc/server.h"
-#include "random.h"
-#include "sync.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "ui_interface.h"
-#include "crypto/hmac_sha256.h"
+#include <httprpc.h>
+
+#include <base58.h>
+#include <chainparams.h>
+#include <httpserver.h>
+#include <rpc/protocol.h>
+#include <rpc/server.h>
+#include <random.h>
+#include <sync.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <ui_interface.h>
+#include <crypto/hmac_sha256.h>
#include <stdio.h>
#include <boost/algorithm/string.hpp> // boost::trim
@@ -62,7 +62,7 @@ private:
/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
-static HTTPRPCTimerInterface* httpRPCTimerInterface = nullptr;
+static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
@@ -238,8 +238,8 @@ bool StartHTTPRPC()
RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
#endif
assert(EventBase());
- httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
- RPCSetTimerInterface(httpRPCTimerInterface);
+ httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(EventBase());
+ RPCSetTimerInterface(httpRPCTimerInterface.get());
return true;
}
@@ -253,8 +253,7 @@ void StopHTTPRPC()
LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
- RPCUnsetTimerInterface(httpRPCTimerInterface);
- delete httpRPCTimerInterface;
- httpRPCTimerInterface = nullptr;
+ RPCUnsetTimerInterface(httpRPCTimerInterface.get());
+ httpRPCTimerInterface.reset();
}
}
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index 5923871691..7d590f8e1f 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -2,16 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "httpserver.h"
+#include <httpserver.h>
-#include "chainparamsbase.h"
-#include "compat.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "netbase.h"
-#include "rpc/protocol.h" // For HTTP status codes
-#include "sync.h"
-#include "ui_interface.h"
+#include <chainparamsbase.h>
+#include <compat.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <netbase.h>
+#include <rpc/protocol.h> // For HTTP status codes
+#include <sync.h>
+#include <ui_interface.h>
#include <stdio.h>
#include <stdlib.h>
@@ -24,10 +24,11 @@
#include <event2/thread.h>
#include <event2/buffer.h>
+#include <event2/bufferevent.h>
#include <event2/util.h>
#include <event2/keyvalq_struct.h>
-#include "support/events.h"
+#include <support/events.h>
#ifdef EVENT__HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -239,6 +240,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m)
/** HTTP request callback */
static void http_request_cb(struct evhttp_request* req, void* arg)
{
+ // Disable reading to work around a libevent bug, fixed in 2.2.0.
+ if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
+ evhttp_connection* conn = evhttp_request_get_connection(req);
+ if (conn) {
+ bufferevent* bev = evhttp_connection_get_bufferevent(conn);
+ if (bev) {
+ bufferevent_disable(bev, EV_READ);
+ }
+ }
+ }
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
@@ -481,6 +492,8 @@ void StopHTTPServer()
}
if (eventBase) {
LogPrint(BCLog::HTTP, "Waiting for HTTP event thread to exit\n");
+ // Exit the event loop as soon as there are no active events.
+ event_base_loopexit(eventBase, nullptr);
// Give event loop a few seconds to exit (to send back last RPC responses), then break it
// Before this was solved with event_base_loopexit, but that didn't work as expected in
// at least libevent 2.0.21 and always introduced a delay. In libevent
@@ -599,8 +612,21 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
struct evbuffer* evb = evhttp_request_get_output_buffer(req);
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
- HTTPEvent* ev = new HTTPEvent(eventBase, true,
- std::bind(evhttp_send_reply, req, nStatus, (const char*)nullptr, (struct evbuffer *)nullptr));
+ auto req_copy = req;
+ HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
+ evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
+ // Re-enable reading from the socket. This is the second part of the libevent
+ // workaround above.
+ if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
+ evhttp_connection* conn = evhttp_request_get_connection(req_copy);
+ if (conn) {
+ bufferevent* bev = evhttp_connection_get_bufferevent(conn);
+ if (bev) {
+ bufferevent_enable(bev, EV_READ | EV_WRITE);
+ }
+ }
+ }
+ });
ev->trigger(nullptr);
replySent = true;
req = nullptr; // transferred back to main thread
diff --git a/src/init.cpp b/src/init.cpp
index 539adc23d5..439eaacfcc 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -4,49 +4,49 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "init.h"
-
-#include "addrman.h"
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "compat/sanity.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "httpserver.h"
-#include "httprpc.h"
-#include "key.h"
-#include "validation.h"
-#include "miner.h"
-#include "netbase.h"
-#include "net.h"
-#include "net_processing.h"
-#include "policy/feerate.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "rpc/server.h"
-#include "rpc/register.h"
-#include "rpc/safemode.h"
-#include "rpc/blockchain.h"
-#include "script/standard.h"
-#include "script/sigcache.h"
-#include "scheduler.h"
-#include "timedata.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "torcontrol.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "validationinterface.h"
+#include <init.h>
+
+#include <addrman.h>
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <compat/sanity.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <httpserver.h>
+#include <httprpc.h>
+#include <key.h>
+#include <validation.h>
+#include <miner.h>
+#include <netbase.h>
+#include <net.h>
+#include <net_processing.h>
+#include <policy/feerate.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <rpc/server.h>
+#include <rpc/register.h>
+#include <rpc/safemode.h>
+#include <rpc/blockchain.h>
+#include <script/standard.h>
+#include <script/sigcache.h>
+#include <scheduler.h>
+#include <timedata.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <torcontrol.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <validationinterface.h>
#ifdef ENABLE_WALLET
-#include "wallet/init.h"
+#include <wallet/init.h>
#endif
-#include "warnings.h"
+#include <warnings.h>
#include <stdint.h>
#include <stdio.h>
#include <memory>
@@ -64,7 +64,7 @@
#include <openssl/crypto.h>
#if ENABLE_ZMQ
-#include "zmq/zmqnotificationinterface.h"
+#include <zmq/zmqnotificationinterface.h>
#endif
bool fFeeEstimatesInitialized = false;
@@ -152,7 +152,7 @@ public:
// Writes do not need similar protection, as failure to write is handled by the caller.
};
-static CCoinsViewErrorCatcher *pcoinscatcher = nullptr;
+static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
void Interrupt(boost::thread_group& threadGroup)
@@ -235,14 +235,10 @@ void Shutdown()
if (pcoinsTip != nullptr) {
FlushStateToDisk();
}
- delete pcoinsTip;
- pcoinsTip = nullptr;
- delete pcoinscatcher;
- pcoinscatcher = nullptr;
- delete pcoinsdbview;
- pcoinsdbview = nullptr;
- delete pblocktree;
- pblocktree = nullptr;
+ pcoinsTip.reset();
+ pcoinscatcher.reset();
+ pcoinsdbview.reset();
+ pblocktree.reset();
}
#ifdef ENABLE_WALLET
StopWallets();
@@ -265,6 +261,7 @@ void Shutdown()
#endif
UnregisterAllValidationInterfaces();
GetMainSignals().UnregisterBackgroundSignalScheduler();
+ GetMainSignals().UnregisterWithMempoolSignals(mempool);
#ifdef ENABLE_WALLET
CloseWallets();
#endif
@@ -369,11 +366,11 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-txindex", strprintf(_("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)"), DEFAULT_TXINDEX));
strUsage += HelpMessageGroup(_("Connection options:"));
- strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open"));
+ strUsage += HelpMessageOpt("-addnode=<ip>", _("Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info)"));
strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD));
strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME));
strUsage += HelpMessageOpt("-bind=<addr>", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6"));
- strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections"));
+ strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections (the rules for this peer are the same as for -addnode)"));
strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)"));
strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP));
strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)"));
@@ -544,14 +541,14 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex
}
static bool fHaveGenesis = false;
-static boost::mutex cs_GenesisWait;
+static CWaitableCriticalSection cs_GenesisWait;
static CConditionVariable condvar_GenesisWait;
static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
{
if (pBlockIndex != nullptr) {
{
- boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait);
+ WaitableLock lock_GenesisWait(cs_GenesisWait);
fHaveGenesis = true;
}
condvar_GenesisWait.notify_all();
@@ -588,7 +585,7 @@ void CleanupBlockRevFiles()
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
fs::path blocksdir = GetDataDir() / "blocks";
for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
- if (is_regular_file(*it) &&
+ if (fs::is_regular_file(*it) &&
it->path().filename().string().length() == 12 &&
it->path().filename().string().substr(8,4) == ".dat")
{
@@ -815,7 +812,6 @@ void InitLogging()
namespace { // Variables internal to initialization process only
-ServiceFlags nRelevantServices = NODE_NETWORK;
int nMaxConnections;
int nUserMaxConnections;
int nFD;
@@ -1241,6 +1237,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+ GetMainSignals().RegisterWithMempoolSignals(mempool);
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
@@ -1271,7 +1268,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
CConnman& connman = *g_connman;
- peerLogic.reset(new PeerLogicValidation(&connman));
+ peerLogic.reset(new PeerLogicValidation(&connman, scheduler));
RegisterValidationInterface(peerLogic.get());
// sanitize comments per BIP-0014, format user agent and check total size
@@ -1407,12 +1404,10 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
do {
try {
UnloadBlockIndex();
- delete pcoinsTip;
- delete pcoinsdbview;
- delete pcoinscatcher;
- delete pblocktree;
-
- pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReset);
+ pcoinsTip.reset();
+ pcoinsdbview.reset();
+ pcoinscatcher.reset();
+ pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, false, fReset));
if (fReset) {
pblocktree->WriteReindexing(true);
@@ -1463,8 +1458,8 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// At this point we're either in reindex or we've loaded a useful
// block tree into mapBlockIndex!
- pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState);
- pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview);
+ pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
+ pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
@@ -1474,13 +1469,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!ReplayBlocks(chainparams, pcoinsdbview)) {
+ if (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
break;
}
// The on-disk coinsdb is now in a good state, create the cache
- pcoinsTip = new CCoinsViewCache(pcoinscatcher);
+ pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
if (!is_coinsview_empty) {
@@ -1522,7 +1517,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected");
break;
@@ -1604,9 +1599,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Note that setting NODE_WITNESS is never required: the only downside from not
// doing so is that after activation, no upgraded nodes will fetch from you.
nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
- // Only care about others providing witness capabilities if there is a softfork
- // defined.
- nRelevantServices = ServiceFlags(nRelevantServices | NODE_WITNESS);
}
// ********************************************************* Step 10: import blocks
@@ -1634,7 +1626,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
// Wait for genesis block to be processed
{
- boost::unique_lock<boost::mutex> lock(cs_GenesisWait);
+ WaitableLock lock(cs_GenesisWait);
while (!fHaveGenesis) {
condvar_GenesisWait.wait(lock);
}
@@ -1663,7 +1655,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
- connOptions.nRelevantServices = nRelevantServices;
connOptions.nMaxConnections = nMaxConnections;
connOptions.nMaxOutbound = std::min(MAX_OUTBOUND_CONNECTIONS, connOptions.nMaxConnections);
connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
diff --git a/src/key.cpp b/src/key.cpp
index 315a3978c8..73983caf41 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
+#include <key.h>
-#include "arith_uint256.h"
-#include "crypto/common.h"
-#include "crypto/hmac_sha512.h"
-#include "pubkey.h"
-#include "random.h"
+#include <arith_uint256.h>
+#include <crypto/common.h>
+#include <crypto/hmac_sha512.h>
+#include <pubkey.h>
+#include <random.h>
#include <secp256k1.h>
#include <secp256k1_recovery.h>
diff --git a/src/key.h b/src/key.h
index 54b5be2270..c610e5e6cd 100644
--- a/src/key.h
+++ b/src/key.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_KEY_H
#define BITCOIN_KEY_H
-#include "pubkey.h"
-#include "serialize.h"
-#include "support/allocators/secure.h"
-#include "uint256.h"
+#include <pubkey.h>
+#include <serialize.h>
+#include <support/allocators/secure.h>
+#include <uint256.h>
#include <stdexcept>
#include <vector>
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 8454175ca8..5718a14ca2 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "keystore.h"
+#include <keystore.h>
-#include "key.h"
-#include "pubkey.h"
-#include "util.h"
+#include <key.h>
+#include <pubkey.h>
+#include <util.h>
bool CKeyStore::AddKey(const CKey &key) {
return AddKeyPubKey(key, key.GetPubKey());
@@ -36,6 +36,33 @@ bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
return true;
}
+bool CBasicKeyStore::HaveKey(const CKeyID &address) const
+{
+ LOCK(cs_KeyStore);
+ return mapKeys.count(address) > 0;
+}
+
+std::set<CKeyID> CBasicKeyStore::GetKeys() const
+{
+ LOCK(cs_KeyStore);
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapKeys) {
+ set_address.insert(mi.first);
+ }
+ return set_address;
+}
+
+bool CBasicKeyStore::GetKey(const CKeyID &address, CKey &keyOut) const
+{
+ LOCK(cs_KeyStore);
+ KeyMap::const_iterator mi = mapKeys.find(address);
+ if (mi != mapKeys.end()) {
+ keyOut = mi->second;
+ return true;
+ }
+ return false;
+}
+
bool CBasicKeyStore::AddCScript(const CScript& redeemScript)
{
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
diff --git a/src/keystore.h b/src/keystore.h
index 9b85ddb0ec..4e6d8e8a27 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -6,11 +6,11 @@
#ifndef BITCOIN_KEYSTORE_H
#define BITCOIN_KEYSTORE_H
-#include "key.h"
-#include "pubkey.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "sync.h"
+#include <key.h>
+#include <pubkey.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <sync.h>
#include <boost/signals2/signal.hpp>
@@ -62,37 +62,9 @@ protected:
public:
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
- bool HaveKey(const CKeyID &address) const override
- {
- bool result;
- {
- LOCK(cs_KeyStore);
- result = (mapKeys.count(address) > 0);
- }
- return result;
- }
- std::set<CKeyID> GetKeys() const override
- {
- LOCK(cs_KeyStore);
- std::set<CKeyID> set_address;
- for (const auto& mi : mapKeys) {
- set_address.insert(mi.first);
- }
- return set_address;
- }
- bool GetKey(const CKeyID &address, CKey &keyOut) const override
- {
- {
- LOCK(cs_KeyStore);
- KeyMap::const_iterator mi = mapKeys.find(address);
- if (mi != mapKeys.end())
- {
- keyOut = mi->second;
- return true;
- }
- }
- return false;
- }
+ bool HaveKey(const CKeyID &address) const override;
+ std::set<CKeyID> GetKeys() const override;
+ bool GetKey(const CKeyID &address, CKey &keyOut) const override;
bool AddCScript(const CScript& redeemScript) override;
bool HaveCScript(const CScriptID &hash) const override;
bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override;
diff --git a/src/memusage.h b/src/memusage.h
index 93fd6a0eb5..d931171d35 100644
--- a/src/memusage.h
+++ b/src/memusage.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_MEMUSAGE_H
#define BITCOIN_MEMUSAGE_H
-#include "indirectmap.h"
+#include <indirectmap.h>
#include <stdlib.h>
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 3f07b4dac4..f4db9dd57e 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "merkleblock.h"
+#include <merkleblock.h>
-#include "hash.h"
-#include "consensus/consensus.h"
-#include "utilstrencodings.h"
+#include <hash.h>
+#include <consensus/consensus.h>
+#include <utilstrencodings.h>
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids)
diff --git a/src/merkleblock.h b/src/merkleblock.h
index 6c05f2c1f8..b64c34370e 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_MERKLEBLOCK_H
#define BITCOIN_MERKLEBLOCK_H
-#include "serialize.h"
-#include "uint256.h"
-#include "primitives/block.h"
-#include "bloom.h"
+#include <serialize.h>
+#include <uint256.h>
+#include <primitives/block.h>
+#include <bloom.h>
#include <vector>
diff --git a/src/miner.cpp b/src/miner.cpp
index a9989f4b17..397d99fc9a 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -3,29 +3,29 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "miner.h"
-
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "coins.h"
-#include "consensus/consensus.h"
-#include "consensus/tx_verify.h"
-#include "consensus/merkle.h"
-#include "consensus/validation.h"
-#include "hash.h"
-#include "validation.h"
-#include "net.h"
-#include "policy/feerate.h"
-#include "policy/policy.h"
-#include "pow.h"
-#include "primitives/transaction.h"
-#include "script/standard.h"
-#include "timedata.h"
-#include "txmempool.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "validationinterface.h"
+#include <miner.h>
+
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <consensus/tx_verify.h>
+#include <consensus/merkle.h>
+#include <consensus/validation.h>
+#include <hash.h>
+#include <validation.h>
+#include <net.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <pow.h>
+#include <primitives/transaction.h>
+#include <script/standard.h>
+#include <timedata.h>
+#include <txmempool.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <validationinterface.h>
#include <algorithm>
#include <queue>
diff --git a/src/miner.h b/src/miner.h
index db165e71c6..36276dc362 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_MINER_H
#define BITCOIN_MINER_H
-#include "primitives/block.h"
-#include "txmempool.h"
+#include <primitives/block.h>
+#include <txmempool.h>
#include <stdint.h>
#include <memory>
diff --git a/src/net.cpp b/src/net.cpp
index ea3840a708..a8e5143d5e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -4,23 +4,23 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "net.h"
-
-#include "addrman.h"
-#include "chainparams.h"
-#include "clientversion.h"
-#include "consensus/consensus.h"
-#include "crypto/common.h"
-#include "crypto/sha256.h"
-#include "hash.h"
-#include "primitives/transaction.h"
-#include "netbase.h"
-#include "scheduler.h"
-#include "ui_interface.h"
-#include "utilstrencodings.h"
+#include <net.h>
+
+#include <addrman.h>
+#include <chainparams.h>
+#include <clientversion.h>
+#include <consensus/consensus.h>
+#include <crypto/common.h>
+#include <crypto/sha256.h>
+#include <hash.h>
+#include <primitives/transaction.h>
+#include <netbase.h>
+#include <scheduler.h>
+#include <ui_interface.h>
+#include <utilstrencodings.h>
#ifdef WIN32
#include <string.h>
@@ -444,7 +444,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
CAddress addr_bind = GetBindAddress(hSocket);
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false);
- pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices);
pnode->AddRef();
return pnode;
@@ -685,7 +684,7 @@ void CNode::copyStats(CNodeStats &stats)
X(cleanSubVer);
}
X(fInbound);
- X(fAddnode);
+ X(m_manual_connection);
X(nStartingHeight);
{
LOCK(cs_vSend);
@@ -962,6 +961,16 @@ static bool CompareNodeTXTime(const NodeEvictionCandidate &a, const NodeEviction
return a.nTimeConnected > b.nTimeConnected;
}
+
+//! Sort an array by the specified comparator, then erase the last K elements.
+template<typename T, typename Comparator>
+static void EraseLastKElements(std::vector<T> &elements, Comparator comparator, size_t k)
+{
+ std::sort(elements.begin(), elements.end(), comparator);
+ size_t eraseSize = std::min(k, elements.size());
+ elements.erase(elements.end() - eraseSize, elements.end());
+}
+
/** Try to find a connection to evict when the node is full.
* Extreme care must be taken to avoid opening the node to attacker
* triggered network partitioning.
@@ -985,48 +994,29 @@ bool CConnman::AttemptToEvictConnection()
continue;
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
node->nLastBlockTime, node->nLastTXTime,
- (node->nServices & nRelevantServices) == nRelevantServices,
+ HasAllDesirableServiceFlags(node->nServices),
node->fRelayTxes, node->pfilter != nullptr, node->addr, node->nKeyedNetGroup};
vEvictionCandidates.push_back(candidate);
}
}
- if (vEvictionCandidates.empty()) return false;
-
// Protect connections with certain characteristics
// Deterministically select 4 peers to protect by netgroup.
// An attacker cannot predict which netgroups will be protected
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNetGroupKeyed);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, CompareNetGroupKeyed, 4);
// Protect the 8 nodes with the lowest minimum ping time.
// An attacker cannot manipulate this metric without physically moving nodes closer to the target.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, ReverseCompareNodeMinPingTime, 8);
// Protect 4 nodes that most recently sent us transactions.
// An attacker cannot manipulate this metric without performing useful work.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeTXTime);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, CompareNodeTXTime, 4);
// Protect 4 nodes that most recently sent us blocks.
// An attacker cannot manipulate this metric without performing useful work.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), CompareNodeBlockTime);
- vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
-
- if (vEvictionCandidates.empty()) return false;
-
+ EraseLastKElements(vEvictionCandidates, CompareNodeBlockTime, 4);
// Protect the half of the remaining nodes which have been connected the longest.
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
- std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
- vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
+ EraseLastKElements(vEvictionCandidates, ReverseCompareNodeTimeConnected, vEvictionCandidates.size() / 2);
if (vEvictionCandidates.empty()) return false;
@@ -1037,12 +1027,12 @@ bool CConnman::AttemptToEvictConnection()
int64_t nMostConnectionsTime = 0;
std::map<uint64_t, std::vector<NodeEvictionCandidate> > mapNetGroupNodes;
for (const NodeEvictionCandidate &node : vEvictionCandidates) {
- mapNetGroupNodes[node.nKeyedNetGroup].push_back(node);
- int64_t grouptime = mapNetGroupNodes[node.nKeyedNetGroup][0].nTimeConnected;
- size_t groupsize = mapNetGroupNodes[node.nKeyedNetGroup].size();
+ std::vector<NodeEvictionCandidate> &group = mapNetGroupNodes[node.nKeyedNetGroup];
+ group.push_back(node);
+ int64_t grouptime = group[0].nTimeConnected;
- if (groupsize > nMostConnections || (groupsize == nMostConnections && grouptime > nMostConnectionsTime)) {
- nMostConnections = groupsize;
+ if (group.size() > nMostConnections || (group.size() == nMostConnections && grouptime > nMostConnectionsTime)) {
+ nMostConnections = group.size();
nMostConnectionsTime = grouptime;
naMostConnections = node.nKeyedNetGroup;
}
@@ -1544,22 +1534,20 @@ void ThreadMapPort()
void MapPort(bool fUseUPnP)
{
- static boost::thread* upnp_thread = nullptr;
+ static std::unique_ptr<boost::thread> upnp_thread;
if (fUseUPnP)
{
if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
- delete upnp_thread;
}
- upnp_thread = new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort));
+ upnp_thread.reset(new boost::thread(boost::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)));
}
else if (upnp_thread) {
upnp_thread->interrupt();
upnp_thread->join();
- delete upnp_thread;
- upnp_thread = nullptr;
+ upnp_thread.reset();
}
}
@@ -1602,7 +1590,7 @@ void CConnman::ThreadDNSAddressSeed()
LOCK(cs_vNodes);
int nRelevant = 0;
for (auto pnode : vNodes) {
- nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);
+ nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound;
}
if (nRelevant >= 2) {
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
@@ -1624,7 +1612,7 @@ void CConnman::ThreadDNSAddressSeed()
} else {
std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd;
- ServiceFlags requiredServiceBits = nRelevantServices;
+ ServiceFlags requiredServiceBits = GetDesirableServiceFlags(NODE_NONE);
std::string host = GetDNSHost(seed, &requiredServiceBits);
CNetAddr resolveSource;
if (!resolveSource.SetInternal(host)) {
@@ -1694,6 +1682,37 @@ void CConnman::ProcessOneShot()
}
}
+bool CConnman::GetTryNewOutboundPeer()
+{
+ return m_try_another_outbound_peer;
+}
+
+void CConnman::SetTryNewOutboundPeer(bool flag)
+{
+ m_try_another_outbound_peer = flag;
+ LogPrint(BCLog::NET, "net: setting try another outbound peer=%s\n", flag ? "true" : "false");
+}
+
+// Return the number of peers we have over our outbound connection limit
+// Exclude peers that are marked for disconnect, or are going to be
+// disconnected soon (eg one-shots and feelers)
+// Also exclude peers that haven't finished initial connection handshake yet
+// (so that we don't decide we're over our desired connection limit, and then
+// evict some peer that has finished the handshake)
+int CConnman::GetExtraOutboundCount()
+{
+ int nOutbound = 0;
+ {
+ LOCK(cs_vNodes);
+ for (CNode* pnode : vNodes) {
+ if (!pnode->fInbound && !pnode->m_manual_connection && !pnode->fFeeler && !pnode->fDisconnect && !pnode->fOneShot && pnode->fSuccessfullyConnected) {
+ ++nOutbound;
+ }
+ }
+ }
+ return std::max(nOutbound - nMaxOutbound, 0);
+}
+
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
// Connect to specific addresses
@@ -1705,7 +1724,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
for (const std::string& strAddr : connect)
{
CAddress addr(CService(), NODE_NONE);
- OpenNetworkConnection(addr, false, nullptr, strAddr.c_str());
+ OpenNetworkConnection(addr, false, nullptr, strAddr.c_str(), false, false, true);
for (int i = 0; i < 10 && i < nLoop; i++)
{
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
@@ -1753,17 +1772,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// Only connect out to one peer per network group (/16 for IPv4).
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect.
int nOutbound = 0;
- int nOutboundRelevant = 0;
std::set<std::vector<unsigned char> > setConnected;
{
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
- if (!pnode->fInbound && !pnode->fAddnode) {
-
- // Count the peers that have all relevant services
- if (pnode->fSuccessfullyConnected && !pnode->fFeeler && ((pnode->nServices & nRelevantServices) == nRelevantServices)) {
- nOutboundRelevant++;
- }
+ if (!pnode->fInbound && !pnode->m_manual_connection) {
// 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
@@ -1788,7 +1801,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// * Only make a feeler connection once every few minutes.
//
bool fFeeler = false;
- if (nOutbound >= nMaxOutbound) {
+
+ if (nOutbound >= nMaxOutbound && !GetTryNewOutboundPeer()) {
int64_t nTime = GetTimeMicros(); // The current time right now (in microseconds).
if (nTime > nNextFeeler) {
nNextFeeler = PoissonNextSend(nTime, FEELER_INTERVAL);
@@ -1818,21 +1832,16 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
if (IsLimited(addr))
continue;
- // only connect to full nodes
- if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
- continue;
-
// only consider very recently tried nodes after 30 failed attempts
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
- // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up.
- ServiceFlags nRequiredServices = nRelevantServices;
- if (nTries >= 40 && nOutbound < (nMaxOutbound >> 1)) {
- nRequiredServices = REQUIRED_SERVICES;
- }
-
- if ((addr.nServices & nRequiredServices) != nRequiredServices) {
+ // for non-feelers, require all the services we'll want,
+ // for feelers, only require they be a full node (only because most
+ // SPV clients don't have a good address DB available)
+ if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) {
+ continue;
+ } else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) {
continue;
}
@@ -1841,13 +1850,6 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
continue;
addrConnect = addr;
-
- // regardless of the services assumed to be available, only require the minimum if half or more outbound have relevant services
- if (nOutboundRelevant >= (nMaxOutbound >> 1)) {
- addrConnect.nServices = REQUIRED_SERVICES;
- } else {
- addrConnect.nServices = nRequiredServices;
- }
break;
}
@@ -1946,7 +1948,7 @@ void CConnman::ThreadOpenAddedConnections()
}
// 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 fAddnode)
+bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection)
{
//
// Initiate outbound network connection
@@ -1975,8 +1977,8 @@ bool CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;
- if (fAddnode)
- pnode->fAddnode = true;
+ if (manual_connection)
+ pnode->m_manual_connection = true;
m_msgproc->InitializeNode(pnode);
{
@@ -2220,9 +2222,8 @@ CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : nSeed0(nSeed0In), nSe
nLastNodeId = 0;
nSendBufferMaxSize = 0;
nReceiveFloodSize = 0;
- semOutbound = nullptr;
- semAddnode = nullptr;
flagInterruptMsgProc = false;
+ SetTryNewOutboundPeer(false);
Options connOptions;
Init(connOptions);
@@ -2326,11 +2327,11 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
if (semOutbound == nullptr) {
// initialize semaphore
- semOutbound = new CSemaphore(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
+ semOutbound = MakeUnique<CSemaphore>(std::min((nMaxOutbound + nMaxFeeler), nMaxConnections));
}
if (semAddnode == nullptr) {
// initialize semaphore
- semAddnode = new CSemaphore(nMaxAddnode);
+ semAddnode = MakeUnique<CSemaphore>(nMaxAddnode);
}
//
@@ -2453,10 +2454,8 @@ void CConnman::Stop()
vNodes.clear();
vNodesDisconnected.clear();
vhListenSocket.clear();
- delete semOutbound;
- semOutbound = nullptr;
- delete semAddnode;
- semAddnode = nullptr;
+ semOutbound.reset();
+ semAddnode.reset();
}
void CConnman::DeleteNode(CNode* pnode)
@@ -2712,7 +2711,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nSendVersion(0)
{
nServices = NODE_NONE;
- nServicesExpected = NODE_NONE;
hSocket = hSocketIn;
nRecvVersion = INIT_PROTO_VERSION;
nLastSend = 0;
@@ -2725,7 +2723,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
strSubVer = "";
fWhitelisted = false;
fOneShot = false;
- fAddnode = false;
+ m_manual_connection = false;
fClient = false; // set by version message
fFeeler = false;
fSuccessfullyConnected = false;
@@ -2743,7 +2741,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nNextInvSend = 0;
fRelayTxes = false;
fSentAddr = false;
- pfilter = new CBloomFilter();
+ pfilter = MakeUnique<CBloomFilter>();
timeLastMempoolReq = 0;
nLastBlockTime = 0;
nLastTXTime = 0;
@@ -2773,9 +2771,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
CNode::~CNode()
{
CloseSocket(hSocket);
-
- if (pfilter)
- delete pfilter;
}
void CNode::AskFor(const CInv& inv)
diff --git a/src/net.h b/src/net.h
index 905d6eb956..a7223050e7 100644
--- a/src/net.h
+++ b/src/net.h
@@ -6,21 +6,21 @@
#ifndef BITCOIN_NET_H
#define BITCOIN_NET_H
-#include "addrdb.h"
-#include "addrman.h"
-#include "amount.h"
-#include "bloom.h"
-#include "compat.h"
-#include "hash.h"
-#include "limitedmap.h"
-#include "netaddress.h"
-#include "policy/feerate.h"
-#include "protocol.h"
-#include "random.h"
-#include "streams.h"
-#include "sync.h"
-#include "uint256.h"
-#include "threadinterrupt.h"
+#include <addrdb.h>
+#include <addrman.h>
+#include <amount.h>
+#include <bloom.h>
+#include <compat.h>
+#include <hash.h>
+#include <limitedmap.h>
+#include <netaddress.h>
+#include <policy/feerate.h>
+#include <protocol.h>
+#include <random.h>
+#include <streams.h>
+#include <sync.h>
+#include <uint256.h>
+#include <threadinterrupt.h>
#include <atomic>
#include <deque>
@@ -84,8 +84,6 @@ static const bool DEFAULT_FORCEDNSSEED = false;
static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
-static const ServiceFlags REQUIRED_SERVICES = NODE_NETWORK;
-
// NOTE: When adjusting this, update rpcnet:setban's help ("24h")
static const unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; // Default 24-hour ban
@@ -130,7 +128,6 @@ public:
struct Options
{
ServiceFlags nLocalServices = NODE_NONE;
- ServiceFlags nRelevantServices = NODE_NONE;
int nMaxConnections = 0;
int nMaxOutbound = 0;
int nMaxAddnode = 0;
@@ -152,7 +149,6 @@ public:
void Init(const Options& connOptions) {
nLocalServices = connOptions.nLocalServices;
- nRelevantServices = connOptions.nRelevantServices;
nMaxConnections = connOptions.nMaxConnections;
nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections);
nMaxAddnode = connOptions.nMaxAddnode;
@@ -175,7 +171,7 @@ public:
void Interrupt();
bool GetNetworkActive() const { return fNetworkActive; };
void SetNetworkActive(bool active);
- bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool fAddnode = false);
+ bool OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false);
bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@@ -255,6 +251,19 @@ public:
void GetBanned(banmap_t &banmap);
void SetBanned(const banmap_t &banmap);
+ // This allows temporarily exceeding nMaxOutbound, with the goal of finding
+ // a peer that is better than all our current peers.
+ void SetTryNewOutboundPeer(bool flag);
+ bool GetTryNewOutboundPeer();
+
+ // Return the number of outbound peers we have in excess of our target (eg,
+ // if we previously called SetTryNewOutboundPeer(true), and have since set
+ // to false, we may have extra peers that we wish to disconnect). This may
+ // return a value less than (num_outbound_connections - num_outbound_slots)
+ // in cases where some outbound connections are not yet fully connected, or
+ // not yet fully disconnected.
+ int GetExtraOutboundCount();
+
bool AddNode(const std::string& node);
bool RemoveAddedNode(const std::string& node);
std::vector<AddedNodeInfo> GetAddedNodeInfo();
@@ -390,11 +399,8 @@ private:
/** Services this instance offers */
ServiceFlags nLocalServices;
- /** Services this instance cares about */
- ServiceFlags nRelevantServices;
-
- CSemaphore *semOutbound;
- CSemaphore *semAddnode;
+ std::unique_ptr<CSemaphore> semOutbound;
+ std::unique_ptr<CSemaphore> semAddnode;
int nMaxConnections;
int nMaxOutbound;
int nMaxAddnode;
@@ -420,6 +426,13 @@ private:
std::thread threadOpenAddedConnections;
std::thread threadOpenConnections;
std::thread threadMessageHandler;
+
+ /** flag for deciding to connect to an extra outbound peer,
+ * in excess of nMaxOutbound
+ * This takes the place of a feeler connection */
+ std::atomic_bool m_try_another_outbound_peer;
+
+ friend struct CConnmanTest;
};
extern std::unique_ptr<CConnman> g_connman;
void Discover(boost::thread_group& threadGroup);
@@ -513,7 +526,7 @@ public:
int nVersion;
std::string cleanSubVer;
bool fInbound;
- bool fAddnode;
+ bool m_manual_connection;
int nStartingHeight;
uint64_t nSendBytes;
mapMsgCmdSize mapSendBytesPerMsgCmd;
@@ -585,7 +598,6 @@ class CNode
public:
// socket
std::atomic<ServiceFlags> nServices;
- ServiceFlags nServicesExpected;
SOCKET hSocket;
size_t nSendSize; // total size of all vSendMsg entries
size_t nSendOffset; // offset inside the first vSendMsg already sent
@@ -623,7 +635,7 @@ public:
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 m_manual_connection;
bool fClient;
const bool fInbound;
std::atomic_bool fSuccessfullyConnected;
@@ -636,7 +648,7 @@ public:
bool fSentAddr;
CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter;
- CBloomFilter* pfilter;
+ std::unique_ptr<CBloomFilter> pfilter;
std::atomic<int> nRefCount;
const uint64_t nKeyedNetGroup;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index b5e37722df..442cd00c9b 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -3,33 +3,34 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "net_processing.h"
-
-#include "addrman.h"
-#include "arith_uint256.h"
-#include "blockencodings.h"
-#include "chainparams.h"
-#include "consensus/validation.h"
-#include "hash.h"
-#include "init.h"
-#include "validation.h"
-#include "merkleblock.h"
-#include "net.h"
-#include "netmessagemaker.h"
-#include "netbase.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "reverse_iterator.h"
-#include "tinyformat.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
+#include <net_processing.h>
+
+#include <addrman.h>
+#include <arith_uint256.h>
+#include <blockencodings.h>
+#include <chainparams.h>
+#include <consensus/validation.h>
+#include <hash.h>
+#include <init.h>
+#include <validation.h>
+#include <merkleblock.h>
+#include <net.h>
+#include <netmessagemaker.h>
+#include <netbase.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <reverse_iterator.h>
+#include <scheduler.h>
+#include <tinyformat.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
@@ -124,6 +125,12 @@ namespace {
/** Number of peers from which we're downloading blocks. */
int nPeersWithValidatedDownloads = 0;
+ /** Number of outbound peers with m_chain_sync.m_protect. */
+ int g_outbound_peers_with_protect_from_disconnect = 0;
+
+ /** When our tip was last updated. */
+ int64_t g_last_tip_update = 0;
+
/** Relay map, protected by cs_main. */
typedef std::map<uint256, CTransactionRef> MapRelay;
MapRelay mapRelay;
@@ -201,6 +208,36 @@ struct CNodeState {
*/
bool fSupportsDesiredCmpctVersion;
+ /** State used to enforce CHAIN_SYNC_TIMEOUT
+ * Only in effect for outbound, non-manual connections, with
+ * m_protect == false
+ * Algorithm: if a peer's best known block has less work than our tip,
+ * set a timeout CHAIN_SYNC_TIMEOUT seconds in the future:
+ * - If at timeout their best known block now has more work than our tip
+ * when the timeout was set, then either reset the timeout or clear it
+ * (after comparing against our current tip's work)
+ * - If at timeout their best known block still has less work than our
+ * tip did when the timeout was set, then send a getheaders message,
+ * and set a shorter timeout, HEADERS_RESPONSE_TIME seconds in future.
+ * If their best known block is still behind when that new timeout is
+ * reached, disconnect.
+ */
+ struct ChainSyncTimeoutState {
+ //! A timeout used for checking whether our peer has sufficiently synced
+ int64_t m_timeout;
+ //! A header with the work we require on our peer's chain
+ const CBlockIndex * m_work_header;
+ //! After timeout is reached, set to true after sending getheaders
+ bool m_sent_getheaders;
+ //! Whether this peer is protected from disconnection due to a bad/slow chain
+ bool m_protect;
+ };
+
+ ChainSyncTimeoutState m_chain_sync;
+
+ //! Time of last new block announcement
+ int64_t m_last_block_announcement;
+
CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
fCurrentlyConnected = false;
nMisbehavior = 0;
@@ -223,6 +260,8 @@ struct CNodeState {
fHaveWitness = false;
fWantsCmpctWitness = false;
fSupportsDesiredCmpctVersion = false;
+ m_chain_sync = { 0, nullptr, false, false };
+ m_last_block_announcement = 0;
}
};
@@ -379,25 +418,32 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) {
}
}
connman->ForNode(nodeid, [connman](CNode* pfrom){
- bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
- connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), [connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
- connman->PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->ForNode(lNodesAnnouncingHeaderAndIDs.front(), [connman, nCMPCTBLOCKVersion](CNode* pnodeStop){
+ connman->PushMessage(pnodeStop, CNetMsgMaker(pnodeStop->GetSendVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/false, nCMPCTBLOCKVersion));
return true;
});
lNodesAnnouncingHeaderAndIDs.pop_front();
}
- fAnnounceUsingCMPCTBLOCK = true;
- connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion));
+ connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::SENDCMPCT, /*fAnnounceUsingCMPCTBLOCK=*/true, nCMPCTBLOCKVersion));
lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
return true;
});
}
}
+bool TipMayBeStale(const Consensus::Params &consensusParams)
+{
+ AssertLockHeld(cs_main);
+ if (g_last_tip_update == 0) {
+ g_last_tip_update = GetTime();
+ }
+ return g_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty();
+}
+
// Requires cs_main
bool CanDirectFetch(const Consensus::Params &consensusParams)
{
@@ -504,6 +550,22 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
} // namespace
+// This function is used for testing the stale tip eviction logic, see
+// DoS_tests.cpp
+void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
+{
+ LOCK(cs_main);
+ CNodeState *state = State(node);
+ if (state) state->m_last_block_announcement = time_in_seconds;
+}
+
+// Returns true for outbound peers, excluding manual connections, feelers, and
+// one-shots
+bool IsOutboundDisconnectionCandidate(const CNode *node)
+{
+ return !(node->fInbound || node->m_manual_connection || node->fFeeler || node->fOneShot);
+}
+
void PeerLogicValidation::InitializeNode(CNode *pnode) {
CAddress addr = pnode->addr;
std::string addrName = pnode->GetAddrName();
@@ -536,6 +598,8 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
nPreferredDownload -= state->fPreferredDownload;
nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
assert(nPeersWithValidatedDownloads >= 0);
+ g_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;
+ assert(g_outbound_peers_with_protect_from_disconnect >= 0);
mapNodeState.erase(nodeid);
@@ -544,6 +608,7 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
assert(mapBlocksInFlight.empty());
assert(nPreferredDownload == 0);
assert(nPeersWithValidatedDownloads == 0);
+ assert(g_outbound_peers_with_protect_from_disconnect == 0);
}
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
}
@@ -568,7 +633,7 @@ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
// mapOrphanTransactions
//
-void AddToCompactExtraTransactions(const CTransactionRef& tx)
+void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN);
if (max_extra_txn <= 0)
@@ -716,18 +781,28 @@ void Misbehaving(NodeId pnode, int howmuch)
// To prevent fingerprinting attacks, only send blocks/headers outside of the
// active chain if they are no more than a month older (both in time, and in
-// best equivalent proof of work) than the best header chain we know about.
-static bool StaleBlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
+// best equivalent proof of work) than the best header chain we know about and
+// we fully-validated them at some point.
+static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
AssertLockHeld(cs_main);
- return (pindexBestHeader != nullptr) &&
+ if (chainActive.Contains(pindex)) return true;
+ return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
(pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
}
-PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {
+PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler) : connman(connmanIn), m_stale_tip_check_time(0) {
// Initialize global variables that cannot be constructed at startup.
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
+
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ // Stale tip checking and peer eviction are on two different timers, but we
+ // don't want them to get out of sync due to drift in the scheduler, so we
+ // combine them in one function and schedule at the quicker (peer-eviction)
+ // timer.
+ static_assert(EXTRA_PEER_CHECK_INTERVAL < STALE_CHECK_INTERVAL, "peer eviction timer should be less than stale tip check timer");
+ scheduler.scheduleEvery(std::bind(&PeerLogicValidation::CheckForStaleTipAndEvictPeers, this, consensusParams), EXTRA_PEER_CHECK_INTERVAL * 1000);
}
void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted) {
@@ -758,6 +833,8 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pb
}
LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased);
}
+
+ g_last_tip_update = GetTime();
}
// All of the following cache a recent block, and are protected by cs_most_recent_block
@@ -999,14 +1076,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
CValidationState dummy;
ActivateBestChain(dummy, Params(), a_recent_block);
}
- if (chainActive.Contains(mi->second)) {
- send = true;
- } else {
- send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) &&
- StaleBlockRequestAllowed(mi->second, consensusParams);
- if (!send) {
- LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
- }
+ send = BlockRequestAllowed(mi->second, consensusParams);
+ if (!send) {
+ LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
}
}
// disconnect node in case we have reached the outbound limit for serving historical blocks
@@ -1166,6 +1238,225 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
+bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool punish_duplicate_invalid)
+{
+ const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
+ size_t nCount = headers.size();
+
+ if (nCount == 0) {
+ // Nothing interesting. Stop asking this peers for more headers.
+ return true;
+ }
+
+ bool received_new_header = false;
+ const CBlockIndex *pindexLast = nullptr;
+ {
+ LOCK(cs_main);
+ CNodeState *nodestate = State(pfrom->GetId());
+
+ // If this looks like it could be a block announcement (nCount <
+ // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
+ // don't connect:
+ // - Send a getheaders message in response to try to connect the chain.
+ // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
+ // don't connect before giving DoS points
+ // - Once a headers message is received that is valid and does connect,
+ // nUnconnectingHeaders gets reset back to 0.
+ if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
+ nodestate->nUnconnectingHeaders++;
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
+ headers[0].GetHash().ToString(),
+ headers[0].hashPrevBlock.ToString(),
+ pindexBestHeader->nHeight,
+ pfrom->GetId(), nodestate->nUnconnectingHeaders);
+ // Set hashLastUnknownBlock for this peer, so that if we
+ // eventually get the headers - even from a different peer -
+ // we can use this peer to download.
+ UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
+
+ if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
+ Misbehaving(pfrom->GetId(), 20);
+ }
+ return true;
+ }
+
+ uint256 hashLastBlock;
+ for (const CBlockHeader& header : headers) {
+ if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
+ Misbehaving(pfrom->GetId(), 20);
+ return error("non-continuous headers sequence");
+ }
+ hashLastBlock = header.GetHash();
+ }
+
+ // If we don't have the last header, then they'll have given us
+ // something new (if these headers are valid).
+ if (mapBlockIndex.find(hashLastBlock) == mapBlockIndex.end()) {
+ received_new_header = true;
+ }
+ }
+
+ CValidationState state;
+ CBlockHeader first_invalid_header;
+ if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
+ int nDoS;
+ if (state.IsInvalid(nDoS)) {
+ LOCK(cs_main);
+ if (nDoS > 0) {
+ Misbehaving(pfrom->GetId(), nDoS);
+ }
+ if (punish_duplicate_invalid && mapBlockIndex.find(first_invalid_header.GetHash()) != mapBlockIndex.end()) {
+ // Goal: don't allow outbound peers to use up our outbound
+ // connection slots if they are on incompatible chains.
+ //
+ // We ask the caller to set punish_invalid appropriately based
+ // on the peer and the method of header delivery (compact
+ // blocks are allowed to be invalid in some circumstances,
+ // under BIP 152).
+ // Here, we try to detect the narrow situation that we have a
+ // valid block header (ie it was valid at the time the header
+ // was received, and hence stored in mapBlockIndex) but know the
+ // block is invalid, and that a peer has announced that same
+ // block as being on its active chain.
+ // Disconnect the peer in such a situation.
+ //
+ // Note: if the header that is invalid was not accepted to our
+ // mapBlockIndex at all, that may also be grounds for
+ // disconnecting the peer, as the chain they are on is likely
+ // to be incompatible. However, there is a circumstance where
+ // that does not hold: if the header's timestamp is more than
+ // 2 hours ahead of our current time. In that case, the header
+ // may become valid in the future, and we don't want to
+ // disconnect a peer merely for serving us one too-far-ahead
+ // block header, to prevent an attacker from splitting the
+ // network by mining a block right at the 2 hour boundary.
+ //
+ // TODO: update the DoS logic (or, rather, rewrite the
+ // DoS-interface between validation and net_processing) so that
+ // the interface is cleaner, and so that we disconnect on all the
+ // reasons that a peer's headers chain is incompatible
+ // with ours (eg block->nVersion softforks, MTP violations,
+ // etc), and not just the duplicate-invalid case.
+ pfrom->fDisconnect = true;
+ }
+ return error("invalid header received");
+ }
+ }
+
+ {
+ LOCK(cs_main);
+ CNodeState *nodestate = State(pfrom->GetId());
+ if (nodestate->nUnconnectingHeaders > 0) {
+ LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders);
+ }
+ nodestate->nUnconnectingHeaders = 0;
+
+ assert(pindexLast);
+ UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
+
+ // From here, pindexBestKnownBlock should be guaranteed to be non-null,
+ // because it is set in UpdateBlockAvailability. Some nullptr checks
+ // are still present, however, as belt-and-suspenders.
+
+ if (received_new_header && pindexLast->nChainWork > chainActive.Tip()->nChainWork) {
+ nodestate->m_last_block_announcement = GetTime();
+ }
+
+ if (nCount == MAX_HEADERS_RESULTS) {
+ // Headers message had its maximum size; the peer may have more headers.
+ // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
+ // from there instead.
+ LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
+ }
+
+ bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
+ // If this set of headers is valid and ends in a block with at least as
+ // much work as our tip, download as much as possible.
+ if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
+ std::vector<const CBlockIndex*> vToFetch;
+ const CBlockIndex *pindexWalk = pindexLast;
+ // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
+ while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
+ !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
+ (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
+ // We don't have this block, and it's not yet in flight.
+ vToFetch.push_back(pindexWalk);
+ }
+ pindexWalk = pindexWalk->pprev;
+ }
+ // If pindexWalk still isn't on our main chain, we're looking at a
+ // very large reorg at a time we think we're close to caught up to
+ // the main chain -- this shouldn't really happen. Bail out on the
+ // direct fetch and rely on parallel download instead.
+ if (!chainActive.Contains(pindexWalk)) {
+ LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
+ pindexLast->GetBlockHash().ToString(),
+ pindexLast->nHeight);
+ } else {
+ std::vector<CInv> vGetData;
+ // Download as much as possible, from earliest to latest.
+ for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
+ if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ // Can't download any more from this peer
+ break;
+ }
+ uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
+ MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex);
+ LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
+ pindex->GetBlockHash().ToString(), pfrom->GetId());
+ }
+ if (vGetData.size() > 1) {
+ LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
+ pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
+ }
+ if (vGetData.size() > 0) {
+ if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) {
+ // In any case, we want to download using a compact block, not a regular one
+ vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
+ }
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
+ }
+ }
+ }
+ // If we're in IBD, we want outbound peers that will serve us a useful
+ // chain. Disconnect peers that are on chains with insufficient work.
+ if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
+ // When nCount < MAX_HEADERS_RESULTS, we know we have no more
+ // headers to fetch from this peer.
+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ // This peer has too little work on their headers chain to help
+ // us sync -- disconnect if using an outbound slot (unless
+ // whitelisted or addnode).
+ // Note: We compare their tip to nMinimumChainWork (rather than
+ // chainActive.Tip()) because we won't start block download
+ // until we have a headers chain that has at least
+ // nMinimumChainWork, even if a peer has a chain past our tip,
+ // as an anti-DoS measure.
+ if (IsOutboundDisconnectionCandidate(pfrom)) {
+ LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom->GetId());
+ pfrom->fDisconnect = true;
+ }
+ }
+ }
+
+ if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) {
+ // If this is an outbound peer, check to see if we should protect
+ // it from the bad/lagging chain logic.
+ if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
+ LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId());
+ nodestate->m_chain_sync.m_protect = true;
+ ++g_outbound_peers_with_protect_from_disconnect;
+ }
+ }
+ }
+
+ return true;
+}
+
bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
@@ -1245,11 +1536,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{
connman->SetServices(pfrom->addr, nServices);
}
- if (pfrom->nServicesExpected & ~nServices)
+ if (!pfrom->fInbound && !pfrom->fFeeler && !pfrom->m_manual_connection && !HasAllDesirableServiceFlags(nServices))
{
- LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, pfrom->nServicesExpected);
+ LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices));
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD,
- strprintf("Expected to offer services %08x", pfrom->nServicesExpected)));
+ strprintf("Expected to offer services %08x", GetDesirableServiceFlags(nServices))));
pfrom->fDisconnect = true;
return false;
}
@@ -1468,7 +1759,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (interruptMsgProc)
return true;
- if ((addr.nServices & REQUIRED_SERVICES) != REQUIRED_SERVICES)
+ // We only bother storing full nodes, though this may include
+ // things which we would not make an outbound connection to, in
+ // part because we may make feeler connections to them.
+ if (!MayHaveUsefulAddressDB(addr.nServices))
continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
@@ -1737,8 +2031,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
pindex = (*mi).second;
- if (!chainActive.Contains(pindex) &&
- !StaleBlockRequestAllowed(pindex, chainparams.GetConsensus())) {
+ if (!BlockRequestAllowed(pindex, chainparams.GetConsensus())) {
LogPrintf("%s: ignoring request from peer=%i for old block header that isn't in the main chain\n", __func__, pfrom->GetId());
return true;
}
@@ -1809,7 +2102,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!AlreadyHave(inv) &&
AcceptToMemoryPool(mempool, state, ptx, &fMissingInputs, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
- mempool.check(pcoinsTip);
+ mempool.check(pcoinsTip.get());
RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
vWorkQueue.emplace_back(inv.hash, i);
@@ -1876,7 +2169,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
recentRejects->insert(orphanHash);
}
}
- mempool.check(pcoinsTip);
+ mempool.check(pcoinsTip.get());
}
}
@@ -1970,6 +2263,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
CBlockHeaderAndShortTxIDs cmpctblock;
vRecv >> cmpctblock;
+ bool received_new_header = false;
+
{
LOCK(cs_main);
@@ -1979,6 +2274,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
return true;
}
+
+ if (mapBlockIndex.find(cmpctblock.header.GetHash()) == mapBlockIndex.end()) {
+ received_new_header = true;
+ }
}
const CBlockIndex *pindex = nullptr;
@@ -2005,7 +2304,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// If we end up treating this as a plain headers message, call that as well
// without cs_main.
bool fRevertToHeaderProcessing = false;
- CDataStream vHeadersMsg(SER_NETWORK, PROTOCOL_VERSION);
// Keep a CBlock for "optimistic" compactblock reconstructions (see
// below)
@@ -2018,6 +2316,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
assert(pindex);
UpdateBlockAvailability(pfrom->GetId(), pindex->GetBlockHash());
+ CNodeState *nodestate = State(pfrom->GetId());
+
+ // If this was a new header with more work than our tip, update the
+ // peer's last block announcement time
+ if (received_new_header && pindex->nChainWork > chainActive.Tip()->nChainWork) {
+ nodestate->m_last_block_announcement = GetTime();
+ }
+
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> >::iterator blockInFlightIt = mapBlocksInFlight.find(pindex->GetBlockHash());
bool fAlreadyInFlight = blockInFlightIt != mapBlocksInFlight.end();
@@ -2040,8 +2346,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!fAlreadyInFlight && !CanDirectFetch(chainparams.GetConsensus()))
return true;
- CNodeState *nodestate = State(pfrom->GetId());
-
if (IsWitnessEnabled(pindex->pprev, chainparams.GetConsensus()) && !nodestate->fSupportsDesiredCmpctVersion) {
// Don't bother trying to process compact blocks from v1 peers
// after segwit activates.
@@ -2122,10 +2426,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
} else {
// If this was an announce-cmpctblock, we want the same treatment as a header message
- // Dirty hack to process as if it were just a headers message (TODO: move message handling into their own functions)
- std::vector<CBlock> headers;
- headers.push_back(cmpctblock.header);
- vHeadersMsg << headers;
fRevertToHeaderProcessing = true;
}
}
@@ -2134,8 +2434,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (fProcessBLOCKTXN)
return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc);
- if (fRevertToHeaderProcessing)
- return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman, interruptMsgProc);
+ if (fRevertToHeaderProcessing) {
+ // Headers received from HB compact block peers are permitted to be
+ // relayed before full validation (see BIP 152), so we don't want to disconnect
+ // the peer if the header turns out to be for an invalid block.
+ // Note that if a peer tries to build on an invalid chain, that
+ // will be detected and the peer will be banned.
+ return ProcessHeadersMessage(pfrom, connman, {cmpctblock.header}, chainparams, /*punish_duplicate_invalid=*/false);
+ }
if (fBlockReconstructed) {
// If we got here, we were able to optimistically reconstruct a
@@ -2145,7 +2451,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false));
}
bool fNewBlock = false;
- ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
+ // Setting fForceProcessing to true means that we bypass some of
+ // our anti-DoS protections in AcceptBlock, which filters
+ // unrequested blocks that might be trying to waste our resources
+ // (eg disk space). Because we only try to reconstruct blocks when
+ // we're close to caught up (via the CanDirectFetch() requirement
+ // above, combined with the behavior of not requesting blocks until
+ // we have a chain with at least nMinimumChainWork), and we ignore
+ // compact blocks with less work than our tip, it is safe to treat
+ // reconstructed compact blocks as having been requested.
+ ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
} else {
@@ -2225,7 +2540,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
bool fNewBlock = false;
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
- ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
+ // This bypasses some anti-DoS logic in AcceptBlock (eg to prevent
+ // disk-space attacks), but this should be safe due to the
+ // protections in the compact block handler -- see related comment
+ // in compact block optimistic reconstruction handling.
+ ProcessNewBlock(chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock);
if (fNewBlock) {
pfrom->nLastBlockTime = GetTime();
} else {
@@ -2253,136 +2572,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- if (nCount == 0) {
- // Nothing interesting. Stop asking this peers for more headers.
- return true;
- }
-
- const CBlockIndex *pindexLast = nullptr;
- {
- LOCK(cs_main);
- CNodeState *nodestate = State(pfrom->GetId());
-
- // If this looks like it could be a block announcement (nCount <
- // MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
- // don't connect:
- // - Send a getheaders message in response to try to connect the chain.
- // - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
- // don't connect before giving DoS points
- // - Once a headers message is received that is valid and does connect,
- // nUnconnectingHeaders gets reset back to 0.
- if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
- nodestate->nUnconnectingHeaders++;
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
- LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
- headers[0].GetHash().ToString(),
- headers[0].hashPrevBlock.ToString(),
- pindexBestHeader->nHeight,
- pfrom->GetId(), nodestate->nUnconnectingHeaders);
- // Set hashLastUnknownBlock for this peer, so that if we
- // eventually get the headers - even from a different peer -
- // we can use this peer to download.
- UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
-
- if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
- Misbehaving(pfrom->GetId(), 20);
- }
- return true;
- }
-
- uint256 hashLastBlock;
- for (const CBlockHeader& header : headers) {
- if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) {
- Misbehaving(pfrom->GetId(), 20);
- return error("non-continuous headers sequence");
- }
- hashLastBlock = header.GetHash();
- }
- }
-
- CValidationState state;
- if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast)) {
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- if (nDoS > 0) {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), nDoS);
- }
- return error("invalid header received");
- }
- }
-
- {
- LOCK(cs_main);
- CNodeState *nodestate = State(pfrom->GetId());
- if (nodestate->nUnconnectingHeaders > 0) {
- LogPrint(BCLog::NET, "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->GetId(), nodestate->nUnconnectingHeaders);
- }
- nodestate->nUnconnectingHeaders = 0;
-
- assert(pindexLast);
- UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
-
- if (nCount == MAX_HEADERS_RESULTS) {
- // Headers message had its maximum size; the peer may have more headers.
- // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
- // from there instead.
- LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
- }
-
- bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
- // If this set of headers is valid and ends in a block with at least as
- // much work as our tip, download as much as possible.
- if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
- std::vector<const CBlockIndex*> vToFetch;
- const CBlockIndex *pindexWalk = pindexLast;
- // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
- while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
- !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
- (!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
- // We don't have this block, and it's not yet in flight.
- vToFetch.push_back(pindexWalk);
- }
- pindexWalk = pindexWalk->pprev;
- }
- // If pindexWalk still isn't on our main chain, we're looking at a
- // very large reorg at a time we think we're close to caught up to
- // the main chain -- this shouldn't really happen. Bail out on the
- // direct fetch and rely on parallel download instead.
- if (!chainActive.Contains(pindexWalk)) {
- LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
- pindexLast->GetBlockHash().ToString(),
- pindexLast->nHeight);
- } else {
- std::vector<CInv> vGetData;
- // Download as much as possible, from earliest to latest.
- for (const CBlockIndex *pindex : reverse_iterate(vToFetch)) {
- if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
- // Can't download any more from this peer
- break;
- }
- uint32_t nFetchFlags = GetFetchFlags(pfrom);
- vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), pindex);
- LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
- pindex->GetBlockHash().ToString(), pfrom->GetId());
- }
- if (vGetData.size() > 1) {
- LogPrint(BCLog::NET, "Downloading blocks toward %s (%d) via headers direct fetch\n",
- pindexLast->GetBlockHash().ToString(), pindexLast->nHeight);
- }
- if (vGetData.size() > 0) {
- if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size() == 1 && mapBlocksInFlight.size() == 1 && pindexLast->pprev->IsValid(BLOCK_VALID_CHAIN)) {
- // In any case, we want to download using a compact block, not a regular one
- vGetData[0] = CInv(MSG_CMPCT_BLOCK, vGetData[0].hash);
- }
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETDATA, vGetData));
- }
- }
- }
- }
+ // Headers received via a HEADERS message should be valid, and reflect
+ // the chain the peer is on. If we receive a known-invalid header,
+ // disconnect the peer if it is using one of our outbound connection
+ // slots.
+ bool should_punish = !pfrom->fInbound && !pfrom->m_manual_connection;
+ return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish);
}
else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
@@ -2392,11 +2587,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom->GetId());
- // Process all blocks from whitelisted peers, even if not requested,
- // unless we're still syncing with the network.
- // Such an unrequested block may still be processed, subject to the
- // conditions in AcceptBlock().
- bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
+ bool forceProcessing = false;
const uint256 hash(pblock->GetHash());
{
LOCK(cs_main);
@@ -2560,8 +2751,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
else
{
LOCK(pfrom->cs_filter);
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter(filter);
+ pfrom->pfilter.reset(new CBloomFilter(filter));
pfrom->pfilter->UpdateEmptyFull();
pfrom->fRelayTxes = true;
}
@@ -2597,8 +2787,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
{
LOCK(pfrom->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
- delete pfrom->pfilter;
- pfrom->pfilter = new CBloomFilter();
+ pfrom->pfilter.reset(new CBloomFilter());
}
pfrom->fRelayTxes = true;
}
@@ -2644,8 +2833,8 @@ static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman)
state.fShouldBan = false;
if (pnode->fWhitelisted)
LogPrintf("Warning: not punishing whitelisted peer %s!\n", pnode->addr.ToString());
- else if (pnode->fAddnode)
- LogPrintf("Warning: not punishing addnoded peer %s!\n", pnode->addr.ToString());
+ else if (pnode->m_manual_connection)
+ LogPrintf("Warning: not punishing manually-connected peer %s!\n", pnode->addr.ToString());
else {
pnode->fDisconnect = true;
if (pnode->addr.IsLocal())
@@ -2780,6 +2969,136 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
return fMoreWork;
}
+void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds)
+{
+ AssertLockHeld(cs_main);
+
+ CNodeState &state = *State(pto->GetId());
+ const CNetMsgMaker msgMaker(pto->GetSendVersion());
+
+ if (!state.m_chain_sync.m_protect && IsOutboundDisconnectionCandidate(pto) && state.fSyncStarted) {
+ // This is an outbound peer subject to disconnection if they don't
+ // announce a block with as much work as the current tip within
+ // CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if
+ // their chain has more work than ours, we should sync to it,
+ // unless it's invalid, in which case we should find that out and
+ // disconnect from them elsewhere).
+ if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork) {
+ if (state.m_chain_sync.m_timeout != 0) {
+ state.m_chain_sync.m_timeout = 0;
+ state.m_chain_sync.m_work_header = nullptr;
+ state.m_chain_sync.m_sent_getheaders = false;
+ }
+ } else if (state.m_chain_sync.m_timeout == 0 || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) {
+ // Our best block known by this peer is behind our tip, and we're either noticing
+ // that for the first time, OR this peer was able to catch up to some earlier point
+ // where we checked against our tip.
+ // Either way, set a new timeout based on current tip.
+ state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT;
+ state.m_chain_sync.m_work_header = chainActive.Tip();
+ state.m_chain_sync.m_sent_getheaders = false;
+ } else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) {
+ // No evidence yet that our peer has synced to a chain with work equal to that
+ // of our tip, when we first detected it was behind. Send a single getheaders
+ // message to give the peer a chance to update us.
+ if (state.m_chain_sync.m_sent_getheaders) {
+ // They've run out of time to catch up!
+ LogPrintf("Disconnecting outbound peer %d for old chain, best known block = %s\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>");
+ pto->fDisconnect = true;
+ } else {
+ assert(state.m_chain_sync.m_work_header);
+ LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
+ state.m_chain_sync.m_sent_getheaders = true;
+ constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes
+ // Bump the timeout to allow a response, which could clear the timeout
+ // (if the response shows the peer has synced), reset the timeout (if
+ // the peer syncs to the required work but not to our tip), or result
+ // in disconnect (if we advance to the timeout and pindexBestKnownBlock
+ // has not sufficiently progressed)
+ state.m_chain_sync.m_timeout = time_in_seconds + HEADERS_RESPONSE_TIME;
+ }
+ }
+ }
+}
+
+void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
+{
+ // Check whether we have too many outbound peers
+ int extra_peers = connman->GetExtraOutboundCount();
+ if (extra_peers > 0) {
+ // If we have more outbound peers than we target, disconnect one.
+ // Pick the outbound peer that least recently announced
+ // us a new block, with ties broken by choosing the more recent
+ // connection (higher node id)
+ NodeId worst_peer = -1;
+ int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
+
+ LOCK(cs_main);
+
+ connman->ForEachNode([&](CNode* pnode) {
+ // Ignore non-outbound peers, or nodes marked for disconnect already
+ if (!IsOutboundDisconnectionCandidate(pnode) || pnode->fDisconnect) return;
+ CNodeState *state = State(pnode->GetId());
+ if (state == nullptr) return; // shouldn't be possible, but just in case
+ // Don't evict our protected peers
+ if (state->m_chain_sync.m_protect) return;
+ if (state->m_last_block_announcement < oldest_block_announcement || (state->m_last_block_announcement == oldest_block_announcement && pnode->GetId() > worst_peer)) {
+ worst_peer = pnode->GetId();
+ oldest_block_announcement = state->m_last_block_announcement;
+ }
+ });
+ if (worst_peer != -1) {
+ bool disconnected = connman->ForNode(worst_peer, [&](CNode *pnode) {
+ // Only disconnect a peer that has been connected to us for
+ // some reasonable fraction of our check-frequency, to give
+ // it time for new information to have arrived.
+ // Also don't disconnect any peer we're trying to download a
+ // block from.
+ CNodeState &state = *State(pnode->GetId());
+ if (time_in_seconds - pnode->nTimeConnected > MINIMUM_CONNECT_TIME && state.nBlocksInFlight == 0) {
+ LogPrint(BCLog::NET, "disconnecting extra outbound peer=%d (last block announcement received at time %d)\n", pnode->GetId(), oldest_block_announcement);
+ pnode->fDisconnect = true;
+ return true;
+ } else {
+ LogPrint(BCLog::NET, "keeping outbound peer=%d chosen for eviction (connect time: %d, blocks_in_flight: %d)\n", pnode->GetId(), pnode->nTimeConnected, state.nBlocksInFlight);
+ return false;
+ }
+ });
+ if (disconnected) {
+ // If we disconnected an extra peer, that means we successfully
+ // connected to at least one peer after the last time we
+ // detected a stale tip. Don't try any more extra peers until
+ // we next detect a stale tip, to limit the load we put on the
+ // network from these extra connections.
+ connman->SetTryNewOutboundPeer(false);
+ }
+ }
+ }
+}
+
+void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams)
+{
+ if (connman == nullptr) return;
+
+ int64_t time_in_seconds = GetTime();
+
+ EvictExtraOutboundPeers(time_in_seconds);
+
+ if (time_in_seconds > m_stale_tip_check_time) {
+ LOCK(cs_main);
+ // Check whether our tip is stale, and if so, allow using an extra
+ // outbound peer
+ if (TipMayBeStale(consensusParams)) {
+ LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update);
+ connman->SetTryNewOutboundPeer(true);
+ } else if (connman->GetTryNewOutboundPeer()) {
+ connman->SetTryNewOutboundPeer(false);
+ }
+ m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL;
+ }
+}
+
class CompareInvMempoolOrder
{
CTxMemPool *mp;
@@ -3246,6 +3565,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptM
}
}
+ // Check that outbound peers have reasonable chains
+ // GetTime() is used by this anti-DoS logic so we can test this using mocktime
+ ConsiderEviction(pto, GetTime());
//
// Message: getdata (blocks)
diff --git a/src/net_processing.h b/src/net_processing.h
index 79745cdd42..3fc1e05835 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -6,8 +6,9 @@
#ifndef BITCOIN_NET_PROCESSING_H
#define BITCOIN_NET_PROCESSING_H
-#include "net.h"
-#include "validationinterface.h"
+#include <net.h>
+#include <validationinterface.h>
+#include <consensus/params.h>
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
@@ -21,13 +22,25 @@ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
* Timeout = base + per_header * (expected number of headers) */
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header
+/** Protect at least this many outbound peers from disconnection due to slow/
+ * behind headers chain.
+ */
+static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4;
+/** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */
+static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes
+/** How frequently to check for stale tips, in seconds */
+static constexpr int64_t STALE_CHECK_INTERVAL = 10 * 60; // 10 minutes
+/** How frequently to check for extra outbound peers and disconnect, in seconds */
+static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45;
+/** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict, in seconds */
+static constexpr int64_t MINIMUM_CONNECT_TIME = 30;
class PeerLogicValidation : public CValidationInterface, public NetEventsInterface {
private:
- CConnman* connman;
+ CConnman* const connman;
public:
- explicit PeerLogicValidation(CConnman* connman);
+ explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler);
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
@@ -47,6 +60,13 @@ public:
* @return True if there is more work to be done
*/
bool SendMessages(CNode* pto, std::atomic<bool>& interrupt) override;
+
+ void ConsiderEviction(CNode *pto, int64_t time_in_seconds);
+ void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams);
+ void EvictExtraOutboundPeers(int64_t time_in_seconds);
+
+private:
+ int64_t m_stale_tip_check_time; //! Next time to check for stale tip
};
struct CNodeStateStats {
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index b8a261c921..3ef3c67ae4 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -4,13 +4,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifdef HAVE_CONFIG_H
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "netaddress.h"
-#include "hash.h"
-#include "utilstrencodings.h"
-#include "tinyformat.h"
+#include <netaddress.h>
+#include <hash.h>
+#include <utilstrencodings.h>
+#include <tinyformat.h>
static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
diff --git a/src/netaddress.h b/src/netaddress.h
index 6ca99b36b5..3b542b4748 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -6,11 +6,11 @@
#define BITCOIN_NETADDRESS_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat.h"
-#include "serialize.h"
+#include <compat.h>
+#include <serialize.h>
#include <stdint.h>
#include <string>
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 5a560bc95a..bd1eaf062f 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -4,17 +4,17 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifdef HAVE_CONFIG_H
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "netbase.h"
+#include <netbase.h>
-#include "hash.h"
-#include "sync.h"
-#include "uint256.h"
-#include "random.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <hash.h>
+#include <sync.h>
+#include <uint256.h>
+#include <random.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <atomic>
@@ -291,7 +291,7 @@ struct ProxyCredentials
std::string password;
};
-/** Convert SOCKS5 reply to a an error message */
+/** Convert SOCKS5 reply to an error message */
std::string Socks5ErrorString(uint8_t err)
{
switch(err) {
diff --git a/src/netbase.h b/src/netbase.h
index e7d7bcb375..0a07be87b7 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -6,12 +6,12 @@
#define BITCOIN_NETBASE_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat.h"
-#include "netaddress.h"
-#include "serialize.h"
+#include <compat.h>
+#include <netaddress.h>
+#include <serialize.h>
#include <stdint.h>
#include <string>
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index 79b2501c5d..ea7fccacb2 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_NETMESSAGEMAKER_H
#define BITCOIN_NETMESSAGEMAKER_H
-#include "net.h"
-#include "serialize.h"
+#include <net.h>
+#include <serialize.h>
class CNetMsgMaker
{
diff --git a/src/noui.cpp b/src/noui.cpp
index 4bfb75fa29..feb3464a56 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "noui.h"
+#include <noui.h>
-#include "ui_interface.h"
-#include "util.h"
+#include <ui_interface.h>
+#include <util.h>
#include <cstdio>
#include <stdint.h>
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index a089c02284..26c44ee0cf 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "feerate.h"
+#include <policy/feerate.h>
-#include "tinyformat.h"
+#include <tinyformat.h>
const std::string CURRENCY_UNIT = "BTC";
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 3449cdd699..35b1b23786 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_POLICY_FEERATE_H
#define BITCOIN_POLICY_FEERATE_H
-#include "amount.h"
-#include "serialize.h"
+#include <amount.h>
+#include <serialize.h>
#include <string>
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index dcf49de5f1..013116318b 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/fees.h"
-#include "policy/policy.h"
+#include <policy/fees.h>
+#include <policy/policy.h>
-#include "amount.h"
-#include "clientversion.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "streams.h"
-#include "txmempool.h"
-#include "util.h"
+#include <amount.h>
+#include <clientversion.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <streams.h>
+#include <txmempool.h>
+#include <util.h>
static constexpr double INF_FEERATE = 1e99;
@@ -180,6 +180,7 @@ TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
: buckets(defaultBuckets), bucketMap(defaultBucketMap)
{
decay = _decay;
+ assert(_scale != 0 && "_scale must be non-zero");
scale = _scale;
confAvg.resize(maxPeriods);
for (unsigned int i = 0; i < maxPeriods; i++) {
@@ -418,6 +419,9 @@ void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets
throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
}
filein >> scale;
+ if (scale == 0) {
+ throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
+ }
}
filein >> avg;
@@ -544,16 +548,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
bucketMap[INF_FEERATE] = bucketIndex;
assert(bucketMap.size() == buckets.size());
- feeStats = new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE);
- shortStats = new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE);
- longStats = new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE);
+ feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
+ shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
+ longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
}
CBlockPolicyEstimator::~CBlockPolicyEstimator()
{
- delete feeStats;
- delete shortStats;
- delete longStats;
}
void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
@@ -686,16 +687,16 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
double sufficientTxs = SUFFICIENT_FEETXS;
switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: {
- stats = shortStats;
+ stats = shortStats.get();
sufficientTxs = SUFFICIENT_TXS_SHORT;
break;
}
case FeeEstimateHorizon::MED_HALFLIFE: {
- stats = feeStats;
+ stats = feeStats.get();
break;
}
case FeeEstimateHorizon::LONG_HALFLIFE: {
- stats = longStats;
+ stats = longStats.get();
break;
}
default: {
@@ -998,12 +999,9 @@ bool CBlockPolicyEstimator::Read(CAutoFile& filein)
}
// Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
- delete feeStats;
- delete shortStats;
- delete longStats;
- feeStats = fileFeeStats.release();
- shortStats = fileShortStats.release();
- longStats = fileLongStats.release();
+ feeStats = std::move(fileFeeStats);
+ shortStats = std::move(fileShortStats);
+ longStats = std::move(fileLongStats);
nBestSeenHeight = nFileBestSeenHeight;
historicalFirst = nFileHistoricalFirst;
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 6edaf28714..6528560f52 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -5,11 +5,11 @@
#ifndef BITCOIN_POLICYESTIMATOR_H
#define BITCOIN_POLICYESTIMATOR_H
-#include "amount.h"
-#include "feerate.h"
-#include "uint256.h"
-#include "random.h"
-#include "sync.h"
+#include <amount.h>
+#include <policy/feerate.h>
+#include <uint256.h>
+#include <random.h>
+#include <sync.h>
#include <map>
#include <string>
@@ -245,9 +245,9 @@ private:
std::map<uint256, TxStatsInfo> mapMemPoolTxs;
/** Classes to track historical data on transaction confirmations */
- TxConfirmStats* feeStats;
- TxConfirmStats* shortStats;
- TxConfirmStats* longStats;
+ std::unique_ptr<TxConfirmStats> feeStats;
+ std::unique_ptr<TxConfirmStats> shortStats;
+ std::unique_ptr<TxConfirmStats> longStats;
unsigned int trackedTxs;
unsigned int untrackedTxs;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index b2fb284508..b69bed5d6f 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -5,14 +5,14 @@
// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic
-#include "policy/policy.h"
-
-#include "consensus/validation.h"
-#include "validation.h"
-#include "coins.h"
-#include "tinyformat.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <policy/policy.h>
+
+#include <consensus/validation.h>
+#include <validation.h>
+#include <coins.h>
+#include <tinyformat.h>
+#include <util.h>
+#include <utilstrencodings.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
diff --git a/src/policy/policy.h b/src/policy/policy.h
index ef71dd73bc..f3f8ebbbb4 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_POLICY_POLICY_H
#define BITCOIN_POLICY_POLICY_H
-#include "consensus/consensus.h"
-#include "feerate.h"
-#include "script/interpreter.h"
-#include "script/standard.h"
+#include <consensus/consensus.h>
+#include <policy/feerate.h>
+#include <script/interpreter.h>
+#include <script/standard.h>
#include <string>
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 755ef83c9a..e9692d4b48 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/rbf.h"
+#include <policy/rbf.h>
bool SignalsOptInRBF(const CTransaction &tx)
{
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 22c73f3319..1a5218e120 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_POLICY_RBF_H
#define BITCOIN_POLICY_RBF_H
-#include "txmempool.h"
+#include <txmempool.h>
static const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd;
diff --git a/src/pow.cpp b/src/pow.cpp
index 7d87c6bbb7..cecb54ca7b 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "pow.h"
+#include <pow.h>
-#include "arith_uint256.h"
-#include "chain.h"
-#include "primitives/block.h"
-#include "uint256.h"
+#include <arith_uint256.h>
+#include <chain.h>
+#include <primitives/block.h>
+#include <uint256.h>
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
{
diff --git a/src/pow.h b/src/pow.h
index e203f492a1..db2f5343b5 100644
--- a/src/pow.h
+++ b/src/pow.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_POW_H
#define BITCOIN_POW_H
-#include "consensus/params.h"
+#include <consensus/params.h>
#include <stdint.h>
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index 3774ac3e4b..9e20565511 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "primitives/block.h"
+#include <primitives/block.h>
-#include "hash.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
-#include "crypto/common.h"
+#include <hash.h>
+#include <tinyformat.h>
+#include <utilstrencodings.h>
+#include <crypto/common.h>
uint256 CBlockHeader::GetHash() const
{
diff --git a/src/primitives/block.h b/src/primitives/block.h
index 292df40896..4957958c6a 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_PRIMITIVES_BLOCK_H
#define BITCOIN_PRIMITIVES_BLOCK_H
-#include "primitives/transaction.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <primitives/transaction.h>
+#include <serialize.h>
+#include <uint256.h>
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index e0a106adb9..d8230d1423 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "primitives/transaction.h"
+#include <primitives/transaction.h>
-#include "hash.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
+#include <hash.h>
+#include <tinyformat.h>
+#include <utilstrencodings.h>
std::string COutPoint::ToString() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 18d524e23d..32f45e5748 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -7,10 +7,10 @@
#define BITCOIN_PRIMITIVES_TRANSACTION_H
#include <stdint.h>
-#include "amount.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <amount.h>
+#include <script/script.h>
+#include <serialize.h>
+#include <uint256.h>
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
diff --git a/src/protocol.cpp b/src/protocol.cpp
index da87e40091..8c34c4196e 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "protocol.h"
+#include <protocol.h>
-#include "util.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilstrencodings.h>
#ifndef WIN32
# include <arpa/inet.h>
diff --git a/src/protocol.h b/src/protocol.h
index 67e01d9606..bc31434515 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -10,10 +10,10 @@
#ifndef BITCOIN_PROTOCOL_H
#define BITCOIN_PROTOCOL_H
-#include "netaddress.h"
-#include "serialize.h"
-#include "uint256.h"
-#include "version.h"
+#include <netaddress.h>
+#include <serialize.h>
+#include <uint256.h>
+#include <version.h>
#include <stdint.h>
#include <string>
@@ -27,16 +27,13 @@
class CMessageHeader
{
public:
- enum {
- MESSAGE_START_SIZE = 4,
- COMMAND_SIZE = 12,
- MESSAGE_SIZE_SIZE = 4,
- CHECKSUM_SIZE = 4,
-
- MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE,
- CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE,
- HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE
- };
+ static constexpr size_t MESSAGE_START_SIZE = 4;
+ static constexpr size_t COMMAND_SIZE = 12;
+ static constexpr size_t MESSAGE_SIZE_SIZE = 4;
+ static constexpr size_t CHECKSUM_SIZE = 4;
+ static constexpr size_t MESSAGE_SIZE_OFFSET = MESSAGE_START_SIZE + COMMAND_SIZE;
+ static constexpr size_t CHECKSUM_OFFSET = MESSAGE_SIZE_OFFSET + MESSAGE_SIZE_SIZE;
+ static constexpr size_t HEADER_SIZE = MESSAGE_START_SIZE + COMMAND_SIZE + MESSAGE_SIZE_SIZE + CHECKSUM_SIZE;
typedef unsigned char MessageStartChars[MESSAGE_START_SIZE];
explicit CMessageHeader(const MessageStartChars& pchMessageStartIn);
@@ -277,6 +274,43 @@ enum ServiceFlags : uint64_t {
// BIP process.
};
+/**
+ * Gets the set of service flags which are "desirable" for a given peer.
+ *
+ * These are the flags which are required for a peer to support for them
+ * to be "interesting" to us, ie for us to wish to use one of our few
+ * outbound connection slots for or for us to wish to prioritize keeping
+ * their connection around.
+ *
+ * Relevant service flags may be peer- and state-specific in that the
+ * version of the peer may determine which flags are required (eg in the
+ * case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers
+ * unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which
+ * case NODE_NETWORK_LIMITED suffices).
+ *
+ * Thus, generally, avoid calling with peerServices == NODE_NONE.
+ */
+static ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
+ return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
+}
+
+/**
+ * A shortcut for (services & GetDesirableServiceFlags(services))
+ * == GetDesirableServiceFlags(services), ie determines whether the given
+ * set of service flags are sufficient for a peer to be "relevant".
+ */
+static inline bool HasAllDesirableServiceFlags(ServiceFlags services) {
+ return !(GetDesirableServiceFlags(services) & (~services));
+}
+
+/**
+ * Checks if a peer with the given service flags may be capable of having a
+ * robust address-storage DB. Currently an alias for checking NODE_NETWORK.
+ */
+static inline bool MayHaveUsefulAddressDB(ServiceFlags services) {
+ return services & NODE_NETWORK;
+}
+
/** A CService with information about it as peer */
class CAddress : public CService
{
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 2dd0a87fc9..7f5ec1e8de 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "pubkey.h"
+#include <pubkey.h>
#include <secp256k1.h>
#include <secp256k1_recovery.h>
diff --git a/src/pubkey.h b/src/pubkey.h
index 65738d8fe2..c9f3c18eb3 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_PUBKEY_H
#define BITCOIN_PUBKEY_H
-#include "hash.h"
-#include "serialize.h"
-#include "uint256.h"
+#include <hash.h>
+#include <serialize.h>
+#include <uint256.h>
#include <stdexcept>
#include <vector>
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index f295bd4689..dda8dce391 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -3,18 +3,18 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "addressbookpage.h"
-#include "ui_addressbookpage.h"
+#include <qt/addressbookpage.h>
+#include <qt/forms/ui_addressbookpage.h>
-#include "addresstablemodel.h"
-#include "bitcoingui.h"
-#include "csvmodelwriter.h"
-#include "editaddressdialog.h"
-#include "guiutil.h"
-#include "platformstyle.h"
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoingui.h>
+#include <qt/csvmodelwriter.h>
+#include <qt/editaddressdialog.h>
+#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
#include <QIcon>
#include <QMenu>
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 0eb7ec4306..1d16940acb 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "addresstablemodel.h"
+#include <qt/addresstablemodel.h>
-#include "guiutil.h"
-#include "walletmodel.h"
+#include <qt/guiutil.h>
+#include <qt/walletmodel.h>
-#include "base58.h"
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <wallet/wallet.h>
#include <QFont>
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index e9f5c77a5b..a720ac956b 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -3,16 +3,16 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "askpassphrasedialog.h"
-#include "ui_askpassphrasedialog.h"
+#include <qt/askpassphrasedialog.h>
+#include <qt/forms/ui_askpassphrasedialog.h>
-#include "guiconstants.h"
-#include "walletmodel.h"
+#include <qt/guiconstants.h>
+#include <qt/walletmodel.h>
-#include "support/allocators/secure.h"
+#include <support/allocators/secure.h>
#include <QKeyEvent>
#include <QMessageBox>
@@ -70,6 +70,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) :
break;
}
textChanged();
+ connect(ui->toggleShowPasswordButton, SIGNAL(toggled(bool)), this, SLOT(toggleShowPassword(bool)));
connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
@@ -234,6 +235,15 @@ bool AskPassphraseDialog::event(QEvent *event)
return QWidget::event(event);
}
+void AskPassphraseDialog::toggleShowPassword(bool show)
+{
+ ui->toggleShowPasswordButton->setDown(show);
+ const auto mode = show ? QLineEdit::Normal : QLineEdit::Password;
+ ui->passEdit1->setEchoMode(mode);
+ ui->passEdit2->setEchoMode(mode);
+ ui->passEdit3->setEchoMode(mode);
+}
+
bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
/* Detect Caps Lock.
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 34bf7ccb31..7c6acc4650 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -43,6 +43,7 @@ private:
private Q_SLOTS:
void textChanged();
void secureClearPassFields();
+ void toggleShowPassword(bool);
protected:
bool event(QEvent *event);
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index f8a99506c1..84807da65d 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bantablemodel.h"
+#include <qt/bantablemodel.h>
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
-#include "sync.h"
-#include "utiltime.h"
+#include <sync.h>
+#include <utiltime.h>
#include <QDebug>
#include <QList>
diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h
index 062cfdc931..dc69dee20a 100644
--- a/src/qt/bantablemodel.h
+++ b/src/qt/bantablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_BANTABLEMODEL_H
#define BITCOIN_QT_BANTABLEMODEL_H
-#include "net.h"
+#include <net.h>
#include <QAbstractTableModel>
#include <QStringList>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 3fd58a2f9a..557d7efcec 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -3,38 +3,38 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "bitcoingui.h"
-
-#include "chainparams.h"
-#include "clientmodel.h"
-#include "fs.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "intro.h"
-#include "networkstyle.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "splashscreen.h"
-#include "utilitydialog.h"
-#include "winshutdownmonitor.h"
+#include <qt/bitcoingui.h>
+
+#include <chainparams.h>
+#include <qt/clientmodel.h>
+#include <fs.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/intro.h>
+#include <qt/networkstyle.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/splashscreen.h>
+#include <qt/utilitydialog.h>
+#include <qt/winshutdownmonitor.h>
#ifdef ENABLE_WALLET
-#include "paymentserver.h"
-#include "walletmodel.h"
+#include <qt/paymentserver.h>
+#include <qt/walletmodel.h>
#endif
-#include "init.h"
-#include "rpc/server.h"
-#include "scheduler.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "warnings.h"
+#include <init.h>
+#include <rpc/server.h>
+#include <scheduler.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <warnings.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
#endif
#include <stdint.h>
@@ -261,7 +261,7 @@ private:
void startThread();
};
-#include "bitcoin.moc"
+#include <qt/bitcoin.moc>
BitcoinCore::BitcoinCore():
QObject()
diff --git a/src/qt/bitcoinaddressvalidator.cpp b/src/qt/bitcoinaddressvalidator.cpp
index 362a71f04d..e8d174bf29 100644
--- a/src/qt/bitcoinaddressvalidator.cpp
+++ b/src/qt/bitcoinaddressvalidator.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinaddressvalidator.h"
+#include <qt/bitcoinaddressvalidator.h>
-#include "base58.h"
+#include <base58.h>
/* Base58 characters are:
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index 73eb35a54e..0b21349c54 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinamountfield.h"
+#include <qt/bitcoinamountfield.h>
-#include "bitcoinunits.h"
-#include "guiconstants.h"
-#include "qvaluecombobox.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiconstants.h>
+#include <qt/qvaluecombobox.h>
#include <QApplication>
#include <QAbstractSpinBox>
@@ -188,7 +188,7 @@ Q_SIGNALS:
void valueChanged();
};
-#include "bitcoinamountfield.moc"
+#include <qt/bitcoinamountfield.moc>
BitcoinAmountField::BitcoinAmountField(QWidget *parent) :
QWidget(parent),
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index 2f03a3d171..659ecb416b 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_BITCOINAMOUNTFIELD_H
#define BITCOIN_QT_BITCOINAMOUNTFIELD_H
-#include "amount.h"
+#include <amount.h>
#include <QWidget>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index dc55141900..cd3234c564 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -3,38 +3,38 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "bitcoingui.h"
-
-#include "bitcoinunits.h"
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "modaloverlay.h"
-#include "networkstyle.h"
-#include "notificator.h"
-#include "openuridialog.h"
-#include "optionsdialog.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "rpcconsole.h"
-#include "utilitydialog.h"
+#include <qt/bitcoingui.h>
+
+#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/modaloverlay.h>
+#include <qt/networkstyle.h>
+#include <qt/notificator.h>
+#include <qt/openuridialog.h>
+#include <qt/optionsdialog.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/rpcconsole.h>
+#include <qt/utilitydialog.h>
#ifdef ENABLE_WALLET
-#include "walletframe.h"
-#include "walletmodel.h"
+#include <qt/walletframe.h>
+#include <qt/walletmodel.h>
#endif // ENABLE_WALLET
#ifdef Q_OS_MAC
-#include "macdockiconhandler.h"
+#include <qt/macdockiconhandler.h>
#endif
-#include "chainparams.h"
-#include "init.h"
-#include "ui_interface.h"
-#include "util.h"
+#include <chainparams.h>
+#include <init.h>
+#include <ui_interface.h>
+#include <util.h>
#include <iostream>
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index aa45ea1f0a..1647975fec 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -6,10 +6,10 @@
#define BITCOIN_QT_BITCOINGUI_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "amount.h"
+#include <amount.h>
#include <QLabel>
#include <QMainWindow>
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 4da414a4e3..c8614fdfe0 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinunits.h"
+#include <qt/bitcoinunits.h>
-#include "primitives/transaction.h"
+#include <primitives/transaction.h>
#include <QStringList>
diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h
index 6ef37de380..3f5a7fd32d 100644
--- a/src/qt/bitcoinunits.h
+++ b/src/qt/bitcoinunits.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_BITCOINUNITS_H
#define BITCOIN_QT_BITCOINUNITS_H
-#include "amount.h"
+#include <amount.h>
#include <QAbstractListModel>
#include <QString>
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 52ce11cefd..78174b90a1 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "clientmodel.h"
-
-#include "bantablemodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "peertablemodel.h"
-
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "clientversion.h"
-#include "validation.h"
-#include "net.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "warnings.h"
+#include <qt/clientmodel.h>
+
+#include <qt/bantablemodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/peertablemodel.h>
+
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <clientversion.h>
+#include <validation.h>
+#include <net.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <warnings.h>
#include <stdint.h>
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 6952eb5064..03e633e375 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coincontroldialog.h"
-#include "ui_coincontroldialog.h"
-
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "txmempool.h"
-#include "walletmodel.h"
-
-#include "wallet/coincontrol.h"
-#include "init.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "validation.h" // For mempool
-#include "wallet/fees.h"
-#include "wallet/wallet.h"
+#include <qt/coincontroldialog.h>
+#include <qt/forms/ui_coincontroldialog.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <txmempool.h>
+#include <qt/walletmodel.h>
+
+#include <wallet/coincontrol.h>
+#include <init.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <validation.h> // For mempool
+#include <wallet/fees.h>
+#include <wallet/wallet.h>
#include <QApplication>
#include <QCheckBox>
@@ -582,8 +582,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
QString toolTipDust = tr("This label turns red if any recipient receives an amount smaller than the current dust threshold.");
// how many satoshis the estimated fee can vary per byte we guess wrong
- assert(nBytes != 0);
- double dFeeVary = (double)nPayFee / nBytes;
+ double dFeeVary = (nBytes != 0) ? (double)nPayFee / nBytes : 0;
QString toolTip4 = tr("Can vary +/- %1 satoshi(s) per input.").arg(dFeeVary);
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 4949c91771..51b0a42907 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_COINCONTROLDIALOG_H
#define BITCOIN_QT_COINCONTROLDIALOG_H
-#include "amount.h"
+#include <amount.h>
#include <QAbstractButton>
#include <QAction>
diff --git a/src/qt/coincontroltreewidget.cpp b/src/qt/coincontroltreewidget.cpp
index 88510b6168..b628824793 100644
--- a/src/qt/coincontroltreewidget.cpp
+++ b/src/qt/coincontroltreewidget.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coincontroltreewidget.h"
-#include "coincontroldialog.h"
+#include <qt/coincontroltreewidget.h>
+#include <qt/coincontroldialog.h>
CoinControlTreeWidget::CoinControlTreeWidget(QWidget *parent) :
QTreeWidget(parent)
diff --git a/src/qt/csvmodelwriter.cpp b/src/qt/csvmodelwriter.cpp
index df59927782..702757147b 100644
--- a/src/qt/csvmodelwriter.cpp
+++ b/src/qt/csvmodelwriter.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "csvmodelwriter.h"
+#include <qt/csvmodelwriter.h>
#include <QAbstractItemModel>
#include <QFile>
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index bb03c12f2d..0437f81a7e 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "editaddressdialog.h"
-#include "ui_editaddressdialog.h"
+#include <qt/editaddressdialog.h>
+#include <qt/forms/ui_editaddressdialog.h>
-#include "addresstablemodel.h"
-#include "guiutil.h"
+#include <qt/addresstablemodel.h>
+#include <qt/guiutil.h>
#include <QDataWidgetMapper>
#include <QMessageBox>
diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui
index a2105ecd0a..69803989cd 100644
--- a/src/qt/forms/askpassphrasedialog.ui
+++ b/src/qt/forms/askpassphrasedialog.ui
@@ -93,6 +93,13 @@
</widget>
</item>
<item row="3" column="1">
+ <widget class="QCheckBox" name="toggleShowPasswordButton">
+ <property name="text">
+ <string>Show password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
<widget class="QLabel" name="capsLabel">
<property name="font">
<font>
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index 1ea00eb5c3..d1237ad283 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -487,7 +487,7 @@
<customwidget>
<class>CoinControlTreeWidget</class>
<extends>QTreeWidget</extends>
- <header>coincontroltreewidget.h</header>
+ <header>qt/coincontroltreewidget.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 093e644bdc..bba822882e 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1424,7 +1424,7 @@
<customwidget>
<class>TrafficGraphWidget</class>
<extends>QWidget</extends>
- <header>trafficgraphwidget.h</header>
+ <header>qt/trafficgraphwidget.h</header>
<container>1</container>
<slots>
<slot>clear()</slot>
diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui
index c1aea36338..e968271107 100644
--- a/src/qt/forms/editaddressdialog.ui
+++ b/src/qt/forms/editaddressdialog.ui
@@ -71,7 +71,7 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/modaloverlay.ui b/src/qt/forms/modaloverlay.ui
index 65a7a6c77e..fdc52dc455 100644
--- a/src/qt/forms/modaloverlay.ui
+++ b/src/qt/forms/modaloverlay.ui
@@ -367,7 +367,7 @@ QLabel { color: rgb(40,40,40); }</string>
<customwidget>
<class>ModalOverlay</class>
<extends>QWidget</extends>
- <header>modaloverlay.h</header>
+ <header>qt/modaloverlay.h</header>
<container>1</container>
</customwidget>
</customwidgets>
diff --git a/src/qt/forms/openuridialog.ui b/src/qt/forms/openuridialog.ui
index 7fce858bd2..0e1048bc07 100644
--- a/src/qt/forms/openuridialog.ui
+++ b/src/qt/forms/openuridialog.ui
@@ -77,7 +77,7 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index e31bfee05e..a3721991ee 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -824,12 +824,12 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
<class>QValueComboBox</class>
<extends>QComboBox</extends>
- <header>qvaluecombobox.h</header>
+ <header>qt/qvaluecombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui
index 03fcb2fb50..58f030ebf0 100644
--- a/src/qt/forms/receivecoinsdialog.ui
+++ b/src/qt/forms/receivecoinsdialog.ui
@@ -28,23 +28,6 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QGridLayout" name="gridLayout">
- <item row="7" column="2">
- <widget class="QCheckBox" name="reuseAddress">
- <property name="toolTip">
- <string>Reuse one of the previously used receiving addresses. Reusing addresses has security and privacy issues. Do not use this unless re-generating a payment request made before.</string>
- </property>
- <property name="text">
- <string>R&amp;euse an existing receiving address (not recommended)</string>
- </property>
- </widget>
- </item>
- <item row="7" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string/>
- </property>
- </widget>
- </item>
<item row="6" column="0">
<widget class="QLabel" name="label_3">
<property name="toolTip">
@@ -127,7 +110,7 @@
</property>
</widget>
</item>
- <item row="8" column="2">
+ <item row="7" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="receiveButton">
@@ -184,7 +167,7 @@
</item>
</layout>
</item>
- <item row="8" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string/>
@@ -316,7 +299,7 @@
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qt/bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
</customwidgets>
@@ -324,7 +307,6 @@
<tabstop>reqLabel</tabstop>
<tabstop>reqAmount</tabstop>
<tabstop>reqMessage</tabstop>
- <tabstop>reuseAddress</tabstop>
<tabstop>receiveButton</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>recentRequestsView</tabstop>
diff --git a/src/qt/forms/receiverequestdialog.ui b/src/qt/forms/receiverequestdialog.ui
index 4163f4189c..dbe966b241 100644
--- a/src/qt/forms/receiverequestdialog.ui
+++ b/src/qt/forms/receiverequestdialog.ui
@@ -127,7 +127,7 @@
<customwidget>
<class>QRImageWidget</class>
<extends>QLabel</extends>
- <header>receiverequestdialog.h</header>
+ <header>qt/receiverequestdialog.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui
index a0e48334c1..9c89741afe 100644
--- a/src/qt/forms/sendcoinsdialog.ui
+++ b/src/qt/forms/sendcoinsdialog.ui
@@ -1264,12 +1264,12 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qt/bitcoinamountfield.h</header>
<container>1</container>
</customwidget>
</customwidgets>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index df06f36833..3c699abc6a 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -163,7 +163,7 @@
</widget>
</item>
<item row="2" column="1">
- <layout class="QHBoxLayout" name="horizontalLayoutAmount" stretch="0,1">
+ <layout class="QHBoxLayout" name="horizontalLayoutAmount" stretch="0,1,0">
<item>
<widget class="BitcoinAmountField" name="payAmount"/>
</item>
@@ -177,6 +177,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QPushButton" name="useAvailableBalanceButton">
+ <property name="text">
+ <string>Use available balance</string>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item row="3" column="0">
@@ -1248,12 +1255,12 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
<customwidget>
<class>BitcoinAmountField</class>
<extends>QLineEdit</extends>
- <header>bitcoinamountfield.h</header>
+ <header>qt/bitcoinamountfield.h</header>
</customwidget>
</customwidgets>
<tabstops>
diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui
index 92f6430c51..c9ddd757c1 100644
--- a/src/qt/forms/signverifymessagedialog.ui
+++ b/src/qt/forms/signverifymessagedialog.ui
@@ -380,7 +380,7 @@
<customwidget>
<class>QValidatedLineEdit</class>
<extends>QLineEdit</extends>
- <header>qvalidatedlineedit.h</header>
+ <header>qt/qvalidatedlineedit.h</header>
</customwidget>
</customwidgets>
<resources>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index d520d7d4be..80ee35a341 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -2,21 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "guiutil.h"
-
-#include "bitcoinaddressvalidator.h"
-#include "bitcoinunits.h"
-#include "qvalidatedlineedit.h"
-#include "walletmodel.h"
-
-#include "fs.h"
-#include "primitives/transaction.h"
-#include "init.h"
-#include "policy/policy.h"
-#include "protocol.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "util.h"
+#include <qt/guiutil.h>
+
+#include <qt/bitcoinaddressvalidator.h>
+#include <qt/bitcoinunits.h>
+#include <qt/qvalidatedlineedit.h>
+#include <qt/walletmodel.h>
+
+#include <fs.h>
+#include <primitives/transaction.h>
+#include <init.h>
+#include <policy/policy.h>
+#include <protocol.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <util.h>
#ifdef WIN32
#ifdef _WIN32_WINNT
@@ -31,9 +31,9 @@
#ifndef NOMINMAX
#define NOMINMAX
#endif
-#include "shellapi.h"
-#include "shlobj.h"
-#include "shlwapi.h"
+#include <shellapi.h>
+#include <shlobj.h>
+#include <shlwapi.h>
#endif
#include <boost/scoped_array.hpp>
@@ -984,6 +984,18 @@ QString formatNiceTimeOffset(qint64 secs)
return timeBehindText;
}
+QString formatBytes(uint64_t bytes)
+{
+ if(bytes < 1024)
+ return QString(QObject::tr("%1 B")).arg(bytes);
+ if(bytes < 1024 * 1024)
+ return QString(QObject::tr("%1 KB")).arg(bytes / 1024);
+ if(bytes < 1024 * 1024 * 1024)
+ return QString(QObject::tr("%1 MB")).arg(bytes / 1024 / 1024);
+
+ return QString(QObject::tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
+}
+
void ClickableLabel::mouseReleaseEvent(QMouseEvent *event)
{
Q_EMIT clicked(event->pos());
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index d10818d0c8..d0ab491952 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_QT_GUIUTIL_H
#define BITCOIN_QT_GUIUTIL_H
-#include "amount.h"
-#include "fs.h"
+#include <amount.h>
+#include <fs.h>
#include <QEvent>
#include <QHeaderView>
@@ -199,6 +199,8 @@ namespace GUIUtil
QString formatNiceTimeOffset(qint64 secs);
+ QString formatBytes(uint64_t bytes);
+
class ClickableLabel : public QLabel
{
Q_OBJECT
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 0ff95d8502..9e4c765101 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -3,16 +3,16 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "fs.h"
-#include "intro.h"
-#include "ui_intro.h"
+#include <fs.h>
+#include <qt/intro.h>
+#include <qt/forms/ui_intro.h>
-#include "guiutil.h"
+#include <qt/guiutil.h>
-#include "util.h"
+#include <util.h>
#include <QFileDialog>
#include <QSettings>
@@ -60,7 +60,7 @@ private:
Intro *intro;
};
-#include "intro.moc"
+#include <qt/intro.moc>
FreespaceChecker::FreespaceChecker(Intro *_intro)
{
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index e32a0bdda8..b707b0dda9 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "modaloverlay.h"
-#include "ui_modaloverlay.h"
+#include <qt/modaloverlay.h>
+#include <qt/forms/ui_modaloverlay.h>
-#include "guiutil.h"
+#include <qt/guiutil.h>
-#include "chainparams.h"
+#include <chainparams.h>
#include <QResizeEvent>
#include <QPropertyAnimation>
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index 4b81c54d36..42ae3ae566 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "networkstyle.h"
+#include <qt/networkstyle.h>
-#include "guiconstants.h"
+#include <qt/guiconstants.h>
#include <QApplication>
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index 937928315b..4f8732a9ce 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "notificator.h"
+#include <qt/notificator.h>
#include <QApplication>
#include <QByteArray>
@@ -24,7 +24,7 @@
// #define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
-#include "macnotificationhandler.h"
+#include <qt/macnotificationhandler.h>
#endif
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index 67f2b1df69..ef6f5c7ec5 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -6,7 +6,7 @@
#define BITCOIN_QT_NOTIFICATOR_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <QIcon>
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 3ee656d470..40671922f4 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "openuridialog.h"
-#include "ui_openuridialog.h"
+#include <qt/openuridialog.h>
+#include <qt/forms/ui_openuridialog.h>
-#include "guiutil.h"
-#include "walletmodel.h"
+#include <qt/guiutil.h>
+#include <qt/walletmodel.h>
#include <QUrl>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 53e2e5053c..d7aa8bc38b 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -3,19 +3,19 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "optionsdialog.h"
-#include "ui_optionsdialog.h"
+#include <qt/optionsdialog.h>
+#include <qt/forms/ui_optionsdialog.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
-#include "validation.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
-#include "netbase.h"
-#include "txdb.h" // for -dbcache defaults
+#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
+#include <netbase.h>
+#include <txdb.h> // for -dbcache defaults
#include <QDataWidgetMapper>
#include <QDir>
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index fb8c60d100..a0645d9a74 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -3,25 +3,25 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "optionsmodel.h"
+#include <qt/optionsmodel.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
-#include "amount.h"
-#include "init.h"
-#include "validation.h" // For DEFAULT_SCRIPTCHECK_THREADS
-#include "net.h"
-#include "netbase.h"
-#include "txdb.h" // for -dbcache defaults
-#include "intro.h"
+#include <amount.h>
+#include <init.h>
+#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
+#include <net.h>
+#include <netbase.h>
+#include <txdb.h> // for -dbcache defaults
+#include <qt/intro.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
#endif
#include <QNetworkProxy>
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 0ac82a4148..b6e8fdef68 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_OPTIONSMODEL_H
#define BITCOIN_QT_OPTIONSMODEL_H
-#include "amount.h"
+#include <amount.h>
#include <QAbstractListModel>
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index ba1839e7b4..7818607d30 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "overviewpage.h"
-#include "ui_overviewpage.h"
-
-#include "bitcoinunits.h"
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "transactionfilterproxy.h"
-#include "transactiontablemodel.h"
-#include "walletmodel.h"
+#include <qt/overviewpage.h>
+#include <qt/forms/ui_overviewpage.h>
+
+#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/transactionfilterproxy.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/walletmodel.h>
#include <QAbstractItemDelegate>
#include <QPainter>
@@ -106,7 +106,7 @@ public:
const PlatformStyle *platformStyle;
};
-#include "overviewpage.moc"
+#include <qt/overviewpage.moc>
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index d76b651ce6..1e09d907b0 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_OVERVIEWPAGE_H
#define BITCOIN_QT_OVERVIEWPAGE_H
-#include "amount.h"
+#include <amount.h>
#include <QWidget>
#include <memory>
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index d3799f59ab..4503728882 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -7,9 +7,9 @@
// with some extra methods
//
-#include "paymentrequestplus.h"
+#include <qt/paymentrequestplus.h>
-#include "util.h"
+#include <util.h>
#include <stdexcept>
@@ -194,8 +194,7 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c
qWarning() << "PaymentRequestPlus::getMerchant: SSL error: " << err.what();
}
- if (website)
- delete[] website;
+ delete[] website;
X509_STORE_CTX_free(store_ctx);
for (unsigned int i = 0; i < certs.size(); i++)
X509_free(certs[i]);
diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h
index a2fea3fdc6..e1388f2b5d 100644
--- a/src/qt/paymentrequestplus.h
+++ b/src/qt/paymentrequestplus.h
@@ -7,10 +7,10 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#include "paymentrequest.pb.h"
+#include <qt/paymentrequest.pb.h>
#pragma GCC diagnostic pop
-#include "base58.h"
+#include <base58.h>
#include <openssl/x509.h>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 169684cf6d..510a3783ae 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "paymentserver.h"
+#include <qt/paymentserver.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
-#include "base58.h"
-#include "chainparams.h"
-#include "policy/policy.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <chainparams.h>
+#include <policy/policy.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <wallet/wallet.h>
#include <cstdlib>
@@ -362,8 +362,7 @@ void PaymentServer::initNetManager()
{
if (!optionsModel)
return;
- if (netManager != nullptr)
- delete netManager;
+ delete netManager;
// netManager is used to fetch paymentrequests given in bitcoin: URIs
netManager = new QNetworkAccessManager(this);
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 98b2364b92..9adef9743d 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -32,8 +32,8 @@
// sends them to the server.
//
-#include "paymentrequestplus.h"
-#include "walletmodel.h"
+#include <qt/paymentrequestplus.h>
+#include <qt/walletmodel.h>
#include <QObject>
#include <QString>
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 42934f8055..cfafab2c8a 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "peertablemodel.h"
+#include <qt/peertablemodel.h>
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
-#include "validation.h" // for cs_main
-#include "sync.h"
+#include <validation.h> // for cs_main
+#include <sync.h>
#include <QDebug>
#include <QList>
@@ -33,6 +33,10 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
case PeerTableModel::Ping:
return pLeft->dMinPing < pRight->dMinPing;
+ case PeerTableModel::Sent:
+ return pLeft->nSendBytes < pRight->nSendBytes;
+ case PeerTableModel::Received:
+ return pLeft->nRecvBytes < pRight->nRecvBytes;
}
return false;
@@ -114,7 +118,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
clientModel(parent),
timer(0)
{
- columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping");
+ columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
priv.reset(new PeerTablePriv());
// default to unsorted
priv->sortColumn = -1;
@@ -173,10 +177,20 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
return QString::fromStdString(rec->nodeStats.cleanSubVer);
case Ping:
return GUIUtil::formatPingTime(rec->nodeStats.dMinPing);
+ case Sent:
+ return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
+ case Received:
+ return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
}
} else if (role == Qt::TextAlignmentRole) {
- if (index.column() == Ping)
- return (QVariant)(Qt::AlignRight | Qt::AlignVCenter);
+ switch (index.column()) {
+ case Ping:
+ case Sent:
+ case Received:
+ return QVariant(Qt::AlignRight | Qt::AlignVCenter);
+ default:
+ return QVariant();
+ }
}
return QVariant();
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index cc47b67ec9..e41fe4bb03 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_QT_PEERTABLEMODEL_H
#define BITCOIN_QT_PEERTABLEMODEL_H
-#include "net_processing.h" // For CNodeStateStats
-#include "net.h"
+#include <net_processing.h> // For CNodeStateStats
+#include <net.h>
#include <QAbstractTableModel>
#include <QStringList>
@@ -55,8 +55,10 @@ public:
enum ColumnIndex {
NetNodeId = 0,
Address = 1,
- Subversion = 2,
- Ping = 3
+ Ping = 2,
+ Sent = 3,
+ Received = 4,
+ Subversion = 5
};
/** @name Methods overridden from QAbstractTableModel
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index 1f4e1a442f..cc8ea3622b 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "platformstyle.h"
+#include <qt/platformstyle.h>
-#include "guiconstants.h"
+#include <qt/guiconstants.h>
#include <QApplication>
#include <QColor>
diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp
index 179ecdc8b3..4d6d5891c9 100644
--- a/src/qt/qvalidatedlineedit.cpp
+++ b/src/qt/qvalidatedlineedit.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "qvalidatedlineedit.h"
+#include <qt/qvalidatedlineedit.h>
-#include "bitcoinaddressvalidator.h"
-#include "guiconstants.h"
+#include <qt/bitcoinaddressvalidator.h>
+#include <qt/guiconstants.h>
QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) :
QLineEdit(parent),
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index a3b9b994ec..af5f6f8fd0 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "qvaluecombobox.h"
+#include <qt/qvaluecombobox.h>
QValueComboBox::QValueComboBox(QWidget *parent) :
QComboBox(parent), role(Qt::UserRole)
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 84f43266e1..d6e2beb312 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "receivecoinsdialog.h"
-#include "ui_receivecoinsdialog.h"
-
-#include "addressbookpage.h"
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "receiverequestdialog.h"
-#include "recentrequeststablemodel.h"
-#include "walletmodel.h"
+#include <qt/receivecoinsdialog.h>
+#include <qt/forms/ui_receivecoinsdialog.h>
+
+#include <qt/addressbookpage.h>
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/receiverequestdialog.h>
+#include <qt/recentrequeststablemodel.h>
+#include <qt/walletmodel.h>
#include <QAction>
#include <QCursor>
@@ -106,7 +106,6 @@ void ReceiveCoinsDialog::clear()
ui->reqAmount->clear();
ui->reqLabel->setText("");
ui->reqMessage->setText("");
- ui->reuseAddress->setChecked(false);
updateDisplayUnit();
}
@@ -135,25 +134,8 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
QString address;
QString label = ui->reqLabel->text();
- if(ui->reuseAddress->isChecked())
- {
- /* Choose existing receiving address */
- AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
- dlg.setModel(model->getAddressTableModel());
- if(dlg.exec())
- {
- address = dlg.getReturnValue();
- if(label.isEmpty()) /* If no label provided, use the previously used label */
- {
- label = model->getAddressTableModel()->labelForAddress(address);
- }
- } else {
- return;
- }
- } else {
- /* Generate new receiving address */
- address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "");
- }
+ /* Generate new receiving address */
+ address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "");
SendCoinsRecipient info(address, label,
ui->reqAmount->value(), ui->reqMessage->text());
ReceiveRequestDialog *dialog = new ReceiveRequestDialog(this);
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 385f98565c..3687cca87b 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_RECEIVECOINSDIALOG_H
#define BITCOIN_QT_RECEIVECOINSDIALOG_H
-#include "guiutil.h"
+#include <qt/guiutil.h>
#include <QDialog>
#include <QHeaderView>
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index 4aa6375d8a..c69fea1c93 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "receiverequestdialog.h"
-#include "ui_receiverequestdialog.h"
+#include <qt/receiverequestdialog.h>
+#include <qt/forms/ui_receiverequestdialog.h>
-#include "bitcoinunits.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "walletmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/walletmodel.h>
#include <QClipboard>
#include <QDrag>
@@ -22,7 +22,7 @@
#endif
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h" /* for USE_QRCODE */
+#include <config/bitcoin-config.h> /* for USE_QRCODE */
#endif
#ifdef USE_QRCODE
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 1a9b165237..23b81135e2 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_RECEIVEREQUESTDIALOG_H
#define BITCOIN_QT_RECEIVEREQUESTDIALOG_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QDialog>
#include <QImage>
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 1c4f7aca86..4d6e401d0d 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "recentrequeststablemodel.h"
+#include <qt/recentrequeststablemodel.h>
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
-#include "clientversion.h"
-#include "streams.h"
+#include <clientversion.h>
+#include <streams.h>
RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel *parent) :
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index 0c02968f92..c88b8c4426 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_RECENTREQUESTSTABLEMODEL_H
#define BITCOIN_QT_RECENTREQUESTSTABLEMODEL_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QAbstractTableModel>
#include <QStringList>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index d895fc1663..6687d62baa 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -3,21 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "rpcconsole.h"
-#include "ui_debugwindow.h"
+#include <qt/rpcconsole.h>
+#include <qt/forms/ui_debugwindow.h>
-#include "bantablemodel.h"
-#include "clientmodel.h"
-#include "guiutil.h"
-#include "platformstyle.h"
-#include "chainparams.h"
-#include "netbase.h"
-#include "rpc/server.h"
-#include "rpc/client.h"
-#include "util.h"
+#include <qt/bantablemodel.h>
+#include <qt/clientmodel.h>
+#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
+#include <chainparams.h>
+#include <netbase.h>
+#include <rpc/server.h>
+#include <rpc/client.h>
+#include <util.h>
#include <openssl/crypto.h>
@@ -125,7 +125,7 @@ public:
};
-#include "rpcconsole.moc"
+#include <qt/rpcconsole.moc>
/**
* Split shell command line into a list of arguments and optionally execute the command(s).
@@ -935,18 +935,6 @@ void RPCConsole::on_sldGraphRange_valueChanged(int value)
setTrafficGraphRange(mins);
}
-QString RPCConsole::FormatBytes(quint64 bytes)
-{
- if(bytes < 1024)
- return QString(tr("%1 B")).arg(bytes);
- if(bytes < 1024 * 1024)
- return QString(tr("%1 KB")).arg(bytes / 1024);
- if(bytes < 1024 * 1024 * 1024)
- return QString(tr("%1 MB")).arg(bytes / 1024 / 1024);
-
- return QString(tr("%1 GB")).arg(bytes / 1024 / 1024 / 1024);
-}
-
void RPCConsole::setTrafficGraphRange(int mins)
{
ui->trafficGraph->setGraphRangeMins(mins);
@@ -955,8 +943,8 @@ void RPCConsole::setTrafficGraphRange(int mins)
void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
{
- ui->lblBytesIn->setText(FormatBytes(totalBytesIn));
- ui->lblBytesOut->setText(FormatBytes(totalBytesOut));
+ ui->lblBytesIn->setText(GUIUtil::formatBytes(totalBytesIn));
+ ui->lblBytesOut->setText(GUIUtil::formatBytes(totalBytesOut));
}
void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelection &deselected)
@@ -1050,8 +1038,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
ui->peerLastSend->setText(stats->nodeStats.nLastSend ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastSend) : tr("never"));
ui->peerLastRecv->setText(stats->nodeStats.nLastRecv ? GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nLastRecv) : tr("never"));
- ui->peerBytesSent->setText(FormatBytes(stats->nodeStats.nSendBytes));
- ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
+ ui->peerBytesSent->setText(GUIUtil::formatBytes(stats->nodeStats.nSendBytes));
+ ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes));
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetSystemTimeInSeconds() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index da06818f87..5960410cdd 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -5,10 +5,10 @@
#ifndef BITCOIN_QT_RPCCONSOLE_H
#define BITCOIN_QT_RPCCONSOLE_H
-#include "guiutil.h"
-#include "peertablemodel.h"
+#include <qt/guiutil.h>
+#include <qt/peertablemodel.h>
-#include "net.h"
+#include <net.h>
#include <QWidget>
#include <QCompleter>
@@ -123,7 +123,6 @@ Q_SIGNALS:
void cmdRequest(const QString &command);
private:
- static QString FormatBytes(quint64 bytes);
void startExecutor();
void setTrafficGraphRange(int mins);
/** show detailed information on ui about selected node */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 6309070fef..036b6ebcc0 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -2,27 +2,27 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sendcoinsdialog.h"
-#include "ui_sendcoinsdialog.h"
-
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "clientmodel.h"
-#include "coincontroldialog.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "sendcoinsentry.h"
-#include "walletmodel.h"
-
-#include "base58.h"
-#include "chainparams.h"
-#include "wallet/coincontrol.h"
-#include "validation.h" // mempool and minRelayTxFee
-#include "ui_interface.h"
-#include "txmempool.h"
-#include "policy/fees.h"
-#include "wallet/fees.h"
+#include <qt/sendcoinsdialog.h>
+#include <qt/forms/ui_sendcoinsdialog.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/clientmodel.h>
+#include <qt/coincontroldialog.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/sendcoinsentry.h>
+#include <qt/walletmodel.h>
+
+#include <base58.h>
+#include <chainparams.h>
+#include <wallet/coincontrol.h>
+#include <validation.h> // mempool and minRelayTxFee
+#include <ui_interface.h>
+#include <txmempool.h>
+#include <policy/fees.h>
+#include <wallet/fees.h>
#include <QFontMetrics>
#include <QMessageBox>
@@ -402,6 +402,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
entry->setModel(model);
ui->entries->addWidget(entry);
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
+ connect(entry, SIGNAL(useAvailableBalance(SendCoinsEntry*)), this, SLOT(useAvailableBalance(SendCoinsEntry*)));
connect(entry, SIGNAL(payAmountChanged()), this, SLOT(coinControlUpdateLabels()));
connect(entry, SIGNAL(subtractFeeFromAmountChanged()), this, SLOT(coinControlUpdateLabels()));
@@ -599,6 +600,31 @@ void SendCoinsDialog::on_buttonMinimizeFee_clicked()
minimizeFeeSection(true);
}
+void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
+{
+ // Get CCoinControl instance if CoinControl is enabled or create a new one.
+ CCoinControl coin_control;
+ if (model->getOptionsModel()->getCoinControlFeatures()) {
+ coin_control = *CoinControlDialog::coinControl;
+ }
+
+ // Calculate available amount to send.
+ CAmount amount = model->getBalance(&coin_control);
+ for (int i = 0; i < ui->entries->count(); ++i) {
+ SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
+ if (e && !e->isHidden() && e != entry) {
+ amount -= e->getValue().amount;
+ }
+ }
+
+ if (amount > 0) {
+ entry->checkSubtractFeeFromAmount();
+ entry->setAmount(amount);
+ } else {
+ entry->setAmount(0);
+ }
+}
+
void SendCoinsDialog::setMinimumFee()
{
ui->customFee->setValue(GetRequiredFee(1000));
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 70b4aa5a03..300116fd9f 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_SENDCOINSDIALOG_H
#define BITCOIN_QT_SENDCOINSDIALOG_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QDialog>
#include <QMessageBox>
@@ -76,6 +76,7 @@ private Q_SLOTS:
void on_buttonChooseFee_clicked();
void on_buttonMinimizeFee_clicked();
void removeEntry(SendCoinsEntry* entry);
+ void useAvailableBalance(SendCoinsEntry* entry);
void updateDisplayUnit();
void coinControlFeatureChanged(bool);
void coinControlButtonClicked();
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index bb0f47b21c..20e39bdeba 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -2,15 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sendcoinsentry.h"
-#include "ui_sendcoinsentry.h"
+#include <qt/sendcoinsentry.h>
+#include <qt/forms/ui_sendcoinsentry.h>
-#include "addressbookpage.h"
-#include "addresstablemodel.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "walletmodel.h"
+#include <qt/addressbookpage.h>
+#include <qt/addresstablemodel.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/walletmodel.h>
#include <QApplication>
#include <QClipboard>
@@ -48,6 +48,7 @@ SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *par
connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));
+ connect(ui->useAvailableBalanceButton, SIGNAL(clicked()), this, SLOT(useAvailableBalanceClicked()));
}
SendCoinsEntry::~SendCoinsEntry()
@@ -112,11 +113,21 @@ void SendCoinsEntry::clear()
updateDisplayUnit();
}
+void SendCoinsEntry::checkSubtractFeeFromAmount()
+{
+ ui->checkboxSubtractFeeFromAmount->setChecked(true);
+}
+
void SendCoinsEntry::deleteClicked()
{
Q_EMIT removeEntry(this);
}
+void SendCoinsEntry::useAvailableBalanceClicked()
+{
+ Q_EMIT useAvailableBalance(this);
+}
+
bool SendCoinsEntry::validate()
{
if (!model)
@@ -228,6 +239,11 @@ void SendCoinsEntry::setAddress(const QString &address)
ui->payAmount->setFocus();
}
+void SendCoinsEntry::setAmount(const CAmount &amount)
+{
+ ui->payAmount->setValue(amount);
+}
+
bool SendCoinsEntry::isClear()
{
return ui->payTo->text().isEmpty() && ui->payTo_is->text().isEmpty() && ui->payTo_s->text().isEmpty();
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index a8be670c2a..b470a0d72e 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_SENDCOINSENTRY_H
#define BITCOIN_QT_SENDCOINSENTRY_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QStackedWidget>
@@ -38,6 +38,7 @@ public:
void setValue(const SendCoinsRecipient &value);
void setAddress(const QString &address);
+ void setAmount(const CAmount &amount);
/** Set up the tab chain manually, as Qt messes up the tab chain by default in some cases
* (issue https://bugreports.qt-project.org/browse/QTBUG-10907).
@@ -48,14 +49,17 @@ public:
public Q_SLOTS:
void clear();
+ void checkSubtractFeeFromAmount();
Q_SIGNALS:
void removeEntry(SendCoinsEntry *entry);
+ void useAvailableBalance(SendCoinsEntry* entry);
void payAmountChanged();
void subtractFeeFromAmountChanged();
private Q_SLOTS:
void deleteClicked();
+ void useAvailableBalanceClicked();
void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked();
void on_pasteButton_clicked();
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index cba9d4da38..4cd0c76b16 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "signverifymessagedialog.h"
-#include "ui_signverifymessagedialog.h"
-
-#include "addressbookpage.h"
-#include "guiutil.h"
-#include "platformstyle.h"
-#include "walletmodel.h"
-
-#include "base58.h"
-#include "init.h"
-#include "validation.h" // For strMessageMagic
-#include "wallet/wallet.h"
+#include <qt/signverifymessagedialog.h>
+#include <qt/forms/ui_signverifymessagedialog.h>
+
+#include <qt/addressbookpage.h>
+#include <qt/guiutil.h>
+#include <qt/platformstyle.h>
+#include <qt/walletmodel.h>
+
+#include <base58.h>
+#include <init.h>
+#include <validation.h> // For strMessageMagic
+#include <wallet/wallet.h>
#include <string>
#include <vector>
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index a1fbba963c..5aa1de5553 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -3,21 +3,21 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "splashscreen.h"
+#include <qt/splashscreen.h>
-#include "networkstyle.h"
+#include <qt/networkstyle.h>
-#include "clientversion.h"
-#include "init.h"
-#include "util.h"
-#include "ui_interface.h"
-#include "version.h"
+#include <clientversion.h>
+#include <init.h>
+#include <util.h>
+#include <ui_interface.h>
+#include <version.h>
#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
#endif
#include <QApplication>
diff --git a/src/qt/test/compattests.cpp b/src/qt/test/compattests.cpp
index 2a7284b5b2..7a4388e940 100644
--- a/src/qt/test/compattests.cpp
+++ b/src/qt/test/compattests.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "paymentrequestplus.h" // this includes protobuf's port.h which defines its own bswap macos
+#include <qt/paymentrequestplus.h> // this includes protobuf's port.h which defines its own bswap macos
-#include "compattests.h"
+#include <qt/test/compattests.h>
-#include "compat/byteswap.h"
+#include <compat/byteswap.h>
void CompatTests::bswapTests()
{
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index 273bd10487..1864604372 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "paymentservertests.h"
+#include <qt/test/paymentservertests.h>
-#include "optionsmodel.h"
-#include "paymentrequestdata.h"
+#include <qt/optionsmodel.h>
+#include <qt/test/paymentrequestdata.h>
-#include "amount.h"
-#include "random.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <amount.h>
+#include <random.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
index faf167f2c6..6d84c38287 100644
--- a/src/qt/test/paymentservertests.h
+++ b/src/qt/test/paymentservertests.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TEST_PAYMENTSERVERTESTS_H
#define BITCOIN_QT_TEST_PAYMENTSERVERTESTS_H
-#include "../paymentserver.h"
+#include <qt/paymentserver.h>
#include <QObject>
#include <QTest>
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index 70fdd4bf58..0596ccf90e 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpcnestedtests.h"
-
-#include "chainparams.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "validation.h"
-#include "rpc/register.h"
-#include "rpc/server.h"
-#include "rpcconsole.h"
-#include "test/test_bitcoin.h"
-#include "univalue.h"
-#include "util.h"
+#include <qt/test/rpcnestedtests.h>
+
+#include <chainparams.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <validation.h>
+#include <rpc/register.h>
+#include <rpc/server.h>
+#include <qt/rpcconsole.h>
+#include <test/test_bitcoin.h>
+#include <univalue.h>
+#include <util.h>
#include <QDir>
#include <QtGlobal>
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
index 9ad409019f..04a9d124aa 100644
--- a/src/qt/test/rpcnestedtests.h
+++ b/src/qt/test/rpcnestedtests.h
@@ -8,8 +8,8 @@
#include <QObject>
#include <QTest>
-#include "txdb.h"
-#include "txmempool.h"
+#include <txdb.h>
+#include <txmempool.h>
class RPCNestedTests : public QObject
{
@@ -17,9 +17,6 @@ class RPCNestedTests : public QObject
private Q_SLOTS:
void rpcNestedTests();
-
-private:
- CCoinsViewDB *pcoinsdbview;
};
#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 4c04e67ccc..2e11b4f4d6 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -3,18 +3,18 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "chainparams.h"
-#include "rpcnestedtests.h"
-#include "util.h"
-#include "uritests.h"
-#include "compattests.h"
+#include <chainparams.h>
+#include <qt/test/rpcnestedtests.h>
+#include <util.h>
+#include <qt/test/uritests.h>
+#include <qt/test/compattests.h>
#ifdef ENABLE_WALLET
-#include "paymentservertests.h"
-#include "wallettests.h"
+#include <qt/test/paymentservertests.h>
+#include <qt/test/wallettests.h>
#endif
#include <QApplication>
diff --git a/src/qt/test/uritests.cpp b/src/qt/test/uritests.cpp
index 8b53c0d5c7..e47aa8b546 100644
--- a/src/qt/test/uritests.cpp
+++ b/src/qt/test/uritests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "uritests.h"
+#include <qt/test/uritests.h>
-#include "guiutil.h"
-#include "walletmodel.h"
+#include <qt/guiutil.h>
+#include <qt/walletmodel.h>
#include <QUrl>
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index eeae58bd05..4b7c3bd726 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,22 +1,22 @@
-#include "wallettests.h"
+#include <qt/test/wallettests.h>
-#include "qt/bitcoinamountfield.h"
-#include "qt/callback.h"
-#include "qt/optionsmodel.h"
-#include "qt/platformstyle.h"
-#include "qt/qvalidatedlineedit.h"
-#include "qt/sendcoinsdialog.h"
-#include "qt/sendcoinsentry.h"
-#include "qt/transactiontablemodel.h"
-#include "qt/transactionview.h"
-#include "qt/walletmodel.h"
-#include "test/test_bitcoin.h"
-#include "validation.h"
-#include "wallet/wallet.h"
-#include "qt/overviewpage.h"
-#include "qt/receivecoinsdialog.h"
-#include "qt/recentrequeststablemodel.h"
-#include "qt/receiverequestdialog.h"
+#include <qt/bitcoinamountfield.h>
+#include <qt/callback.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/qvalidatedlineedit.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/sendcoinsentry.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/transactionview.h>
+#include <qt/walletmodel.h>
+#include <test/test_bitcoin.h>
+#include <validation.h>
+#include <wallet/wallet.h>
+#include <qt/overviewpage.h>
+#include <qt/receivecoinsdialog.h>
+#include <qt/recentrequeststablemodel.h>
+#include <qt/receiverequestdialog.h>
#include <QAbstractButton>
#include <QAction>
@@ -164,7 +164,10 @@ void TestGUI()
wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
}
- wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
+ {
+ LOCK(cs_main);
+ wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, true);
+ }
wallet.SetBroadcastTransactions(true);
// Create widgets for sending coins and listing transactions.
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 5bb863451f..b5e4ccb406 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "trafficgraphwidget.h"
-#include "clientmodel.h"
+#include <qt/trafficgraphwidget.h>
+#include <qt/clientmodel.h>
#include <QPainter>
#include <QColor>
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 74f5c774a0..3f245e6c33 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -2,21 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactiondesc.h"
-
-#include "bitcoinunits.h"
-#include "guiutil.h"
-#include "paymentserver.h"
-#include "transactionrecord.h"
-
-#include "base58.h"
-#include "consensus/consensus.h"
-#include "validation.h"
-#include "script/script.h"
-#include "timedata.h"
-#include "util.h"
-#include "wallet/db.h"
-#include "wallet/wallet.h"
+#include <qt/transactiondesc.h>
+
+#include <qt/bitcoinunits.h>
+#include <qt/guiutil.h>
+#include <qt/paymentserver.h>
+#include <qt/transactionrecord.h>
+
+#include <base58.h>
+#include <consensus/consensus.h>
+#include <validation.h>
+#include <script/script.h>
+#include <timedata.h>
+#include <util.h>
+#include <wallet/db.h>
+#include <wallet/wallet.h>
#include <stdint.h>
#include <string>
@@ -24,7 +24,7 @@
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
AssertLockHeld(cs_main);
- if (!CheckFinalTx(wtx))
+ if (!CheckFinalTx(*wtx.tx))
{
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - chainActive.Height());
diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp
index 65f163deb2..74d7a8f525 100644
--- a/src/qt/transactiondescdialog.cpp
+++ b/src/qt/transactiondescdialog.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactiondescdialog.h"
-#include "ui_transactiondescdialog.h"
+#include <qt/transactiondescdialog.h>
+#include <qt/forms/ui_transactiondescdialog.h>
-#include "transactiontablemodel.h"
+#include <qt/transactiontablemodel.h>
#include <QModelIndex>
diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp
index 44e4ef8238..15859bf36d 100644
--- a/src/qt/transactionfilterproxy.cpp
+++ b/src/qt/transactionfilterproxy.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactionfilterproxy.h"
+#include <qt/transactionfilterproxy.h>
-#include "transactiontablemodel.h"
-#include "transactionrecord.h"
+#include <qt/transactiontablemodel.h>
+#include <qt/transactionrecord.h>
#include <cstdlib>
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
index 7db02cd61f..4bdd9ea6c7 100644
--- a/src/qt/transactionfilterproxy.h
+++ b/src/qt/transactionfilterproxy.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TRANSACTIONFILTERPROXY_H
#define BITCOIN_QT_TRANSACTIONFILTERPROXY_H
-#include "amount.h"
+#include <amount.h>
#include <QDateTime>
#include <QSortFilterProxyModel>
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index d40ffd22cd..e3e8377cb9 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactionrecord.h"
+#include <qt/transactionrecord.h>
-#include "base58.h"
-#include "consensus/consensus.h"
-#include "validation.h"
-#include "timedata.h"
-#include "wallet/wallet.h"
+#include <base58.h>
+#include <consensus/consensus.h>
+#include <validation.h>
+#include <timedata.h>
+#include <wallet/wallet.h>
#include <stdint.h>
@@ -182,7 +182,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = chainActive.Height();
- if (!CheckFinalTx(wtx))
+ if (!CheckFinalTx(*wtx.tx))
{
if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD)
{
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index a26e676142..ee85acf4ac 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -5,8 +5,8 @@
#ifndef BITCOIN_QT_TRANSACTIONRECORD_H
#define BITCOIN_QT_TRANSACTIONRECORD_H
-#include "amount.h"
-#include "uint256.h"
+#include <amount.h>
+#include <uint256.h>
#include <QList>
#include <QString>
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 59cef555b1..cc0dc5ef48 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactiontablemodel.h"
-
-#include "addresstablemodel.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "transactiondesc.h"
-#include "transactionrecord.h"
-#include "walletmodel.h"
-
-#include "core_io.h"
-#include "validation.h"
-#include "sync.h"
-#include "uint256.h"
-#include "util.h"
-#include "wallet/wallet.h"
+#include <qt/transactiontablemodel.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/transactiondesc.h>
+#include <qt/transactionrecord.h>
+#include <qt/walletmodel.h>
+
+#include <core_io.h>
+#include <validation.h>
+#include <sync.h>
+#include <uint256.h>
+#include <util.h>
+#include <wallet/wallet.h>
#include <QColor>
#include <QDateTime>
@@ -230,7 +230,7 @@ public:
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
if(mi != wallet->mapWallet.end())
{
- std::string strHex = EncodeHexTx(static_cast<CTransaction>(mi->second));
+ std::string strHex = EncodeHexTx(*mi->second.tx);
return QString::fromStdString(strHex);
}
return QString();
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index b1f81498b2..a769707163 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TRANSACTIONTABLEMODEL_H
#define BITCOIN_QT_TRANSACTIONTABLEMODEL_H
-#include "bitcoinunits.h"
+#include <qt/bitcoinunits.h>
#include <QAbstractTableModel>
#include <QStringList>
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 39dfdb587c..92e8e91600 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "transactionview.h"
-
-#include "addresstablemodel.h"
-#include "bitcoinunits.h"
-#include "csvmodelwriter.h"
-#include "editaddressdialog.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "platformstyle.h"
-#include "sendcoinsdialog.h"
-#include "transactiondescdialog.h"
-#include "transactionfilterproxy.h"
-#include "transactionrecord.h"
-#include "transactiontablemodel.h"
-#include "walletmodel.h"
-
-#include "ui_interface.h"
+#include <qt/transactionview.h>
+
+#include <qt/addresstablemodel.h>
+#include <qt/bitcoinunits.h>
+#include <qt/csvmodelwriter.h>
+#include <qt/editaddressdialog.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/platformstyle.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/transactiondescdialog.h>
+#include <qt/transactionfilterproxy.h>
+#include <qt/transactionrecord.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/walletmodel.h>
+
+#include <ui_interface.h>
#include <QComboBox>
#include <QDateTimeEdit>
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 5b4cfd4a88..5b28b34723 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_TRANSACTIONVIEW_H
#define BITCOIN_QT_TRANSACTIONVIEW_H
-#include "guiutil.h"
+#include <qt/guiutil.h>
#include <QWidget>
#include <QKeyEvent>
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 5d8c23d13c..6d5a2f3101 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -3,23 +3,23 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "utilitydialog.h"
+#include <qt/utilitydialog.h>
-#include "ui_helpmessagedialog.h"
+#include <qt/forms/ui_helpmessagedialog.h>
-#include "bitcoingui.h"
-#include "clientmodel.h"
-#include "guiconstants.h"
-#include "intro.h"
-#include "paymentrequestplus.h"
-#include "guiutil.h"
+#include <qt/bitcoingui.h>
+#include <qt/clientmodel.h>
+#include <qt/guiconstants.h>
+#include <qt/intro.h>
+#include <qt/paymentrequestplus.h>
+#include <qt/guiutil.h>
-#include "clientversion.h"
-#include "init.h"
-#include "util.h"
+#include <clientversion.h>
+#include <init.h>
+#include <util.h>
#include <stdio.h>
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 714a594318..573b3f1412 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletframe.h"
+#include <qt/walletframe.h>
-#include "bitcoingui.h"
-#include "walletview.h"
+#include <qt/bitcoingui.h>
+#include <qt/walletview.h>
#include <cassert>
#include <cstdio>
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 53b1c2967c..a38e233608 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -2,32 +2,32 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletmodel.h"
-
-#include "addresstablemodel.h"
-#include "consensus/validation.h"
-#include "guiconstants.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "paymentserver.h"
-#include "recentrequeststablemodel.h"
-#include "sendcoinsdialog.h"
-#include "transactiontablemodel.h"
-
-#include "base58.h"
-#include "chain.h"
-#include "keystore.h"
-#include "validation.h"
-#include "net.h" // for g_connman
-#include "policy/fees.h"
-#include "policy/rbf.h"
-#include "sync.h"
-#include "ui_interface.h"
-#include "util.h" // for GetBoolArg
-#include "wallet/coincontrol.h"
-#include "wallet/feebumper.h"
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h" // for BackupWallet
+#include <qt/walletmodel.h>
+
+#include <qt/addresstablemodel.h>
+#include <consensus/validation.h>
+#include <qt/guiconstants.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/paymentserver.h>
+#include <qt/recentrequeststablemodel.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/transactiontablemodel.h>
+
+#include <base58.h>
+#include <chain.h>
+#include <keystore.h>
+#include <validation.h>
+#include <net.h> // for g_connman
+#include <policy/fees.h>
+#include <policy/rbf.h>
+#include <sync.h>
+#include <ui_interface.h>
+#include <util.h> // for GetBoolArg
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h> // for BackupWallet
#include <stdint.h>
@@ -659,45 +659,39 @@ bool WalletModel::abandonTransaction(uint256 hash) const
bool WalletModel::transactionCanBeBumped(uint256 hash) const
{
- LOCK2(cs_main, wallet->cs_wallet);
- const CWalletTx *wtx = wallet->GetWalletTx(hash);
- return wtx && SignalsOptInRBF(*wtx) && !wtx->mapValue.count("replaced_by_txid");
+ return feebumper::TransactionCanBeBumped(wallet, hash);
}
bool WalletModel::bumpFee(uint256 hash)
{
- std::unique_ptr<CFeeBumper> feeBump;
- {
- CCoinControl coin_control;
- coin_control.signalRbf = true;
- LOCK2(cs_main, wallet->cs_wallet);
- feeBump.reset(new CFeeBumper(wallet, hash, coin_control, 0));
- }
- if (feeBump->getResult() != BumpFeeResult::OK)
- {
+ CCoinControl coin_control;
+ coin_control.signalRbf = true;
+ std::vector<std::string> errors;
+ CAmount old_fee;
+ CAmount new_fee;
+ CMutableTransaction mtx;
+ if (feebumper::CreateTransaction(wallet, hash, coin_control, 0 /* totalFee */, errors, old_fee, new_fee, mtx) != feebumper::Result::OK) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Increasing transaction fee failed") + "<br />(" +
- (feeBump->getErrors().size() ? QString::fromStdString(feeBump->getErrors()[0]) : "") +")");
+ (errors.size() ? QString::fromStdString(errors[0]) : "") +")");
return false;
}
// allow a user based fee verification
QString questionString = tr("Do you want to increase the fee?");
questionString.append("<br />");
- CAmount oldFee = feeBump->getOldFee();
- CAmount newFee = feeBump->getNewFee();
questionString.append("<table style=\"text-align: left;\">");
questionString.append("<tr><td>");
questionString.append(tr("Current fee:"));
questionString.append("</td><td>");
- questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), oldFee));
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), old_fee));
questionString.append("</td></tr><tr><td>");
questionString.append(tr("Increase:"));
questionString.append("</td><td>");
- questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee - oldFee));
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee - old_fee));
questionString.append("</td></tr><tr><td>");
questionString.append(tr("New fee:"));
questionString.append("</td><td>");
- questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), newFee));
+ questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee));
questionString.append("</td></tr></table>");
SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
confirmationDialog.exec();
@@ -715,23 +709,15 @@ bool WalletModel::bumpFee(uint256 hash)
}
// sign bumped transaction
- bool res = false;
- {
- LOCK2(cs_main, wallet->cs_wallet);
- res = feeBump->signTransaction(wallet);
- }
- if (!res) {
+ if (!feebumper::SignTransaction(wallet, mtx)) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Can't sign transaction."));
return false;
}
// commit the bumped transaction
- {
- LOCK2(cs_main, wallet->cs_wallet);
- res = feeBump->commit(wallet);
- }
- if(!res) {
+ uint256 txid;
+ if (feebumper::CommitTransaction(wallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
QMessageBox::critical(0, tr("Fee bump error"), tr("Could not commit transaction") + "<br />(" +
- QString::fromStdString(feeBump->getErrors()[0])+")");
+ QString::fromStdString(errors[0])+")");
return false;
}
return true;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 05733f8272..028146c187 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -5,10 +5,10 @@
#ifndef BITCOIN_QT_WALLETMODEL_H
#define BITCOIN_QT_WALLETMODEL_H
-#include "paymentrequestplus.h"
-#include "walletmodeltransaction.h"
+#include <qt/paymentrequestplus.h>
+#include <qt/walletmodeltransaction.h>
-#include "support/allocators/secure.h"
+#include <support/allocators/secure.h>
#include <map>
#include <vector>
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index eae2c27f8a..3bf3e295ff 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletmodeltransaction.h"
+#include <qt/walletmodeltransaction.h>
-#include "policy/policy.h"
-#include "wallet/wallet.h"
+#include <policy/policy.h>
+#include <wallet/wallet.h>
WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
recipients(_recipients),
@@ -34,7 +34,7 @@ CWalletTx *WalletModelTransaction::getTransaction() const
unsigned int WalletModelTransaction::getTransactionSize()
{
- return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction));
+ return (!walletTransaction ? 0 : ::GetVirtualTransactionSize(*walletTransaction->tx));
}
CAmount WalletModelTransaction::getTransactionFee() const
diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h
index d7ecd7aa8c..d75875eefd 100644
--- a/src/qt/walletmodeltransaction.h
+++ b/src/qt/walletmodeltransaction.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_WALLETMODELTRANSACTION_H
#define BITCOIN_QT_WALLETMODELTRANSACTION_H
-#include "walletmodel.h"
+#include <qt/walletmodel.h>
#include <QObject>
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 971f5e0e1a..a589fad9bd 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "walletview.h"
-
-#include "addressbookpage.h"
-#include "askpassphrasedialog.h"
-#include "bitcoingui.h"
-#include "clientmodel.h"
-#include "guiutil.h"
-#include "optionsmodel.h"
-#include "overviewpage.h"
-#include "platformstyle.h"
-#include "receivecoinsdialog.h"
-#include "sendcoinsdialog.h"
-#include "signverifymessagedialog.h"
-#include "transactiontablemodel.h"
-#include "transactionview.h"
-#include "walletmodel.h"
-
-#include "ui_interface.h"
+#include <qt/walletview.h>
+
+#include <qt/addressbookpage.h>
+#include <qt/askpassphrasedialog.h>
+#include <qt/bitcoingui.h>
+#include <qt/clientmodel.h>
+#include <qt/guiutil.h>
+#include <qt/optionsmodel.h>
+#include <qt/overviewpage.h>
+#include <qt/platformstyle.h>
+#include <qt/receivecoinsdialog.h>
+#include <qt/sendcoinsdialog.h>
+#include <qt/signverifymessagedialog.h>
+#include <qt/transactiontablemodel.h>
+#include <qt/transactionview.h>
+#include <qt/walletmodel.h>
+
+#include <ui_interface.h>
#include <QAction>
#include <QActionGroup>
@@ -122,8 +122,8 @@ void WalletView::setWalletModel(WalletModel *_walletModel)
overviewPage->setWalletModel(_walletModel);
receiveCoinsPage->setModel(_walletModel);
sendCoinsPage->setModel(_walletModel);
- usedReceivingAddressesPage->setModel(_walletModel->getAddressTableModel());
- usedSendingAddressesPage->setModel(_walletModel->getAddressTableModel());
+ usedReceivingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
+ usedSendingAddressesPage->setModel(_walletModel ? _walletModel->getAddressTableModel() : nullptr);
if (_walletModel)
{
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index c1f8422f0c..4c90874135 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_WALLETVIEW_H
#define BITCOIN_QT_WALLETVIEW_H
-#include "amount.h"
+#include <amount.h>
#include <QStackedWidget>
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index d78d9a2358..aa6c273431 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "winshutdownmonitor.h"
+#include <qt/winshutdownmonitor.h>
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
-#include "init.h"
-#include "util.h"
+#include <init.h>
+#include <util.h>
#include <windows.h>
diff --git a/src/random.cpp b/src/random.cpp
index 7e0e94439e..3075a77182 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
+#include <random.h>
-#include "crypto/sha512.h"
-#include "support/cleanse.h"
+#include <crypto/sha512.h>
+#include <support/cleanse.h>
#ifdef WIN32
-#include "compat.h" // for Windows API
+#include <compat.h> // for Windows API
#include <wincrypt.h>
#endif
-#include "util.h" // for LogPrint()
-#include "utilstrencodings.h" // for GetTime()
+#include <util.h> // for LogPrint()
+#include <utilstrencodings.h> // for GetTime()
#include <stdlib.h>
#include <limits>
diff --git a/src/random.h b/src/random.h
index c60ab36179..9309917689 100644
--- a/src/random.h
+++ b/src/random.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_RANDOM_H
#define BITCOIN_RANDOM_H
-#include "crypto/chacha20.h"
-#include "crypto/common.h"
-#include "uint256.h"
+#include <crypto/chacha20.h>
+#include <crypto/common.h>
+#include <uint256.h>
#include <stdint.h>
diff --git a/src/rest.cpp b/src/rest.cpp
index 0b2c843d5f..86ee7804a3 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -3,20 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "chainparams.h"
-#include "core_io.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "validation.h"
-#include "httpserver.h"
-#include "rpc/blockchain.h"
-#include "rpc/server.h"
-#include "streams.h"
-#include "sync.h"
-#include "txmempool.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <core_io.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <validation.h>
+#include <httpserver.h>
+#include <rpc/blockchain.h>
+#include <rpc/server.h>
+#include <streams.h>
+#include <sync.h>
+#include <txmempool.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <boost/algorithm/string.hpp>
@@ -178,8 +178,11 @@ static bool rest_headers(HTTPRequest* req,
}
case RF_JSON: {
UniValue jsonHeaders(UniValue::VARR);
- for (const CBlockIndex *pindex : headers) {
- jsonHeaders.push_back(blockheaderToJSON(pindex));
+ {
+ LOCK(cs_main);
+ for (const CBlockIndex *pindex : headers) {
+ jsonHeaders.push_back(blockheaderToJSON(pindex));
+ }
}
std::string strJSON = jsonHeaders.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -239,7 +242,11 @@ static bool rest_block(HTTPRequest* req,
}
case RF_JSON: {
- UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
+ UniValue objBlock;
+ {
+ LOCK(cs_main);
+ objBlock = blockToJSON(block, pblockindex, showTxDetails);
+ }
std::string strJSON = objBlock.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
@@ -409,10 +416,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
if (uriParts.size() > 0)
{
-
//inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)
- if (uriParts.size() > 0 && uriParts[0] == "checkmempool")
- fCheckMemPool = true;
+ if (uriParts[0] == "checkmempool") fCheckMemPool = true;
for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
{
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 68af376f35..601965d4c4 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -3,28 +3,28 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/blockchain.h"
-
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "coins.h"
-#include "consensus/validation.h"
-#include "validation.h"
-#include "core_io.h"
-#include "policy/feerate.h"
-#include "policy/policy.h"
-#include "primitives/transaction.h"
-#include "rpc/server.h"
-#include "streams.h"
-#include "sync.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "hash.h"
-#include "warnings.h"
+#include <rpc/blockchain.h>
+
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <coins.h>
+#include <consensus/validation.h>
+#include <validation.h>
+#include <core_io.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <primitives/transaction.h>
+#include <rpc/server.h>
+#include <streams.h>
+#include <sync.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <hash.h>
+#include <warnings.h>
#include <stdint.h>
@@ -78,6 +78,7 @@ double GetDifficulty(const CBlockIndex* blockindex)
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
+ AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
int confirmations = -1;
@@ -106,6 +107,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex)
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails)
{
+ AssertLockHeld(cs_main);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
int confirmations = -1;
@@ -926,7 +928,7 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request)
CCoinsStats stats;
FlushStateToDisk();
- if (GetUTXOStats(pcoinsdbview, stats)) {
+ if (GetUTXOStats(pcoinsdbview.get(), stats)) {
ret.push_back(Pair("height", (int64_t)stats.nHeight));
ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
@@ -994,7 +996,7 @@ UniValue gettxout(const JSONRPCRequest& request)
Coin coin;
if (fMempool) {
LOCK(mempool.cs);
- CCoinsViewMemPool view(pcoinsTip, mempool);
+ CCoinsViewMemPool view(pcoinsTip.get(), mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
return NullUniValue;
}
@@ -1046,7 +1048,7 @@ UniValue verifychain(const JSONRPCRequest& request)
if (!request.params[1].isNull())
nCheckDepth = request.params[1].get_int();
- return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
+ return CVerifyDB().VerifyDB(Params(), pcoinsTip.get(), nCheckLevel, nCheckDepth);
}
/** Implementation of IsSuperMajority with better feedback */
@@ -1128,45 +1130,46 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
"Returns an object containing various state info regarding blockchain processing.\n"
"\nResult:\n"
"{\n"
- " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
- " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
- " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
- " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
- " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
- " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n"
+ " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
+ " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
+ " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
+ " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
+ " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
+ " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
- " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
- " \"size_on_disk\": xxxxxx, (numeric) the estimated size of the block and undo files on disk\n"
- " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
- " \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled)\n"
- " \"automatic_pruning\": xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\n"
+ " \"initialblockdownload\": xxxx, (bool) (debug information) estimate of whether this node is in Initial Block Download mode.\n"
+ " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
+ " \"size_on_disk\": xxxxxx, (numeric) the estimated size of the block and undo files on disk\n"
+ " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
+ " \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled)\n"
+ " \"automatic_pruning\": xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\n"
" \"prune_target_size\": xxxxxx, (numeric) the target size used by pruning (only present if automatic pruning is enabled)\n"
- " \"softforks\": [ (array) status of softforks in progress\n"
+ " \"softforks\": [ (array) status of softforks in progress\n"
" {\n"
- " \"id\": \"xxxx\", (string) name of softfork\n"
- " \"version\": xx, (numeric) block version\n"
- " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
- " \"status\": xx, (boolean) true if threshold reached\n"
+ " \"id\": \"xxxx\", (string) name of softfork\n"
+ " \"version\": xx, (numeric) block version\n"
+ " \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
+ " \"status\": xx, (boolean) true if threshold reached\n"
" },\n"
" }, ...\n"
" ],\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\", \"locked_in\", \"active\", \"failed\"\n"
- " \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\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"
- " \"since\": xx, (numeric) height of the first block to which the status applies\n"
- " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
- " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
- " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
- " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
- " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
- " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \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\", \"locked_in\", \"active\", \"failed\"\n"
+ " \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\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"
+ " \"since\": xx, (numeric) height of the first block to which the status applies\n"
+ " \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
+ " \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
+ " \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
+ " \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
+ " \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
+ " \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
" }\n"
" }\n"
" }\n"
- " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
+ " \"warnings\" : \"...\", (string) any network and blockchain warnings.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -1183,6 +1186,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast()));
obj.push_back(Pair("verificationprogress", GuessVerificationProgress(Params().TxData(), chainActive.Tip())));
+ obj.push_back(Pair("initialblockdownload", IsInitialBlockDownload()));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("size_on_disk", CalculateCurrentUsage()));
obj.push_back(Pair("pruned", fPruneMode));
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index f54f24e2a7..a595b6ec27 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/client.h"
-#include "rpc/protocol.h"
-#include "util.h"
+#include <rpc/client.h>
+#include <rpc/protocol.h>
+#include <util.h>
#include <set>
#include <stdint.h>
@@ -141,6 +141,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "echojson", 7, "arg7" },
{ "echojson", 8, "arg8" },
{ "echojson", 9, "arg9" },
+ { "rescanblockchain", 0, "start_height"},
+ { "rescanblockchain", 1, "stop_height"},
};
class CRPCConvertTable
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f79439f038..1753ecd3fc 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -3,28 +3,28 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "amount.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "consensus/consensus.h"
-#include "consensus/params.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "init.h"
-#include "validation.h"
-#include "miner.h"
-#include "net.h"
-#include "policy/fees.h"
-#include "pow.h"
-#include "rpc/blockchain.h"
-#include "rpc/mining.h"
-#include "rpc/server.h"
-#include "txmempool.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
-#include "warnings.h"
+#include <base58.h>
+#include <amount.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <consensus/consensus.h>
+#include <consensus/params.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <init.h>
+#include <validation.h>
+#include <miner.h>
+#include <net.h>
+#include <policy/fees.h>
+#include <pow.h>
+#include <rpc/blockchain.h>
+#include <rpc/mining.h>
+#include <rpc/server.h>
+#include <txmempool.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
+#include <warnings.h>
#include <memory>
#include <stdint.h>
@@ -455,7 +455,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
{
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain;
- boost::system_time checktxtime;
+ std::chrono::steady_clock::time_point checktxtime;
unsigned int nTransactionsUpdatedLastLP;
if (lpval.isStr())
@@ -476,17 +476,17 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
// Release the wallet and main lock while waiting
LEAVE_CRITICAL_SECTION(cs_main);
{
- checktxtime = boost::get_system_time() + boost::posix_time::minutes(1);
+ checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
- boost::unique_lock<boost::mutex> lock(csBestBlock);
+ WaitableLock lock(csBestBlock);
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
{
- if (!cvBlockChange.timed_wait(lock, checktxtime))
+ if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout)
{
// Timeout: Check transactions for update
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
- checktxtime += boost::posix_time::seconds(10);
+ checktxtime += std::chrono::seconds(10);
}
}
}
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
index 868d7002b5..8d46273159 100644
--- a/src/rpc/mining.h
+++ b/src/rpc/mining.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_RPC_MINING_H
#define BITCOIN_RPC_MINING_H
-#include "script/script.h"
+#include <script/script.h>
#include <univalue.h>
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 521b49e2a7..b3e22f5f10 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -3,27 +3,27 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "chain.h"
-#include "clientversion.h"
-#include "core_io.h"
-#include "crypto/ripemd160.h"
-#include "init.h"
-#include "validation.h"
-#include "httpserver.h"
-#include "net.h"
-#include "netbase.h"
-#include "rpc/blockchain.h"
-#include "rpc/server.h"
-#include "timedata.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <base58.h>
+#include <chain.h>
+#include <clientversion.h>
+#include <core_io.h>
+#include <crypto/ripemd160.h>
+#include <init.h>
+#include <validation.h>
+#include <httpserver.h>
+#include <net.h>
+#include <netbase.h>
+#include <rpc/blockchain.h>
+#include <rpc/server.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilstrencodings.h>
#ifdef ENABLE_WALLET
-#include "wallet/rpcwallet.h"
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
+#include <wallet/rpcwallet.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
#endif
-#include "warnings.h"
+#include <warnings.h>
#include <stdint.h>
#ifdef HAVE_MALLOC_INFO
@@ -608,6 +608,7 @@ static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
{ "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
+ { "control", "logging", &logging, {"include", "exclude"}},
{ "util", "validateaddress", &validateaddress, {"address"} }, /* uses wallet if enabled */
{ "util", "createmultisig", &createmultisig, {"nrequired","keys"} },
{ "util", "verifymessage", &verifymessage, {"address","signature","message"} },
@@ -617,7 +618,6 @@ static const CRPCCommand commands[] =
{ "hidden", "setmocktime", &setmocktime, {"timestamp"}},
{ "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
{ "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "logging", &logging, {"include", "exclude"}},
};
void RegisterMiscRPCCommands(CRPCTable &t)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index a3d3df26a3..322a3e0cbd 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/server.h"
-
-#include "chainparams.h"
-#include "clientversion.h"
-#include "core_io.h"
-#include "validation.h"
-#include "net.h"
-#include "net_processing.h"
-#include "netbase.h"
-#include "policy/policy.h"
-#include "protocol.h"
-#include "sync.h"
-#include "timedata.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
-#include "warnings.h"
+#include <rpc/server.h>
+
+#include <chainparams.h>
+#include <clientversion.h>
+#include <core_io.h>
+#include <validation.h>
+#include <net.h>
+#include <net_processing.h>
+#include <netbase.h>
+#include <policy/policy.h>
+#include <rpc/protocol.h>
+#include <sync.h>
+#include <timedata.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
+#include <warnings.h>
#include <univalue.h>
@@ -92,7 +92,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request)
" \"version\": v, (numeric) The peer version, such as 7001\n"
" \"subver\": \"/Satoshi:0.8.5/\", (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"
+ " \"addnode\": true|false, (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\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"
@@ -156,7 +156,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("addnode", stats.m_manual_connection));
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
@@ -201,6 +201,8 @@ UniValue addnode(const JSONRPCRequest& request)
"addnode \"node\" \"add|remove|onetry\"\n"
"\nAttempts to add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
+ "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n"
+ "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n"
"\nArguments:\n"
"1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
"2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n"
@@ -217,7 +219,7 @@ UniValue addnode(const JSONRPCRequest& request)
if (strCommand == "onetry")
{
CAddress addr;
- g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str());
+ g_connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true);
return NullUniValue;
}
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 1f4ae75b18..4cb28c2104 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/protocol.h"
-
-#include "random.h"
-#include "tinyformat.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "utiltime.h"
-#include "version.h"
+#include <rpc/protocol.h>
+
+#include <random.h>
+#include <tinyformat.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <utiltime.h>
+#include <version.h>
#include <stdint.h>
#include <fstream>
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index cb668f3db9..4b9bd41994 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_RPCPROTOCOL_H
#define BITCOIN_RPCPROTOCOL_H
-#include "fs.h"
+#include <fs.h>
#include <list>
#include <map>
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index d860dbc244..e65959bf0e 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -3,33 +3,35 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "chain.h"
-#include "coins.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "init.h"
-#include "keystore.h"
-#include "validation.h"
-#include "merkleblock.h"
-#include "net.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "primitives/transaction.h"
-#include "rpc/safemode.h"
-#include "rpc/server.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "script/standard.h"
-#include "txmempool.h"
-#include "uint256.h"
-#include "utilstrencodings.h"
+#include <base58.h>
+#include <chain.h>
+#include <coins.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <init.h>
+#include <keystore.h>
+#include <validation.h>
+#include <validationinterface.h>
+#include <merkleblock.h>
+#include <net.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <primitives/transaction.h>
+#include <rpc/safemode.h>
+#include <rpc/server.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/sign.h>
+#include <script/standard.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <utilstrencodings.h>
#ifdef ENABLE_WALLET
-#include "wallet/rpcwallet.h"
-#include "wallet/wallet.h"
+#include <wallet/rpcwallet.h>
+#include <wallet/wallet.h>
#endif
+#include <future>
#include <stdint.h>
#include <univalue.h>
@@ -917,7 +919,9 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
);
ObserveSafeMode();
- LOCK(cs_main);
+
+ std::promise<void> promise;
+
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
// parse hex string from parameter
@@ -931,6 +935,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
if (!request.params[1].isNull() && request.params[1].get_bool())
nMaxRawTxFee = 0;
+ { // cs_main scope
+ LOCK(cs_main);
CCoinsViewCache &view = *pcoinsTip;
bool fHaveChain = false;
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
@@ -952,10 +958,24 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
}
throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason());
}
+ } else {
+ // If wallet is enabled, ensure that the wallet has been made aware
+ // of the new transaction prior to returning. This prevents a race
+ // where a user might call sendrawtransaction with a transaction
+ // to/from their wallet, immediately call some wallet RPC, and get
+ // a stale result because callbacks have not yet been processed.
+ CallFunctionInValidationInterfaceQueue([&promise] {
+ promise.set_value();
+ });
}
} else if (fHaveChain) {
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
}
+
+ } // cs_main
+
+ promise.get_future().wait();
+
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -964,6 +984,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
{
pnode->PushInventory(inv);
});
+
return hashTx.GetHex();
}
diff --git a/src/rpc/safemode.cpp b/src/rpc/safemode.cpp
index 24770ad47f..9f3a9d30b8 100644
--- a/src/rpc/safemode.cpp
+++ b/src/rpc/safemode.cpp
@@ -1,8 +1,8 @@
-#include "safemode.h"
+#include <rpc/safemode.h>
-#include "rpc/protocol.h"
-#include "util.h"
-#include "warnings.h"
+#include <rpc/protocol.h>
+#include <util.h>
+#include <warnings.h>
void ObserveSafeMode()
{
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 39bcfc6903..fa81398272 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/server.h"
-
-#include "base58.h"
-#include "fs.h"
-#include "init.h"
-#include "random.h"
-#include "sync.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <rpc/server.h>
+
+#include <base58.h>
+#include <fs.h>
+#include <init.h>
+#include <random.h>
+#include <sync.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <univalue.h>
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 74c4a9e801..cd201bf316 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_RPCSERVER_H
#define BITCOIN_RPCSERVER_H
-#include "amount.h"
-#include "rpc/protocol.h"
-#include "uint256.h"
+#include <amount.h>
+#include <rpc/protocol.h>
+#include <uint256.h>
#include <list>
#include <map>
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 4edb2c6d9b..260f6fa60e 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "scheduler.h"
+#include <scheduler.h>
-#include "random.h"
-#include "reverselock.h"
+#include <random.h>
+#include <reverselock.h>
#include <assert.h>
#include <boost/bind.hpp>
diff --git a/src/scheduler.h b/src/scheduler.h
index db93bcb21e..b99f165343 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -14,7 +14,7 @@
#include <boost/thread.hpp>
#include <map>
-#include "sync.h"
+#include <sync.h>
//
// Simple class for background tasks that should be run
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 03128917fd..77edc85b8c 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bitcoinconsensus.h"
+#include <script/bitcoinconsensus.h>
-#include "primitives/transaction.h"
-#include "pubkey.h"
-#include "script/interpreter.h"
-#include "version.h"
+#include <primitives/transaction.h>
+#include <pubkey.h>
+#include <script/interpreter.h>
+#include <version.h>
namespace {
diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h
index 33bf80e5a7..f09cd59b92 100644
--- a/src/script/bitcoinconsensus.h
+++ b/src/script/bitcoinconsensus.h
@@ -9,7 +9,7 @@
#include <stdint.h>
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#if defined(_WIN32)
#if defined(DLL_EXPORT)
#if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT)
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 2f7b8e3a03..d6348f17d8 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -3,15 +3,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "interpreter.h"
-
-#include "primitives/transaction.h"
-#include "crypto/ripemd160.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "pubkey.h"
-#include "script/script.h"
-#include "uint256.h"
+#include <script/interpreter.h>
+
+#include <primitives/transaction.h>
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <pubkey.h>
+#include <script/script.h>
+#include <uint256.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 1cb9cc7899..2eae68179e 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_SCRIPT_INTERPRETER_H
#define BITCOIN_SCRIPT_INTERPRETER_H
-#include "script_error.h"
-#include "primitives/transaction.h"
+#include <script/script_error.h>
+#include <primitives/transaction.h>
#include <vector>
#include <stdint.h>
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 6b68f0679e..60bef3b701 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -3,13 +3,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "ismine.h"
+#include <script/ismine.h>
-#include "key.h"
-#include "keystore.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "script/sign.h"
+#include <key.h>
+#include <keystore.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <script/sign.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/script/ismine.h b/src/script/ismine.h
index 1aa5937b34..77ffa82432 100644
--- a/src/script/ismine.h
+++ b/src/script/ismine.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SCRIPT_ISMINE_H
#define BITCOIN_SCRIPT_ISMINE_H
-#include "script/standard.h"
+#include <script/standard.h>
#include <stdint.h>
diff --git a/src/script/script.cpp b/src/script/script.cpp
index a10b619f7d..a7bfb170eb 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script.h"
+#include <script/script.h>
-#include "tinyformat.h"
-#include "utilstrencodings.h"
+#include <tinyformat.h>
+#include <utilstrencodings.h>
const char* GetOpName(opcodetype opcode)
{
diff --git a/src/script/script.h b/src/script/script.h
index 2a92060543..263db62edf 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_SCRIPT_SCRIPT_H
#define BITCOIN_SCRIPT_SCRIPT_H
-#include "crypto/common.h"
-#include "prevector.h"
-#include "serialize.h"
+#include <crypto/common.h>
+#include <prevector.h>
+#include <serialize.h>
#include <assert.h>
#include <climits>
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index 6c590f53e3..32aa639ac4 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script_error.h"
+#include <script/script_error.h>
const char* ScriptErrorString(const ScriptError serror)
{
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 4cc7afa2f5..88d1d67559 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -3,15 +3,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sigcache.h"
+#include <script/sigcache.h>
-#include "memusage.h"
-#include "pubkey.h"
-#include "random.h"
-#include "uint256.h"
-#include "util.h"
+#include <memusage.h>
+#include <pubkey.h>
+#include <random.h>
+#include <uint256.h>
+#include <util.h>
-#include "cuckoocache.h"
+#include <cuckoocache.h>
#include <boost/thread.hpp>
namespace {
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 5832b264b3..1019061fbb 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SCRIPT_SIGCACHE_H
#define BITCOIN_SCRIPT_SIGCACHE_H
-#include "script/interpreter.h"
+#include <script/interpreter.h>
#include <vector>
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index ac58b690a2..117a4d8a52 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script/sign.h"
-
-#include "key.h"
-#include "keystore.h"
-#include "policy/policy.h"
-#include "primitives/transaction.h"
-#include "script/standard.h"
-#include "uint256.h"
+#include <script/sign.h>
+
+#include <key.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <primitives/transaction.h>
+#include <script/standard.h>
+#include <uint256.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/script/sign.h b/src/script/sign.h
index a0d8ee4ff9..400c0c0865 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SCRIPT_SIGN_H
#define BITCOIN_SCRIPT_SIGN_H
-#include "script/interpreter.h"
+#include <script/interpreter.h>
class CKeyID;
class CKeyStore;
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index f57f1f61b4..b7b33fade6 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "script/standard.h"
+#include <script/standard.h>
-#include "pubkey.h"
-#include "script/script.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <pubkey.h>
+#include <script/script.h>
+#include <util.h>
+#include <utilstrencodings.h>
typedef std::vector<unsigned char> valtype;
diff --git a/src/script/standard.h b/src/script/standard.h
index fa07ea88c1..3eeeabdc15 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_SCRIPT_STANDARD_H
#define BITCOIN_SCRIPT_STANDARD_H
-#include "script/interpreter.h"
-#include "uint256.h"
+#include <script/interpreter.h>
+#include <uint256.h>
#include <boost/variant.hpp>
diff --git a/src/serialize.h b/src/serialize.h
index eeb05fa76c..62ecde4823 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SERIALIZE_H
#define BITCOIN_SERIALIZE_H
-#include "compat/endian.h"
+#include <compat/endian.h>
#include <algorithm>
#include <assert.h>
@@ -21,7 +21,7 @@
#include <utility>
#include <vector>
-#include "prevector.h"
+#include <prevector.h>
static const unsigned int MAX_SIZE = 0x02000000;
diff --git a/src/streams.h b/src/streams.h
index 9a3badea57..a212691f6d 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_STREAMS_H
#define BITCOIN_STREAMS_H
-#include "support/allocators/zeroafterfree.h"
-#include "serialize.h"
+#include <support/allocators/zeroafterfree.h>
+#include <serialize.h>
#include <algorithm>
#include <assert.h>
@@ -345,18 +345,16 @@ public:
// Read from the beginning of the buffer
unsigned int nReadPosNext = nReadPos + nSize;
- if (nReadPosNext >= vch.size())
+ if (nReadPosNext > vch.size()) {
+ throw std::ios_base::failure("CDataStream::read(): end of data");
+ }
+ memcpy(pch, &vch[nReadPos], nSize);
+ if (nReadPosNext == vch.size())
{
- if (nReadPosNext > vch.size())
- {
- throw std::ios_base::failure("CDataStream::read(): end of data");
- }
- memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
vch.clear();
return;
}
- memcpy(pch, &vch[nReadPos], nSize);
nReadPos = nReadPosNext;
}
diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h
index 39347c73bb..7cd031bfe8 100644
--- a/src/support/allocators/secure.h
+++ b/src/support/allocators/secure.h
@@ -6,8 +6,8 @@
#ifndef BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
#define BITCOIN_SUPPORT_ALLOCATORS_SECURE_H
-#include "support/lockedpool.h"
-#include "support/cleanse.h"
+#include <support/lockedpool.h>
+#include <support/cleanse.h>
#include <string>
diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h
index 618874ceee..23ef96c13f 100644
--- a/src/support/allocators/zeroafterfree.h
+++ b/src/support/allocators/zeroafterfree.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
#define BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H
-#include "support/cleanse.h"
+#include <support/cleanse.h>
#include <memory>
#include <vector>
diff --git a/src/support/cleanse.cpp b/src/support/cleanse.cpp
index 95899c9f02..82cdfe707b 100644
--- a/src/support/cleanse.cpp
+++ b/src/support/cleanse.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "cleanse.h"
+#include <support/cleanse.h>
#include <cstring>
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 2ead72185f..98e8694181 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "support/lockedpool.h"
-#include "support/cleanse.h"
+#include <support/lockedpool.h>
+#include <support/cleanse.h>
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#ifdef WIN32
diff --git a/src/sync.cpp b/src/sync.cpp
index 87024ccdf2..fcc6ddc354 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sync.h"
+#include <sync.h>
-#include "util.h"
-#include "utilstrencodings.h"
+#include <util.h>
+#include <utilstrencodings.h>
#include <stdio.h>
@@ -155,6 +155,16 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
abort();
}
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
+{
+ for (const std::pair<void*, CLockLocation>& i : *lockstack) {
+ if (i.first == cs) {
+ fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
+ abort();
+ }
+ }
+}
+
void DeleteLock(void* cs)
{
if (!lockdata.available) {
diff --git a/src/sync.h b/src/sync.h
index 0871c5fb4d..b0889be767 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -6,11 +6,13 @@
#ifndef BITCOIN_SYNC_H
#define BITCOIN_SYNC_H
-#include "threadsafety.h"
+#include <threadsafety.h>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
-#include <boost/thread/recursive_mutex.hpp>
+#include <condition_variable>
+#include <thread>
+#include <mutex>
////////////////////////////////////////////////
@@ -21,17 +23,17 @@
/*
CCriticalSection mutex;
- boost::recursive_mutex mutex;
+ std::recursive_mutex mutex;
LOCK(mutex);
- boost::unique_lock<boost::recursive_mutex> criticalblock(mutex);
+ std::unique_lock<std::recursive_mutex> criticalblock(mutex);
LOCK2(mutex1, mutex2);
- boost::unique_lock<boost::recursive_mutex> criticalblock1(mutex1);
- boost::unique_lock<boost::recursive_mutex> criticalblock2(mutex2);
+ std::unique_lock<std::recursive_mutex> criticalblock1(mutex1);
+ std::unique_lock<std::recursive_mutex> criticalblock2(mutex2);
TRY_LOCK(mutex, name);
- boost::unique_lock<boost::recursive_mutex> name(mutex, boost::try_to_lock_t);
+ std::unique_lock<std::recursive_mutex> name(mutex, std::try_to_lock_t);
ENTER_CRITICAL_SECTION(mutex); // no RAII
mutex.lock();
@@ -75,20 +77,23 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs
void LeaveCritical();
std::string LocksHeld();
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
+void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs);
void DeleteLock(void* cs);
#else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
void static inline LeaveCritical() {}
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
+void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {}
void static inline DeleteLock(void* cs) {}
#endif
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
+#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
/**
- * Wrapped boost mutex: supports recursive locking, but no waiting
+ * Wrapped mutex: supports recursive locking, but no waiting
* TODO: We should move away from using the recursive lock by default.
*/
-class CCriticalSection : public AnnotatedMixin<boost::recursive_mutex>
+class CCriticalSection : public AnnotatedMixin<std::recursive_mutex>
{
public:
~CCriticalSection() {
@@ -96,22 +101,24 @@ public:
}
};
-/** Wrapped boost mutex: supports waiting but not recursive locking */
-typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
+/** Wrapped mutex: supports waiting but not recursive locking */
+typedef AnnotatedMixin<std::mutex> CWaitableCriticalSection;
-/** Just a typedef for boost::condition_variable, can be wrapped later if desired */
-typedef boost::condition_variable CConditionVariable;
+/** Just a typedef for std::condition_variable, can be wrapped later if desired */
+typedef std::condition_variable CConditionVariable;
+
+/** Just a typedef for std::unique_lock, can be wrapped later if desired */
+typedef std::unique_lock<std::mutex> WaitableLock;
#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
#endif
-/** Wrapper around boost::unique_lock<Mutex> */
-template <typename Mutex>
-class SCOPED_LOCKABLE CMutexLock
+/** Wrapper around std::unique_lock<CCriticalSection> */
+class SCOPED_LOCKABLE CCriticalBlock
{
private:
- boost::unique_lock<Mutex> lock;
+ std::unique_lock<CCriticalSection> lock;
void Enter(const char* pszName, const char* pszFile, int nLine)
{
@@ -136,7 +143,7 @@ private:
}
public:
- CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
+ CCriticalBlock(CCriticalSection& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, std::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -144,18 +151,18 @@ public:
Enter(pszName, pszFile, nLine);
}
- CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
+ CCriticalBlock(CCriticalSection* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
- lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
+ lock = std::unique_lock<CCriticalSection>(*pmutexIn, std::defer_lock);
if (fTry)
TryEnter(pszName, pszFile, nLine);
else
Enter(pszName, pszFile, nLine);
}
- ~CMutexLock() UNLOCK_FUNCTION()
+ ~CCriticalBlock() UNLOCK_FUNCTION()
{
if (lock.owns_lock())
LeaveCritical();
@@ -167,8 +174,6 @@ public:
}
};
-typedef CMutexLock<CCriticalSection> CCriticalBlock;
-
#define PASTE(x, y) x ## y
#define PASTE2(x, y) PASTE(x, y)
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index b88ad5ed1b..6be176a1ad 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -4,17 +4,17 @@
// Unit tests for denial-of-service detection/prevention code
-#include "chainparams.h"
-#include "keystore.h"
-#include "net.h"
-#include "net_processing.h"
-#include "pow.h"
-#include "script/sign.h"
-#include "serialize.h"
-#include "util.h"
-#include "validation.h"
-
-#include "test/test_bitcoin.h"
+#include <chainparams.h>
+#include <keystore.h>
+#include <net.h>
+#include <net_processing.h>
+#include <pow.h>
+#include <script/sign.h>
+#include <serialize.h>
+#include <util.h>
+#include <validation.h>
+
+#include <test/test_bitcoin.h>
#include <stdint.h>
@@ -40,8 +40,141 @@ CService ip(uint32_t i)
static NodeId id = 0;
+void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds);
+
BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
+// Test eviction of an outbound peer whose chain never advances
+// Mock a node connection, and use mocktime to simulate a peer
+// which never sends any headers messages. PeerLogic should
+// decide to evict that outbound peer, after the appropriate timeouts.
+// Note that we protect 4 outbound nodes from being subject to
+// this logic; this test takes advantage of that protection only
+// being applied to nodes which send headers with sufficient
+// work.
+BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
+{
+ std::atomic<bool> interruptDummy(false);
+
+ // Mock an outbound peer
+ CAddress addr1(ip(0xa0b0c001), NODE_NONE);
+ CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", /*fInboundIn=*/ false);
+ dummyNode1.SetSendVersion(PROTOCOL_VERSION);
+
+ peerLogic->InitializeNode(&dummyNode1);
+ dummyNode1.nVersion = 1;
+ dummyNode1.fSuccessfullyConnected = true;
+
+ // This test requires that we have a chain with non-zero work.
+ LOCK(cs_main);
+ BOOST_CHECK(chainActive.Tip() != nullptr);
+ BOOST_CHECK(chainActive.Tip()->nChainWork > 0);
+
+ // Test starts here
+ LOCK(dummyNode1.cs_sendProcessing);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ LOCK(dummyNode1.cs_vSend);
+ BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ dummyNode1.vSendMsg.clear();
+
+ int64_t nStartTime = GetTime();
+ // Wait 21 minutes
+ SetMockTime(nStartTime+21*60);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in getheaders
+ BOOST_CHECK(dummyNode1.vSendMsg.size() > 0);
+ // Wait 3 more minutes
+ SetMockTime(nStartTime+24*60);
+ peerLogic->SendMessages(&dummyNode1, interruptDummy); // should result in disconnect
+ BOOST_CHECK(dummyNode1.fDisconnect == true);
+ SetMockTime(0);
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
+}
+
+void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic)
+{
+ CAddress addr(ip(GetRandInt(0xffffffff)), NODE_NONE);
+ vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false));
+ CNode &node = *vNodes.back();
+ node.SetSendVersion(PROTOCOL_VERSION);
+
+ peerLogic.InitializeNode(&node);
+ node.nVersion = 1;
+ node.fSuccessfullyConnected = true;
+
+ CConnmanTest::AddNode(node);
+}
+
+BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ constexpr int nMaxOutbound = 8;
+ CConnman::Options options;
+ options.nMaxConnections = 125;
+ options.nMaxOutbound = nMaxOutbound;
+ options.nMaxFeeler = 1;
+
+ connman->Init(options);
+ std::vector<CNode *> vNodes;
+
+ // Mock some outbound peers
+ for (int i=0; i<nMaxOutbound; ++i) {
+ AddRandomOutboundPeer(vNodes, *peerLogic);
+ }
+
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+
+ // No nodes should be marked for disconnection while we have no extra peers
+ for (const CNode *node : vNodes) {
+ BOOST_CHECK(node->fDisconnect == false);
+ }
+
+ SetMockTime(GetTime() + 3*consensusParams.nPowTargetSpacing + 1);
+
+ // Now tip should definitely be stale, and we should look for an extra
+ // outbound peer
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ BOOST_CHECK(connman->GetTryNewOutboundPeer());
+
+ // Still no peers should be marked for disconnection
+ for (const CNode *node : vNodes) {
+ BOOST_CHECK(node->fDisconnect == false);
+ }
+
+ // If we add one more peer, something should get marked for eviction
+ // on the next check (since we're mocking the time to be in the future, the
+ // required time connected check should be satisfied).
+ AddRandomOutboundPeer(vNodes, *peerLogic);
+
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ for (int i=0; i<nMaxOutbound; ++i) {
+ BOOST_CHECK(vNodes[i]->fDisconnect == false);
+ }
+ // Last added node should get marked for eviction
+ BOOST_CHECK(vNodes.back()->fDisconnect == true);
+
+ vNodes.back()->fDisconnect = false;
+
+ // Update the last announced block time for the last
+ // peer, and check that the next newest node gets evicted.
+ UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());
+
+ peerLogic->CheckForStaleTipAndEvictPeers(consensusParams);
+ for (int i=0; i<nMaxOutbound-1; ++i) {
+ BOOST_CHECK(vNodes[i]->fDisconnect == false);
+ }
+ BOOST_CHECK(vNodes[nMaxOutbound-1]->fDisconnect == true);
+ BOOST_CHECK(vNodes.back()->fDisconnect == false);
+
+ bool dummy;
+ for (const CNode *node : vNodes) {
+ peerLogic->FinalizeNode(node->GetId(), dummy);
+ }
+
+ CConnmanTest::ClearNodes();
+}
+
BOOST_AUTO_TEST_CASE(DoS_banning)
{
std::atomic<bool> interruptDummy(false);
@@ -53,7 +186,11 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true;
- Misbehaving(dummyNode1.GetId(), 100); // Should get banned
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 100); // Should get banned
+ }
+ LOCK(dummyNode1.cs_sendProcessing);
peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr1));
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
@@ -64,13 +201,24 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1;
dummyNode2.fSuccessfullyConnected = true;
- Misbehaving(dummyNode2.GetId(), 50);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode2.GetId(), 50);
+ }
+ LOCK(dummyNode2.cs_sendProcessing);
peerLogic->SendMessages(&dummyNode2, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
BOOST_CHECK(connman->IsBanned(addr1)); // ... but 1 still should be
- Misbehaving(dummyNode2.GetId(), 50);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode2.GetId(), 50);
+ }
peerLogic->SendMessages(&dummyNode2, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr2));
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
+ peerLogic->FinalizeNode(dummyNode2.GetId(), dummy);
}
BOOST_AUTO_TEST_CASE(DoS_banscore)
@@ -85,16 +233,29 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true;
- Misbehaving(dummyNode1.GetId(), 100);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 100);
+ }
+ LOCK(dummyNode1.cs_sendProcessing);
peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr1));
- Misbehaving(dummyNode1.GetId(), 10);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 10);
+ }
peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(!connman->IsBanned(addr1));
- Misbehaving(dummyNode1.GetId(), 1);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode1.GetId(), 1);
+ }
peerLogic->SendMessages(&dummyNode1, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr1));
gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
}
BOOST_AUTO_TEST_CASE(DoS_bantime)
@@ -112,7 +273,11 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
dummyNode.nVersion = 1;
dummyNode.fSuccessfullyConnected = true;
- Misbehaving(dummyNode.GetId(), 100);
+ {
+ LOCK(cs_main);
+ Misbehaving(dummyNode.GetId(), 100);
+ }
+ LOCK(dummyNode.cs_sendProcessing);
peerLogic->SendMessages(&dummyNode, interruptDummy);
BOOST_CHECK(connman->IsBanned(addr));
@@ -121,11 +286,15 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime+60*60*24+1);
BOOST_CHECK(!connman->IsBanned(addr));
+
+ bool dummy;
+ peerLogic->FinalizeNode(dummyNode.GetId(), dummy);
}
CTransactionRef RandomOrphan()
{
std::map<uint256, COrphanTx>::iterator it;
+ LOCK(cs_main);
it = mapOrphanTransactions.lower_bound(InsecureRand256());
if (it == mapOrphanTransactions.end())
it = mapOrphanTransactions.begin();
@@ -195,6 +364,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));
}
+ LOCK(cs_main);
// Test EraseOrphansFor:
for (NodeId i = 0; i < 3; i++)
{
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 7be29c6d6b..609b1a05d3 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -1,14 +1,14 @@
// 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 "addrman.h"
-#include "test/test_bitcoin.h"
+#include <addrman.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <boost/test/unit_test.hpp>
-#include "hash.h"
-#include "netbase.h"
-#include "random.h"
+#include <hash.h>
+#include <netbase.h>
+#include <random.h>
class CAddrManTest : public CAddrMan
{
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 4a533b5bf2..83fa3b76be 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
+#include <util.h>
-#include "support/allocators/secure.h"
-#include "test/test_bitcoin.h"
+#include <support/allocators/secure.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index 952cf901f0..7ebbd22c5d 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "amount.h"
-#include "policy/feerate.h"
-#include "test/test_bitcoin.h"
+#include <amount.h>
+#include <policy/feerate.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 2c98fbcfd6..eb3148a1de 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.cpp
@@ -8,11 +8,11 @@
#include <iomanip>
#include <limits>
#include <cmath>
-#include "uint256.h"
-#include "arith_uint256.h"
+#include <uint256.h>
+#include <arith_uint256.h>
#include <string>
-#include "version.h"
-#include "test/test_bitcoin.h"
+#include <version.h>
+#include <test/test_bitcoin.h>
BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup)
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index 6422b3a88f..abf236b953 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index 6bc6dd5187..3156cc53d0 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-
-#include "data/base58_encode_decode.json.h"
-#include "data/base58_keys_invalid.json.h"
-#include "data/base58_keys_valid.json.h"
-
-#include "key.h"
-#include "script/script.h"
-#include "test/test_bitcoin.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <base58.h>
+
+#include <test/data/base58_encode_decode.json.h>
+#include <test/data/base58_keys_invalid.json.h>
+#include <test/data/base58_keys_valid.json.h>
+
+#include <key.h>
+#include <script/script.h>
+#include <test/test_bitcoin.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <univalue.h>
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index ccad94d946..46b3a04f35 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
index ce4cddd64b..495290c8d9 100644
--- a/src/test/bech32_tests.cpp
+++ b/src/test/bech32_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bech32.h"
-#include "test/test_bitcoin.h"
+#include <bech32.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index e123c26ad0..e3e727439b 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -4,12 +4,12 @@
#include <boost/test/unit_test.hpp>
-#include "base58.h"
-#include "key.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <base58.h>
+#include <key.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <vector>
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index f2d5b385d0..718b5bdfb9 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "blockencodings.h"
-#include "consensus/merkle.h"
-#include "chainparams.h"
-#include "random.h"
+#include <blockencodings.h>
+#include <consensus/merkle.h>
+#include <chainparams.h>
+#include <random.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
@@ -62,6 +62,7 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest)
CBlock block(BuildBlockTestCase());
pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
// Do a simple ShortTxIDs RT
@@ -161,6 +162,7 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest)
CBlock block(BuildBlockTestCase());
pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2]));
+ LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
uint256 txhash;
@@ -227,6 +229,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest)
CBlock block(BuildBlockTestCase());
pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1]));
+ LOCK(pool.cs);
BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0);
uint256 txhash;
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index eac2c102a6..fdd30be0b1 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -2,20 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "bloom.h"
-
-#include "base58.h"
-#include "clientversion.h"
-#include "key.h"
-#include "merkleblock.h"
-#include "primitives/block.h"
-#include "random.h"
-#include "serialize.h"
-#include "streams.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <bloom.h>
+
+#include <base58.h>
+#include <clientversion.h>
+#include <key.h>
+#include <merkleblock.h>
+#include <primitives/block.h>
+#include <random.h>
+#include <serialize.h>
+#include <streams.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp
index 7b3134d327..ab4f08b999 100644
--- a/src/test/bswap_tests.cpp
+++ b/src/test/bswap_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compat/byteswap.h"
-#include "test/test_bitcoin.h"
+#include <compat/byteswap.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 6ae0bcadd0..d8ad0d9165 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
-#include "utiltime.h"
-#include "validation.h"
+#include <util.h>
+#include <utiltime.h>
+#include <validation.h>
-#include "test/test_bitcoin.h"
-#include "checkqueue.h"
+#include <test/test_bitcoin.h>
+#include <checkqueue.h>
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
#include <atomic>
@@ -18,7 +18,7 @@
#include <unordered_set>
#include <memory>
-#include "random.h"
+#include <random.h>
// BasicTestingSetup not sufficient because nScriptCheckThreads is not set
// otherwise.
@@ -38,7 +38,7 @@ struct FakeCheckCheckCompletion {
static std::atomic<size_t> n_calls;
bool operator()()
{
- ++n_calls;
+ n_calls.fetch_add(1, std::memory_order_relaxed);
return true;
}
void swap(FakeCheckCheckCompletion& x){};
@@ -88,15 +88,15 @@ struct MemoryCheck {
//
// Really, copy constructor should be deletable, but CCheckQueue breaks
// if it is deleted because of internal push_back.
- fake_allocated_memory += b;
+ fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);
};
MemoryCheck(bool b_) : b(b_)
{
- fake_allocated_memory += b;
+ fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);
};
- ~MemoryCheck(){
- fake_allocated_memory -= b;
-
+ ~MemoryCheck()
+ {
+ fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed);
};
void swap(MemoryCheck& x) { std::swap(b, x.b); };
};
@@ -117,9 +117,9 @@ struct FrozenCleanupCheck {
{
if (should_freeze) {
std::unique_lock<std::mutex> l(m);
- nFrozen = 1;
+ nFrozen.store(1, std::memory_order_relaxed);
cv.notify_one();
- cv.wait(l, []{ return nFrozen == 0;});
+ cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;});
}
}
void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);};
@@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
control.Add(vChecks);
}
bool r =control.Wait();
- BOOST_REQUIRE(r || end_fails);
+ BOOST_REQUIRE(r != end_fails);
}
}
tg.interrupt_all();
@@ -337,7 +337,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
tg.join_all();
}
-// Test that a new verification cannot occur until all checks
+// Test that a new verification cannot occur until all checks
// have been destructed
BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
{
@@ -361,11 +361,14 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
// Wait until the queue has finished all jobs and frozen
FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;});
- // Try to get control of the queue a bunch of times
- for (auto x = 0; x < 100 && !fails; ++x) {
- fails = queue->ControlMutex.try_lock();
- }
- // Unfreeze
+ }
+ // Try to get control of the queue a bunch of times
+ for (auto x = 0; x < 100 && !fails; ++x) {
+ fails = queue->ControlMutex.try_lock();
+ }
+ {
+ // Unfreeze (we need lock n case of spurious wakeup)
+ std::unique_lock<std::mutex> l(FrozenCleanupCheck::m);
FrozenCleanupCheck::nFrozen = 0;
}
// Awaken frozen destructor
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index dc358bff95..7c3d02ba63 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "coins.h"
-#include "script/standard.h"
-#include "uint256.h"
-#include "undo.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
-#include "validation.h"
-#include "consensus/validation.h"
+#include <coins.h>
+#include <script/standard.h>
+#include <uint256.h>
+#include <undo.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
+#include <validation.h>
+#include <consensus/validation.h>
#include <vector>
#include <map>
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index 35e4458bba..87e75d8020 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compressor.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <compressor.h>
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <stdint.h>
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index c748b2448c..a63d62bb37 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypto/aes.h"
-#include "crypto/chacha20.h"
-#include "crypto/ripemd160.h"
-#include "crypto/sha1.h"
-#include "crypto/sha256.h"
-#include "crypto/sha512.h"
-#include "crypto/hmac_sha256.h"
-#include "crypto/hmac_sha512.h"
-#include "random.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <crypto/aes.h>
+#include <crypto/chacha20.h>
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <crypto/sha512.h>
+#include <crypto/hmac_sha256.h>
+#include <crypto/hmac_sha512.h>
+#include <random.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index 1004482224..32d46da984 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
-#include "cuckoocache.h"
-#include "script/sigcache.h"
-#include "test/test_bitcoin.h"
-#include "random.h"
+#include <cuckoocache.h>
+#include <script/sigcache.h>
+#include <test/test_bitcoin.h>
+#include <random.h>
#include <thread>
/** Test Suite for CuckooCache
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index efddafe17e..2e1e4da72f 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "dbwrapper.h"
-#include "uint256.h"
-#include "random.h"
-#include "test/test_bitcoin.h"
+#include <dbwrapper.h>
+#include <uint256.h>
+#include <random.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
@@ -125,7 +125,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
@@ -135,8 +135,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
// Call the destructor to free leveldb LOCK
- delete dbw;
- dbw = nullptr;
+ dbw.reset();
// Now, set up another wrapper that wants to obfuscate the same directory
CDBWrapper odbw(ph, (1 << 10), false, false, true);
@@ -167,7 +166,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
- CDBWrapper* dbw = new CDBWrapper(ph, (1 << 10), false, false, false);
+ std::unique_ptr<CDBWrapper> dbw = MakeUnique<CDBWrapper>(ph, (1 << 10), false, false, false);
char key = 'k';
uint256 in = InsecureRand256();
uint256 res;
@@ -177,8 +176,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_CHECK_EQUAL(res.ToString(), in.ToString());
// Call the destructor to free leveldb LOCK
- delete dbw;
- dbw = nullptr;
+ dbw.reset();
// Simulate a -reindex by wiping the existing data store
CDBWrapper odbw(ph, (1 << 10), false, true, true);
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 40f0ecd5f1..3c39258693 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <vector>
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 05b6b3b1e6..68f445d142 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "hash.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <hash.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 91c0175412..7b9d7a6398 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
-
-#include "base58.h"
-#include "script/script.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
+#include <key.h>
+
+#include <base58.h>
+#include <script/script.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <vector>
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
index b071ab117b..90730cd7b5 100644
--- a/src/test/limitedmap_tests.cpp
+++ b/src/test/limitedmap_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "limitedmap.h"
+#include <limitedmap.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 656aec606b..4be32f7628 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparams.h"
-#include "validation.h"
-#include "net.h"
+#include <chainparams.h>
+#include <validation.h>
+#include <net.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 116210a297..a694b870fe 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -2,11 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/policy.h"
-#include "txmempool.h"
-#include "util.h"
+#include <policy/policy.h>
+#include <txmempool.h>
+#include <util.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <list>
@@ -165,6 +165,7 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
sortedOrder[2] = tx1.GetHash().ToString(); // 10000
sortedOrder[3] = tx4.GetHash().ToString(); // 15000
sortedOrder[4] = tx2.GetHash().ToString(); // 20000
+ LOCK(pool.cs);
CheckSort<descendant_score>(pool, sortedOrder);
/* low fee but with high fee child */
@@ -375,6 +376,7 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
}
sortedOrder[4] = tx3.GetHash().ToString(); // 0
+ LOCK(pool.cs);
CheckSort<ancestor_score>(pool, sortedOrder);
/* low fee parent with high fee child */
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 1a1cf4399c..ee48d96ad9 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/merkle.h"
-#include "test/test_bitcoin.h"
+#include <consensus/merkle.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp
index 3e66c6f2c6..37a1a84136 100644
--- a/src/test/merkleblock_tests.cpp
+++ b/src/test/merkleblock_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "merkleblock.h"
-#include "uint256.h"
-#include "test/test_bitcoin.h"
+#include <merkleblock.h>
+#include <uint256.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 41e0626eb9..b1a2032ea8 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -2,23 +2,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chainparams.h"
-#include "coins.h"
-#include "consensus/consensus.h"
-#include "consensus/merkle.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "validation.h"
-#include "miner.h"
-#include "policy/policy.h"
-#include "pubkey.h"
-#include "script/standard.h"
-#include "txmempool.h"
-#include "uint256.h"
-#include "util.h"
-#include "utilstrencodings.h"
-
-#include "test/test_bitcoin.h"
+#include <chainparams.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <consensus/merkle.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <validation.h>
+#include <miner.h>
+#include <policy/policy.h>
+#include <pubkey.h>
+#include <script/standard.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <util.h>
+#include <utilstrencodings.h>
+
+#include <test/test_bitcoin.h>
#include <memory>
@@ -335,23 +335,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear();
- // invalid (pre-p2sh) txn in mempool, template creation fails
- tx.vin[0].prevout.hash = txFirst[0]->GetHash();
- tx.vin[0].prevout.n = 0;
- tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
- script = CScript() << OP_0;
- tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
- hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- tx.vin[0].prevout.hash = hash;
- tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
- tx.vout[0].nValue -= LOWFEE;
- hash = tx.GetHash();
- mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
- mempool.clear();
-
// double spend txn pair in mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash();
tx.vin[0].scriptSig = CScript() << OP_1;
@@ -391,6 +374,24 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.SetTip(next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+
+ // invalid p2sh txn in mempool, template creation fails
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
+ tx.vin[0].prevout.n = 0;
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
+ script = CScript() << OP_0;
+ tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
+ tx.vin[0].prevout.hash = hash;
+ tx.vin[0].scriptSig = CScript() << std::vector<unsigned char>(script.begin(), script.end());
+ tx.vout[0].nValue -= LOWFEE;
+ hash = tx.GetHash();
+ mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
+ BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
+ mempool.clear();
+
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex* del = chainActive.Tip();
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index de7f3b48f5..ffba7d6d22 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -2,16 +2,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
-#include "keystore.h"
-#include "policy/policy.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/interpreter.h"
-#include "script/sign.h"
-#include "script/ismine.h"
-#include "uint256.h"
-#include "test/test_bitcoin.h"
+#include <key.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/interpreter.h>
+#include <script/sign.h>
+#include <script/ismine.h>
+#include <uint256.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 31b05d868b..b4176a2b85 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1,17 +1,17 @@
// 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 "addrman.h"
-#include "test/test_bitcoin.h"
+#include <addrman.h>
+#include <test/test_bitcoin.h>
#include <string>
#include <boost/test/unit_test.hpp>
-#include "hash.h"
-#include "serialize.h"
-#include "streams.h"
-#include "net.h"
-#include "netbase.h"
-#include "chainparams.h"
-#include "util.h"
+#include <hash.h>
+#include <serialize.h>
+#include <streams.h>
+#include <net.h>
+#include <netbase.h>
+#include <chainparams.h>
+#include <util.h>
class CAddrManSerializationMock : public CAddrMan
{
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 1baf7643e5..f3a9b1fc65 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "netbase.h"
-#include "test/test_bitcoin.h"
-#include "utilstrencodings.h"
+#include <netbase.h>
+#include <test/test_bitcoin.h>
+#include <utilstrencodings.h>
#include <string>
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index c1d216d094..b7b632be3a 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/merkle.h"
-#include "merkleblock.h"
-#include "serialize.h"
-#include "streams.h"
-#include "uint256.h"
-#include "arith_uint256.h"
-#include "version.h"
-#include "test/test_bitcoin.h"
+#include <consensus/merkle.h>
+#include <merkleblock.h>
+#include <serialize.h>
+#include <streams.h>
+#include <uint256.h>
+#include <arith_uint256.h>
+#include <version.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index fd8f7191f4..d8026e4468 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "policy/policy.h"
-#include "policy/fees.h"
-#include "txmempool.h"
-#include "uint256.h"
-#include "util.h"
+#include <policy/policy.h>
+#include <policy/fees.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <util.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index b13f2625aa..2837537c9a 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "chainparams.h"
-#include "pow.h"
-#include "random.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <pow.h>
+#include <random.h>
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index 841282873f..1327d67650 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -3,13 +3,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <vector>
-#include "prevector.h"
+#include <prevector.h>
-#include "reverse_iterator.h"
-#include "serialize.h"
-#include "streams.h"
+#include <reverse_iterator.h>
+#include <serialize.h>
+#include <streams.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index 0d541ec7d4..781b1e242d 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -10,9 +10,9 @@
#include <map>
#include <stdlib.h>
-#include "support/events.h"
+#include <support/events.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 132e190051..1ca5a53d72 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
+#include <random.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
index 00dc47e13e..86d6161e20 100644
--- a/src/test/reverselock_tests.cpp
+++ b/src/test/reverselock_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "reverselock.h"
-#include "test/test_bitcoin.h"
+#include <reverselock.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index c6643be7a7..710d09ead6 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "rpc/server.h"
-#include "rpc/client.h"
+#include <rpc/server.h>
+#include <rpc/client.h>
-#include "base58.h"
-#include "core_io.h"
-#include "netbase.h"
+#include <base58.h>
+#include <core_io.h>
+#include <netbase.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 51f9e9f39f..b3ec6d34c7 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "compat/sanity.h"
-#include "key.h"
-#include "test/test_bitcoin.h"
+#include <compat/sanity.h>
+#include <key.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 1de865776e..7e86eed1c5 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
-#include "scheduler.h"
+#include <random.h>
+#include <scheduler.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index 58aa32c969..5a64aa3959 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -2,17 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/tx_verify.h"
-#include "core_io.h"
-#include "key.h"
-#include "keystore.h"
-#include "validation.h"
-#include "policy/policy.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "script/ismine.h"
-#include "test/test_bitcoin.h"
+#include <consensus/tx_verify.h>
+#include <core_io.h>
+#include <key.h>
+#include <keystore.h>
+#include <validation.h>
+#include <policy/policy.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/sign.h>
+#include <script/ismine.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index bd2d9ed115..19060eccc9 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "key.h"
-#include "keystore.h"
-#include "script/ismine.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/standard.h"
-#include "test/test_bitcoin.h"
+#include <key.h>
+#include <keystore.h>
+#include <script/ismine.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/standard.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 011a5db795..57b3e501af 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -2,21 +2,21 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "data/script_tests.json.h"
-
-#include "core_io.h"
-#include "key.h"
-#include "keystore.h"
-#include "script/script.h"
-#include "script/script_error.h"
-#include "script/sign.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "test/test_bitcoin.h"
-#include "rpc/server.h"
+#include <test/data/script_tests.json.h>
+
+#include <core_io.h>
+#include <key.h>
+#include <keystore.h>
+#include <script/script.h>
+#include <script/script_error.h>
+#include <script/sign.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <test/test_bitcoin.h>
+#include <rpc/server.h>
#if defined(HAVE_CONSENSUS_LIB)
-#include "script/bitcoinconsensus.h"
+#include <script/bitcoinconsensus.h>
#endif
#include <fstream>
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
index 94dd58526c..ad15427a9b 100644
--- a/src/test/scriptnum10.h
+++ b/src/test/scriptnum10.h
@@ -12,7 +12,7 @@
#include <stdint.h>
#include <string>
#include <vector>
-#include "assert.h"
+#include <assert.h>
class scriptnum10_error : public std::runtime_error
{
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index 280eb59ce8..aef500174a 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "scriptnum10.h"
-#include "script/script.h"
-#include "test/test_bitcoin.h"
+#include <test/scriptnum10.h>
+#include <script/script.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <limits.h>
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 9661a66514..28ed2bfeb0 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -2,10 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "serialize.h"
-#include "streams.h"
-#include "hash.h"
-#include "test/test_bitcoin.h"
+#include <serialize.h>
+#include <streams.h>
+#include <hash.h>
+#include <test/test_bitcoin.h>
#include <stdint.h>
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index ecbdf57788..d97e106287 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -2,18 +2,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "data/sighash.json.h"
-#include "hash.h"
-#include "script/interpreter.h"
-#include "script/script.h"
-#include "serialize.h"
-#include "streams.h"
-#include "test/test_bitcoin.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "version.h"
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <test/data/sighash.json.h>
+#include <hash.h>
+#include <script/interpreter.h>
+#include <script/script.h>
+#include <serialize.h>
+#include <streams.h>
+#include <test/test_bitcoin.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <version.h>
#include <iostream>
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index d3b8b07228..891cd1e1d8 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "pubkey.h"
-#include "key.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "uint256.h"
-#include "test/test_bitcoin.h"
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <pubkey.h>
+#include <key.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <uint256.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 164cbd873f..1ffd9f2b42 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "util.h"
-#include "test/test_bitcoin.h"
+#include <chain.h>
+#include <util.h>
+#include <test/test_bitcoin.h>
#include <vector>
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index af2a152aa5..3636e6c332 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "streams.h"
-#include "support/allocators/zeroafterfree.h"
-#include "test/test_bitcoin.h"
+#include <streams.h>
+#include <support/allocators/zeroafterfree.h>
+#include <test/test_bitcoin.h>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/test/unit_test.hpp>
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 79bc48a118..419106194e 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -2,29 +2,41 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "test_bitcoin.h"
-
-#include "chainparams.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "crypto/sha256.h"
-#include "fs.h"
-#include "key.h"
-#include "validation.h"
-#include "miner.h"
-#include "net_processing.h"
-#include "pubkey.h"
-#include "random.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "streams.h"
-#include "rpc/server.h"
-#include "rpc/register.h"
-#include "script/sigcache.h"
+#include <test/test_bitcoin.h>
+
+#include <chainparams.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <crypto/sha256.h>
+#include <fs.h>
+#include <key.h>
+#include <validation.h>
+#include <miner.h>
+#include <net_processing.h>
+#include <pubkey.h>
+#include <random.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <streams.h>
+#include <rpc/server.h>
+#include <rpc/register.h>
+#include <script/sigcache.h>
#include <memory>
+void CConnmanTest::AddNode(CNode& node)
+{
+ LOCK(g_connman->cs_vNodes);
+ g_connman->vNodes.push_back(&node);
+}
+
+void CConnmanTest::ClearNodes()
+{
+ LOCK(g_connman->cs_vNodes);
+ g_connman->vNodes.clear();
+}
+
uint256 insecure_rand_seed = GetRandHash();
FastRandomContext insecure_rand_ctx(insecure_rand_seed);
@@ -69,9 +81,9 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
mempool.setSanityCheck(1.0);
- pblocktree = new CBlockTreeDB(1 << 20, true);
- pcoinsdbview = new CCoinsViewDB(1 << 23, true);
- pcoinsTip = new CCoinsViewCache(pcoinsdbview);
+ pblocktree.reset(new CBlockTreeDB(1 << 20, true));
+ pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
+ pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
if (!LoadGenesisBlock(chainparams)) {
throw std::runtime_error("LoadGenesisBlock failed.");
}
@@ -86,7 +98,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
threadGroup.create_thread(&ThreadScriptCheck);
g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
connman = g_connman.get();
- peerLogic.reset(new PeerLogicValidation(connman));
+ peerLogic.reset(new PeerLogicValidation(connman, scheduler));
}
TestingSetup::~TestingSetup()
@@ -98,14 +110,17 @@ TestingSetup::~TestingSetup()
g_connman.reset();
peerLogic.reset();
UnloadBlockIndex();
- delete pcoinsTip;
- delete pcoinsdbview;
- delete pblocktree;
+ pcoinsTip.reset();
+ pcoinsdbview.reset();
+ pblocktree.reset();
fs::remove_all(pathTemp);
}
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
+ // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
+ // TODO: fix the code to support SegWit blocks.
+ UpdateVersionBitsParameters(Consensus::DEPLOYMENT_SEGWIT, 0, Consensus::BIP9Deployment::NO_TIMEOUT);
// Generate a 100-block chain:
coinbaseKey.MakeNewKey(true);
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
@@ -134,7 +149,10 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
block.vtx.push_back(MakeTransactionRef(tx));
// IncrementExtraNonce creates a valid coinbase and merkleRoot
unsigned int extraNonce = 0;
- IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+ {
+ LOCK(cs_main);
+ IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+ }
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 2390aca342..80a9cbaeea 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -5,14 +5,14 @@
#ifndef BITCOIN_TEST_TEST_BITCOIN_H
#define BITCOIN_TEST_TEST_BITCOIN_H
-#include "chainparamsbase.h"
-#include "fs.h"
-#include "key.h"
-#include "pubkey.h"
-#include "random.h"
-#include "scheduler.h"
-#include "txdb.h"
-#include "txmempool.h"
+#include <chainparamsbase.h>
+#include <fs.h>
+#include <key.h>
+#include <pubkey.h>
+#include <random.h>
+#include <scheduler.h>
+#include <txdb.h>
+#include <txmempool.h>
#include <boost/thread.hpp>
@@ -49,9 +49,14 @@ struct BasicTestingSetup {
* Included are data directory, coins database, script check threads setup.
*/
class CConnman;
+class CNode;
+struct CConnmanTest {
+ static void AddNode(CNode& node);
+ static void ClearNodes();
+};
+
class PeerLogicValidation;
struct TestingSetup: public BasicTestingSetup {
- CCoinsViewDB *pcoinsdbview;
fs::path pathTemp;
boost::thread_group threadGroup;
CConnman* connman;
diff --git a/src/test/test_bitcoin_fuzzy.cpp b/src/test/test_bitcoin_fuzzy.cpp
index 581ad2ffa0..319d81187a 100644
--- a/src/test/test_bitcoin_fuzzy.cpp
+++ b/src/test/test_bitcoin_fuzzy.cpp
@@ -3,22 +3,23 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "consensus/merkle.h"
-#include "primitives/block.h"
-#include "script/script.h"
-#include "addrman.h"
-#include "chain.h"
-#include "coins.h"
-#include "compressor.h"
-#include "net.h"
-#include "protocol.h"
-#include "streams.h"
-#include "undo.h"
-#include "version.h"
-#include "pubkey.h"
+#include <consensus/merkle.h>
+#include <primitives/block.h>
+#include <script/script.h>
+#include <addrman.h>
+#include <chain.h>
+#include <coins.h>
+#include <compressor.h>
+#include <net.h>
+#include <protocol.h>
+#include <streams.h>
+#include <undo.h>
+#include <version.h>
+#include <pubkey.h>
+#include <blockencodings.h>
#include <stdint.h>
#include <unistd.h>
@@ -45,6 +46,8 @@ enum TEST_ID {
CBLOOMFILTER_DESERIALIZE,
CDISKBLOCKINDEX_DESERIALIZE,
CTXOUTCOMPRESSOR_DESERIALIZE,
+ BLOCKTRANSACTIONS_DESERIALIZE,
+ BLOCKTRANSACTIONSREQUEST_DESERIALIZE,
TEST_ID_END
};
@@ -245,6 +248,26 @@ int test_one_input(std::vector<uint8_t> buffer) {
break;
}
+ case BLOCKTRANSACTIONS_DESERIALIZE:
+ {
+ try
+ {
+ BlockTransactions bt;
+ ds >> bt;
+ } catch (const std::ios_base::failure& e) {return 0;}
+
+ break;
+ }
+ case BLOCKTRANSACTIONSREQUEST_DESERIALIZE:
+ {
+ try
+ {
+ BlockTransactionsRequest btr;
+ ds >> btr;
+ } catch (const std::ios_base::failure& e) {return 0;}
+
+ break;
+ }
default:
return 0;
}
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
index b556c953b9..8d81ff6fc6 100644
--- a/src/test/test_bitcoin_main.cpp
+++ b/src/test/test_bitcoin_main.cpp
@@ -4,7 +4,7 @@
#define BOOST_TEST_MODULE Bitcoin Test Suite
-#include "net.h"
+#include <net.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp
index 34863fd9d0..9ff95bd2b0 100644
--- a/src/test/timedata_tests.cpp
+++ b/src/test/timedata_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
-#include "timedata.h"
-#include "test/test_bitcoin.h"
+#include <timedata.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/torcontrol_tests.cpp b/src/test/torcontrol_tests.cpp
index b7affaacde..d0aa8659c2 100644
--- a/src/test/torcontrol_tests.cpp
+++ b/src/test/torcontrol_tests.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
-#include "test/test_bitcoin.h"
-#include "torcontrol.cpp"
+#include <test/test_bitcoin.h>
+#include <torcontrol.cpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index cb6ab7cdbe..34a182722d 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -2,24 +2,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "data/tx_invalid.json.h"
-#include "data/tx_valid.json.h"
-#include "test/test_bitcoin.h"
-
-#include "clientversion.h"
-#include "checkqueue.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "key.h"
-#include "keystore.h"
-#include "validation.h"
-#include "policy/policy.h"
-#include "script/script.h"
-#include "script/sign.h"
-#include "script/script_error.h"
-#include "script/standard.h"
-#include "utilstrencodings.h"
+#include <test/data/tx_invalid.json.h>
+#include <test/data/tx_valid.json.h>
+#include <test/test_bitcoin.h>
+
+#include <clientversion.h>
+#include <checkqueue.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <key.h>
+#include <keystore.h>
+#include <validation.h>
+#include <policy/policy.h>
+#include <script/script.h>
+#include <script/sign.h>
+#include <script/script_error.h>
+#include <script/standard.h>
+#include <utilstrencodings.h>
#include <map>
#include <string>
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 82ca93e7da..fa49b9c33b 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -2,20 +2,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/validation.h"
-#include "key.h"
-#include "validation.h"
-#include "miner.h"
-#include "pubkey.h"
-#include "txmempool.h"
-#include "random.h"
-#include "script/standard.h"
-#include "script/sign.h"
-#include "test/test_bitcoin.h"
-#include "utiltime.h"
-#include "core_io.h"
-#include "keystore.h"
-#include "policy/policy.h"
+#include <consensus/validation.h>
+#include <key.h>
+#include <validation.h>
+#include <miner.h>
+#include <pubkey.h>
+#include <txmempool.h>
+#include <random.h>
+#include <script/standard.h>
+#include <script/sign.h>
+#include <test/test_bitcoin.h>
+#include <utiltime.h>
+#include <core_io.h>
+#include <keystore.h>
+#include <policy/policy.h>
#include <boost/test/unit_test.hpp>
@@ -66,6 +66,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// Test 1: block with both of those transactions should be rejected.
block = CreateAndProcessBlock(spends, scriptPubKey);
+ LOCK(cs_main);
BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
// Test 2: ... and should be rejected if spend1 is in the memory pool
@@ -119,7 +120,7 @@ void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_fl
// WITNESS requires P2SH
test_flags |= SCRIPT_VERIFY_P2SH;
}
- bool ret = CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, nullptr);
+ bool ret = CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, nullptr);
// CheckInputs should succeed iff test_flags doesn't intersect with
// failing_flags
bool expected_return_value = !(test_flags & failing_flags);
@@ -135,13 +136,13 @@ void ValidateCheckInputsForAllFlags(CMutableTransaction &tx, uint32_t failing_fl
if (ret && add_to_cache) {
// Check that we get a cache hit if the tx was valid
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK(scriptchecks.empty());
} else {
// Check that we get script executions to check, if the transaction
// was invalid, or we didn't add to cache.
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, test_flags, true, add_to_cache, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, test_flags, true, add_to_cache, txdata, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
}
}
@@ -151,7 +152,10 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
{
// Test that passing CheckInputs with one set of script flags doesn't imply
// that we would pass again with a different set of flags.
- InitScriptExecutionCache();
+ {
+ LOCK(cs_main);
+ InitScriptExecutionCache();
+ }
CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey));
@@ -201,13 +205,13 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData ptd_spend_tx(spend_tx);
- BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
+ BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
// If we call again asking for scriptchecks (as happens in
// ConnectBlock), we should add a script check object for this -- we're
// not caching invalidity (if that changes, delete this test case).
std::vector<CScriptCheck> scriptchecks;
- BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
+ BOOST_CHECK(CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
BOOST_CHECK_EQUAL(scriptchecks.size(), 1);
// Test that CheckInputs returns true iff DERSIG-enforcing flags are
@@ -268,7 +272,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
- BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(invalid_with_cltv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
}
// TEST CHECKSEQUENCEVERIFY
@@ -296,7 +300,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
CValidationState state;
PrecomputedTransactionData txdata(invalid_with_csv_tx);
- BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip, true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
+ BOOST_CHECK(CheckInputs(invalid_with_csv_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
}
// TODO: add tests for remaining script flags
@@ -358,12 +362,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
CValidationState state;
PrecomputedTransactionData txdata(tx);
// This transaction is now invalid under segwit, because of the second input.
- BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
+ BOOST_CHECK(!CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
std::vector<CScriptCheck> scriptchecks;
// Make sure this transaction was not cached (ie because the first
// input was valid)
- BOOST_CHECK(CheckInputs(tx, state, pcoinsTip, true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
+ BOOST_CHECK(CheckInputs(tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
// Should get 2 script checks back -- caching is on a whole-transaction basis.
BOOST_CHECK_EQUAL(scriptchecks.size(), 2);
}
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index 70d83a2e54..40ef9adb2e 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,10 +1,10 @@
// Copyright (c) 2011-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 "arith_uint256.h"
-#include "uint256.h"
-#include "version.h"
-#include "test/test_bitcoin.h"
+#include <arith_uint256.h>
+#include <uint256.h>
+#include <version.h>
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
#include <stdint.h>
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index dffe8e55a8..7386204437 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -8,7 +8,7 @@
#include <string>
#include <map>
#include <univalue.h>
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 6ec544290d..998090cd9b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2,14 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
-
-#include "clientversion.h"
-#include "primitives/transaction.h"
-#include "sync.h"
-#include "utilstrencodings.h"
-#include "utilmoneystr.h"
-#include "test/test_bitcoin.h"
+#include <util.h>
+
+#include <clientversion.h>
+#include <primitives/transaction.h>
+#include <sync.h>
+#include <utilstrencodings.h>
+#include <utilmoneystr.h>
+#include <test/test_bitcoin.h>
#include <stdint.h>
#include <vector>
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 882afb2e20..7029b347dd 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -2,12 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "versionbits.h"
-#include "test/test_bitcoin.h"
-#include "chainparams.h"
-#include "validation.h"
-#include "consensus/params.h"
+#include <chain.h>
+#include <versionbits.h>
+#include <test/test_bitcoin.h>
+#include <chainparams.h>
+#include <validation.h>
+#include <consensus/params.h>
#include <boost/test/unit_test.hpp>
@@ -32,6 +32,12 @@ public:
int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }
};
+class TestAlwaysActiveConditionChecker : public TestConditionChecker
+{
+public:
+ int64_t BeginTime(const Consensus::Params& params) const override { return Consensus::BIP9Deployment::ALWAYS_ACTIVE; }
+};
+
#define CHECKERS 6
class VersionBitsTester
@@ -43,6 +49,8 @@ class VersionBitsTester
// The first one performs all checks, the second only 50%, the third only 25%, etc...
// This is to test whether lack of cached information leads to the same results.
TestConditionChecker checker[CHECKERS];
+ // Another 6 that assume always active activation
+ TestAlwaysActiveConditionChecker checker_always[CHECKERS];
// Test counter (to identify failures)
int num;
@@ -56,6 +64,7 @@ public:
}
for (unsigned int i = 0; i < CHECKERS; i++) {
checker[i] = TestConditionChecker();
+ checker_always[i] = TestAlwaysActiveConditionChecker();
}
vpblock.clear();
return *this;
@@ -82,6 +91,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(vpblock.empty() ? nullptr : vpblock.back()) == 0, strprintf("Test %i for StateSinceHeight (always active)", num));
}
}
num++;
@@ -92,6 +102,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_DEFINED, strprintf("Test %i for DEFINED", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -102,6 +113,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_STARTED, strprintf("Test %i for STARTED", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -112,6 +124,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_LOCKED_IN, strprintf("Test %i for LOCKED_IN", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -122,6 +135,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
@@ -132,6 +146,7 @@ public:
for (int i = 0; i < CHECKERS; i++) {
if (InsecureRandBits(i) == 0) {
BOOST_CHECK_MESSAGE(checker[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_FAILED, strprintf("Test %i for FAILED", num));
+ BOOST_CHECK_MESSAGE(checker_always[i].GetStateFor(vpblock.empty() ? nullptr : vpblock.back()) == THRESHOLD_ACTIVE, strprintf("Test %i for ACTIVE (always active)", num));
}
}
num++;
diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp
index 9d691079ed..7bcacc3014 100644
--- a/src/threadinterrupt.cpp
+++ b/src/threadinterrupt.cpp
@@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "threadinterrupt.h"
+#include <threadinterrupt.h>
CThreadInterrupt::operator bool() const
{
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 5113bb60db..b91cf01723 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -3,17 +3,17 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "timedata.h"
+#include <timedata.h>
-#include "netaddress.h"
-#include "sync.h"
-#include "ui_interface.h"
-#include "util.h"
-#include "utilstrencodings.h"
-#include "warnings.h"
+#include <netaddress.h>
+#include <sync.h>
+#include <ui_interface.h>
+#include <util.h>
+#include <utilstrencodings.h>
+#include <warnings.h>
static CCriticalSection cs_nTimeOffset;
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 2e453e56bb..d34cfaa94f 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -495,7 +495,11 @@ namespace detail {
class FormatArg
{
public:
- FormatArg() {}
+ FormatArg()
+ : m_value(nullptr),
+ m_formatImpl(nullptr),
+ m_toIntImpl(nullptr)
+ { }
template<typename T>
explicit FormatArg(const T& value)
@@ -507,11 +511,15 @@ class FormatArg
void format(std::ostream& out, const char* fmtBegin,
const char* fmtEnd, int ntrunc) const
{
+ assert(m_value);
+ assert(m_formatImpl);
m_formatImpl(out, fmtBegin, fmtEnd, ntrunc, m_value);
}
int toInt() const
{
+ assert(m_value);
+ assert(m_toIntImpl);
return m_toIntImpl(m_value);
}
@@ -712,23 +720,27 @@ inline const char* streamStateFromFormat(std::ostream& out, bool& spacePadPositi
break;
case 'X':
out.setf(std::ios::uppercase);
+ // Falls through
case 'x': case 'p':
out.setf(std::ios::hex, std::ios::basefield);
intConversion = true;
break;
case 'E':
out.setf(std::ios::uppercase);
+ // Falls through
case 'e':
out.setf(std::ios::scientific, std::ios::floatfield);
out.setf(std::ios::dec, std::ios::basefield);
break;
case 'F':
out.setf(std::ios::uppercase);
+ // Falls through
case 'f':
out.setf(std::ios::fixed, std::ios::floatfield);
break;
case 'G':
out.setf(std::ios::uppercase);
+ // Falls through
case 'g':
out.setf(std::ios::dec, std::ios::basefield);
// As in boost::format, let stream decide float format.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 1cea197666..46f39d65a0 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -3,12 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "torcontrol.h"
-#include "utilstrencodings.h"
-#include "netbase.h"
-#include "net.h"
-#include "util.h"
-#include "crypto/hmac_sha256.h"
+#include <torcontrol.h>
+#include <utilstrencodings.h>
+#include <netbase.h>
+#include <net.h>
+#include <util.h>
+#include <crypto/hmac_sha256.h>
#include <vector>
#include <deque>
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 72dc82c5b1..a01eeefeb8 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -8,7 +8,7 @@
#ifndef BITCOIN_TORCONTROL_H
#define BITCOIN_TORCONTROL_H
-#include "scheduler.h"
+#include <scheduler.h>
extern const std::string DEFAULT_TOR_CONTROL;
static const bool DEFAULT_LISTEN_ONION = true;
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 134bb8721b..7a8e854b55 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -3,16 +3,16 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "txdb.h"
-
-#include "chainparams.h"
-#include "hash.h"
-#include "random.h"
-#include "pow.h"
-#include "uint256.h"
-#include "util.h"
-#include "ui_interface.h"
-#include "init.h"
+#include <txdb.h>
+
+#include <chainparams.h>
+#include <hash.h>
+#include <random.h>
+#include <pow.h>
+#include <uint256.h>
+#include <util.h>
+#include <ui_interface.h>
+#include <init.h>
#include <stdint.h>
diff --git a/src/txdb.h b/src/txdb.h
index ec9f571b13..2e8095e3cd 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -6,9 +6,9 @@
#ifndef BITCOIN_TXDB_H
#define BITCOIN_TXDB_H
-#include "coins.h"
-#include "dbwrapper.h"
-#include "chain.h"
+#include <coins.h>
+#include <dbwrapper.h>
+#include <chain.h>
#include <map>
#include <string>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index b0306811cb..392323808f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -3,20 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "txmempool.h"
-
-#include "consensus/consensus.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "validation.h"
-#include "policy/policy.h"
-#include "policy/fees.h"
-#include "reverse_iterator.h"
-#include "streams.h"
-#include "timedata.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utiltime.h"
+#include <txmempool.h>
+
+#include <consensus/consensus.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <validation.h>
+#include <policy/policy.h>
+#include <policy/fees.h>
+#include <reverse_iterator.h>
+#include <streams.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utiltime.h>
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, unsigned int _entryHeight,
@@ -317,7 +317,7 @@ void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, CAmount modifyFe
assert(int64_t(nCountWithDescendants) > 0);
}
-void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps)
+void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps)
{
nSizeWithAncestors += modifySize;
assert(int64_t(nSizeWithAncestors) > 0);
diff --git a/src/txmempool.h b/src/txmempool.h
index 929d223588..346585ab11 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -13,13 +13,13 @@
#include <utility>
#include <string>
-#include "amount.h"
-#include "coins.h"
-#include "indirectmap.h"
-#include "policy/feerate.h"
-#include "primitives/transaction.h"
-#include "sync.h"
-#include "random.h"
+#include <amount.h>
+#include <coins.h>
+#include <indirectmap.h>
+#include <policy/feerate.h>
+#include <primitives/transaction.h>
+#include <sync.h>
+#include <random.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
@@ -109,7 +109,7 @@ public:
// Adjusts the descendant state.
void UpdateDescendantState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
// Adjusts the ancestor state
- void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int modifySigOps);
+ void UpdateAncestorState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount, int64_t modifySigOps);
// Updates the fee delta used for mining priority score, and the
// modified fees with descendants.
void UpdateFeeDelta(int64_t feeDelta);
@@ -513,6 +513,9 @@ public:
// 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.
+ // Note that addUnchecked is ONLY called from ATMP outside of tests
+ // and any other callers may break wallet's in-mempool tracking (due to
+ // lack of CValidationInterface::TransactionAddedToMempool callbacks).
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true);
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index 74a13e0e05..c0f7defa46 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "ui_interface.h"
-#include "util.h"
+#include <ui_interface.h>
+#include <util.h>
CClientUIInterface uiInterface;
diff --git a/src/uint256.cpp b/src/uint256.cpp
index 736a0d4fe2..b7255231c1 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "uint256.h"
+#include <uint256.h>
-#include "utilstrencodings.h"
+#include <utilstrencodings.h>
#include <stdio.h>
#include <string.h>
diff --git a/src/uint256.h b/src/uint256.h
index 94a4f7fc30..e45c990dae 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -12,14 +12,14 @@
#include <stdint.h>
#include <string>
#include <vector>
-#include "crypto/common.h"
+#include <crypto/common.h>
/** Template base class for fixed-sized opaque blobs. */
template<unsigned int BITS>
class base_blob
{
protected:
- enum { WIDTH=BITS/8 };
+ static constexpr int WIDTH = BITS / 8;
uint8_t data[WIDTH];
public:
base_blob()
diff --git a/src/undo.h b/src/undo.h
index a720de4ac5..b482fd3089 100644
--- a/src/undo.h
+++ b/src/undo.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_UNDO_H
#define BITCOIN_UNDO_H
-#include "compressor.h"
-#include "consensus/consensus.h"
-#include "primitives/transaction.h"
-#include "serialize.h"
+#include <compressor.h>
+#include <consensus/consensus.h>
+#include <primitives/transaction.h>
+#include <serialize.h>
/** Undo information for a CTxIn
*
diff --git a/src/util.cpp b/src/util.cpp
index 51ccc94787..b87dd091be 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -4,17 +4,17 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "util.h"
+#include <util.h>
-#include "chainparamsbase.h"
-#include "fs.h"
-#include "random.h"
-#include "serialize.h"
-#include "utilstrencodings.h"
-#include "utiltime.h"
+#include <chainparamsbase.h>
+#include <fs.h>
+#include <random.h>
+#include <serialize.h>
+#include <utilstrencodings.h>
+#include <utiltime.h>
#include <stdarg.h>
diff --git a/src/util.h b/src/util.h
index 480a80c0a3..be5c99567d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -11,14 +11,14 @@
#define BITCOIN_UTIL_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "compat.h"
-#include "fs.h"
-#include "sync.h"
-#include "tinyformat.h"
-#include "utiltime.h"
+#include <compat.h>
+#include <fs.h>
+#include <sync.h>
+#include <tinyformat.h>
+#include <utiltime.h>
#include <atomic>
#include <exception>
@@ -326,4 +326,11 @@ template <typename Callable> void TraceThread(const char* name, Callable func)
std::string CopyrightHolders(const std::string& strPrefix);
+//! Substitute for C++14 std::make_unique.
+template <typename T, typename... Args>
+std::unique_ptr<T> MakeUnique(Args&&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
#endif // BITCOIN_UTIL_H
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 6e6e33184e..656d7c51b7 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -3,11 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilmoneystr.h"
+#include <utilmoneystr.h>
-#include "primitives/transaction.h"
-#include "tinyformat.h"
-#include "utilstrencodings.h"
+#include <primitives/transaction.h>
+#include <tinyformat.h>
+#include <utilstrencodings.h>
std::string FormatMoney(const CAmount& n)
{
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
index bc885ee167..b1a4499e90 100644
--- a/src/utilmoneystr.h
+++ b/src/utilmoneystr.h
@@ -12,7 +12,7 @@
#include <stdint.h>
#include <string>
-#include "amount.h"
+#include <amount.h>
/* Do not use these functions to represent or parse monetary amounts to or from
* JSON but use AmountFromValue and ValueFromAmount for that.
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 741680e93f..d90713ed6a 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -3,9 +3,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "utilstrencodings.h"
+#include <utilstrencodings.h>
-#include "tinyformat.h"
+#include <tinyformat.h>
#include <cstdlib>
#include <cstring>
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index 4cc77dbfeb..ca11cf341f 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -4,10 +4,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "utiltime.h"
+#include <utiltime.h>
#include <atomic>
diff --git a/src/validation.cpp b/src/validation.cpp
index a073e3d1c0..99ea1433f9 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -3,44 +3,44 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "validation.h"
-
-#include "arith_uint256.h"
-#include "chain.h"
-#include "chainparams.h"
-#include "checkpoints.h"
-#include "checkqueue.h"
-#include "consensus/consensus.h"
-#include "consensus/merkle.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "cuckoocache.h"
-#include "fs.h"
-#include "hash.h"
-#include "init.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "pow.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "random.h"
-#include "reverse_iterator.h"
-#include "script/script.h"
-#include "script/sigcache.h"
-#include "script/standard.h"
-#include "timedata.h"
-#include "tinyformat.h"
-#include "txdb.h"
-#include "txmempool.h"
-#include "ui_interface.h"
-#include "undo.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
-#include "versionbits.h"
-#include "warnings.h"
+#include <validation.h>
+
+#include <arith_uint256.h>
+#include <chain.h>
+#include <chainparams.h>
+#include <checkpoints.h>
+#include <checkqueue.h>
+#include <consensus/consensus.h>
+#include <consensus/merkle.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <cuckoocache.h>
+#include <fs.h>
+#include <hash.h>
+#include <init.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <pow.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <random.h>
+#include <reverse_iterator.h>
+#include <script/script.h>
+#include <script/sigcache.h>
+#include <script/standard.h>
+#include <timedata.h>
+#include <tinyformat.h>
+#include <txdb.h>
+#include <txmempool.h>
+#include <ui_interface.h>
+#include <undo.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
+#include <versionbits.h>
+#include <warnings.h>
#include <atomic>
#include <sstream>
@@ -156,6 +156,26 @@ namespace {
/** chainwork for the last block that preciousblock has been applied to. */
arith_uint256 nLastPreciousChainwork = 0;
+ /** In order to efficiently track invalidity of headers, we keep the set of
+ * blocks which we tried to connect and found to be invalid here (ie which
+ * were set to BLOCK_FAILED_VALID since the last restart). We can then
+ * walk this set and check if a new header is a descendant of something in
+ * this set, preventing us from having to walk mapBlockIndex when we try
+ * to connect a bad block and fail.
+ *
+ * While this is more complicated than marking everything which descends
+ * from an invalid block as invalid at the time we discover it to be
+ * invalid, doing so would require walking all of mapBlockIndex to find all
+ * descendants. Since this case should be very rare, keeping track of all
+ * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
+ * well.
+ *
+ * Because we already walk mapBlockIndex in height-order at startup, we go
+ * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
+ * instead of putting things in this set.
+ */
+ std::set<CBlockIndex*> g_failed_blocks;
+
/** Dirty block index entries. */
std::set<CBlockIndex*> setDirtyBlockIndex;
@@ -181,9 +201,9 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
return chain.Genesis();
}
-CCoinsViewDB *pcoinsdbview = nullptr;
-CCoinsViewCache *pcoinsTip = nullptr;
-CBlockTreeDB *pblocktree = nullptr;
+std::unique_ptr<CCoinsViewDB> pcoinsdbview;
+std::unique_ptr<CCoinsViewCache> pcoinsTip;
+std::unique_ptr<CBlockTreeDB> pblocktree;
enum FlushStateMode {
FLUSH_STATE_NONE,
@@ -275,7 +295,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool
}
else {
// pcoinsTip contains the UTXO set for chainActive.Tip()
- CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
@@ -404,7 +424,7 @@ void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool, bool f
mempool.UpdateTransactionsFromBlock(vHashUpdate);
// We also need to remove any now-immature transactions
- mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ mempool.removeForReorg(pcoinsTip.get(), chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
// Re-limit mempool size, in case we added any transactions
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
}
@@ -537,7 +557,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
LockPoints lp;
{
LOCK(pool.cs);
- CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
+ CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
view.SetBackend(viewMemPool);
// do all inputs exist?
@@ -939,6 +959,9 @@ bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus
return error("%s: txid mismatch", __func__);
return true;
}
+
+ // transaction not found in index, nothing more can be done
+ return false;
}
if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it
@@ -1177,6 +1200,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
+ g_failed_blocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
setBlockIndexCandidates.erase(pindex);
InvalidChainFound(pindex);
@@ -1587,11 +1611,12 @@ static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS];
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) {
AssertLockHeld(cs_main);
- // BIP16 didn't become active until Apr 1 2012
- int64_t nBIP16SwitchTime = 1333238400;
- bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime);
+ unsigned int flags = SCRIPT_VERIFY_NONE;
- unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
+ // Start enforcing P2SH (BIP16)
+ if (pindex->nHeight >= consensusparams.BIP16Height) {
+ flags |= SCRIPT_VERIFY_P2SH;
+ }
// Start enforcing the DERSIG (BIP66) rule
if (pindex->nHeight >= consensusparams.BIP66Height) {
@@ -2080,7 +2105,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
- CCoinsViewCache view(pcoinsTip);
+ CCoinsViewCache view(pcoinsTip.get());
assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
@@ -2210,7 +2235,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
int64_t nTime3;
LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
{
- CCoinsViewCache view(pcoinsTip);
+ CCoinsViewCache view(pcoinsTip.get());
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams);
GetMainSignals().BlockChecked(blockConnecting, state);
if (!rv) {
@@ -2388,7 +2413,7 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
// any disconnected transactions back to the mempool.
UpdateMempoolForReorg(disconnectpool, true);
}
- mempool.check(pcoinsTip);
+ mempool.check(pcoinsTip.get());
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
@@ -2469,7 +2494,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
assert(trace.pblock && trace.pindex);
- GetMainSignals().BlockConnected(trace.pblock, trace.pindex, *trace.conflictedTxs);
+ GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
}
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
@@ -2530,17 +2555,18 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
{
AssertLockHeld(cs_main);
- // Mark the block itself as invalid.
- pindex->nStatus |= BLOCK_FAILED_VALID;
- setDirtyBlockIndex.insert(pindex);
- setBlockIndexCandidates.erase(pindex);
+ // We first disconnect backwards and then mark the blocks as invalid.
+ // This prevents a case where pruned nodes may fail to invalidateblock
+ // and be left unable to start as they have no tip candidates (as there
+ // are no blocks that meet the "have data and are not invalid per
+ // nStatus" criteria for inclusion in setBlockIndexCandidates).
+
+ bool pindex_was_in_chain = false;
+ CBlockIndex *invalid_walk_tip = chainActive.Tip();
DisconnectedBlockTransactions disconnectpool;
while (chainActive.Contains(pindex)) {
- CBlockIndex *pindexWalk = chainActive.Tip();
- pindexWalk->nStatus |= BLOCK_FAILED_CHILD;
- setDirtyBlockIndex.insert(pindexWalk);
- setBlockIndexCandidates.erase(pindexWalk);
+ pindex_was_in_chain = true;
// ActivateBestChain considers blocks already in chainActive
// unconditionally valid already, so force disconnect away from it.
if (!DisconnectTip(state, chainparams, &disconnectpool)) {
@@ -2551,6 +2577,21 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
}
}
+ // Now mark the blocks we just disconnected as descendants invalid
+ // (note this may not be all descendants).
+ while (pindex_was_in_chain && invalid_walk_tip != pindex) {
+ invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(invalid_walk_tip);
+ setBlockIndexCandidates.erase(invalid_walk_tip);
+ invalid_walk_tip = invalid_walk_tip->pprev;
+ }
+
+ // Mark the block itself as invalid.
+ pindex->nStatus |= BLOCK_FAILED_VALID;
+ setDirtyBlockIndex.insert(pindex);
+ setBlockIndexCandidates.erase(pindex);
+ g_failed_blocks.insert(pindex);
+
// DisconnectTip will add transactions to disconnectpool; try to add these
// back to the mempool.
UpdateMempoolForReorg(disconnectpool, true);
@@ -2588,6 +2629,7 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
// Reset invalid block marker if it was pointing to one of those.
pindexBestInvalid = nullptr;
}
+ g_failed_blocks.erase(it->second);
}
it++;
}
@@ -2613,7 +2655,6 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
// Construct new block index object
CBlockIndex* pindexNew = new CBlockIndex(block);
- assert(pindexNew);
// We assign the sequence id to blocks only when the full data is available,
// to avoid miners withholding blocks but broadcasting headers, to get a
// competitive advantage.
@@ -3064,6 +3105,21 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
+
+ if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
+ for (const CBlockIndex* failedit : g_failed_blocks) {
+ if (pindexPrev->GetAncestor(failedit->nHeight) == failedit) {
+ assert(failedit->nStatus & BLOCK_FAILED_VALID);
+ CBlockIndex* invalid_walk = pindexPrev;
+ while (invalid_walk != failedit) {
+ invalid_walk->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(invalid_walk);
+ invalid_walk = invalid_walk->pprev;
+ }
+ return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
+ }
+ }
+ }
}
if (pindex == nullptr)
pindex = AddToBlockIndex(block);
@@ -3077,13 +3133,15 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
}
// Exposed wrapper for AcceptBlockHeader
-bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
+bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid)
{
+ if (first_invalid != nullptr) first_invalid->SetNull();
{
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
if (!AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ if (first_invalid) *first_invalid = header;
return false;
}
if (ppindex) {
@@ -3113,7 +3171,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
// process an unrequested block if it's new and has enough work to
// advance our tip, and isn't too many blocks ahead.
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
- bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
+ bool fHasMoreOrSameWork = (chainActive.Tip() ? pindex->nChainWork >= chainActive.Tip()->nChainWork : true);
// Blocks that are too out-of-order needlessly limit the effectiveness of
// pruning, because pruning will not delete block files that contain any
// blocks which are too close in height to the tip. Apply this test
@@ -3130,9 +3188,15 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
// and unrequested blocks.
if (fAlreadyHave) return true;
if (!fRequested) { // If we didn't ask for it:
- if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
- if (!fHasMoreWork) return true; // Don't process less-work chains
- if (fTooFarAhead) return true; // Block height is too high
+ if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
+ if (!fHasMoreOrSameWork) return true; // Don't process less-work chains
+ if (fTooFarAhead) return true; // Block height is too high
+
+ // Protect against DoS attacks from low-work chains.
+ // If our tip is behind, a peer could try to send us
+ // low-work blocks on a fake chain that we would never
+ // request; don't process these.
+ if (pindex->nChainWork < nMinimumChainWork) return true;
}
if (fNewBlock) *fNewBlock = true;
@@ -3211,7 +3275,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
{
AssertLockHeld(cs_main);
assert(pindexPrev && pindexPrev == chainActive.Tip());
- CCoinsViewCache viewNew(pcoinsTip);
+ CCoinsViewCache viewNew(pcoinsTip.get());
CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1;
@@ -3443,8 +3507,6 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
// Create new
CBlockIndex* pindexNew = new CBlockIndex();
- if (!pindexNew)
- throw std::runtime_error(std::string(__func__) + ": new CBlockIndex failed");
mi = mapBlockIndex.insert(std::make_pair(hash, pindexNew)).first;
pindexNew->phashBlock = &((*mi).first);
@@ -3486,6 +3548,10 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
pindex->nChainTx = pindex->nTx;
}
}
+ if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) {
+ pindex->nStatus |= BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(pindex);
+ }
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == nullptr))
setBlockIndexCandidates.insert(pindex);
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork))
@@ -3876,6 +3942,7 @@ void UnloadBlockIndex()
nLastBlockFile = 0;
nBlockSequenceId = 1;
setDirtyBlockIndex.clear();
+ g_failed_blocks.clear();
setDirtyFileInfo.clear();
versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
@@ -4290,8 +4357,9 @@ bool LoadMempool(void)
}
int64_t count = 0;
- int64_t skipped = 0;
+ int64_t expired = 0;
int64_t failed = 0;
+ int64_t already_there = 0;
int64_t nNow = GetTime();
try {
@@ -4322,10 +4390,18 @@ bool LoadMempool(void)
if (state.IsValid()) {
++count;
} else {
- ++failed;
+ // mempool may contain the transaction already, e.g. from
+ // wallet(s) having loaded it while we were processing
+ // mempool transactions; consider these as valid, instead of
+ // failed, but mark them as 'already there'
+ if (mempool.exists(tx->GetHash())) {
+ ++already_there;
+ } else {
+ ++failed;
+ }
}
} else {
- ++skipped;
+ ++expired;
}
if (ShutdownRequested())
return false;
@@ -4341,7 +4417,7 @@ bool LoadMempool(void)
return false;
}
- LogPrintf("Imported mempool transactions from disk: %i successes, %i failed, %i expired\n", count, failed, skipped);
+ LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there\n", count, failed, expired, already_there);
return true;
}
diff --git a/src/validation.h b/src/validation.h
index 6bc52753c5..254f3e0754 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -7,17 +7,17 @@
#define BITCOIN_VALIDATION_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
-#include "amount.h"
-#include "coins.h"
-#include "fs.h"
-#include "protocol.h" // For CMessageHeader::MessageStartChars
-#include "policy/feerate.h"
-#include "script/script_error.h"
-#include "sync.h"
-#include "versionbits.h"
+#include <amount.h>
+#include <coins.h>
+#include <fs.h>
+#include <protocol.h> // For CMessageHeader::MessageStartChars
+#include <policy/feerate.h>
+#include <script/script_error.h>
+#include <sync.h>
+#include <versionbits.h>
#include <algorithm>
#include <exception>
@@ -247,8 +247,9 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
* @param[out] state This may be set to an Error state if any error occurred processing them
* @param[in] chainparams The params for the chain we want to connect to
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
+ * @param[out] first_invalid First header that fails validation, if one exists
*/
-bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr);
+bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex=nullptr, CBlockHeader *first_invalid=nullptr);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
@@ -443,13 +444,13 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex);
extern CChain chainActive;
/** Global variable that points to the coins database (protected by cs_main) */
-extern CCoinsViewDB *pcoinsdbview;
+extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
/** Global variable that points to the active CCoinsView (protected by cs_main) */
-extern CCoinsViewCache *pcoinsTip;
+extern std::unique_ptr<CCoinsViewCache> pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
-extern CBlockTreeDB *pblocktree;
+extern std::unique_ptr<CBlockTreeDB> pblocktree;
/**
* Return the spend height, which is one more than the inputs.GetBestBlock().
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 281bc04b0a..5ceba17e06 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -3,13 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "validationinterface.h"
+#include <validationinterface.h>
-#include "init.h"
-#include "primitives/block.h"
-#include "scheduler.h"
-#include "sync.h"
-#include "util.h"
+#include <init.h>
+#include <primitives/block.h>
+#include <scheduler.h>
+#include <sync.h>
+#include <txmempool.h>
+#include <util.h>
#include <list>
#include <atomic>
@@ -21,6 +22,7 @@ struct MainSignalsInstance {
boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
+ boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
boost::signals2::signal<void (const uint256 &)> Inventory;
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
@@ -50,6 +52,14 @@ void CMainSignals::FlushBackgroundCallbacks() {
m_internals->m_schedulerClient.EmptyQueue();
}
+void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
+ pool.NotifyEntryRemoved.connect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
+}
+
+void CMainSignals::UnregisterWithMempoolSignals(CTxMemPool& pool) {
+ pool.NotifyEntryRemoved.disconnect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
+}
+
CMainSignals& GetMainSignals()
{
return g_signals;
@@ -60,6 +70,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
@@ -75,6 +86,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
+ g_signals.m_internals->TransactionRemovedFromMempool.disconnect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
g_signals.m_internals->UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
g_signals.m_internals->NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
}
@@ -87,32 +99,57 @@ void UnregisterAllValidationInterfaces() {
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
g_signals.m_internals->BlockConnected.disconnect_all_slots();
g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
+ g_signals.m_internals->TransactionRemovedFromMempool.disconnect_all_slots();
g_signals.m_internals->UpdatedBlockTip.disconnect_all_slots();
g_signals.m_internals->NewPoWValidBlock.disconnect_all_slots();
}
+void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
+ g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
+}
+
+void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason reason) {
+ if (reason != MemPoolRemovalReason::BLOCK && reason != MemPoolRemovalReason::CONFLICT) {
+ m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
+ m_internals->TransactionRemovedFromMempool(ptx);
+ });
+ }
+}
+
void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
- m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
+ m_internals->m_schedulerClient.AddToProcessQueue([pindexNew, pindexFork, fInitialDownload, this] {
+ m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
+ });
}
void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
- m_internals->TransactionAddedToMempool(ptx);
+ m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
+ m_internals->TransactionAddedToMempool(ptx);
+ });
}
-void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
- m_internals->BlockConnected(pblock, pindex, vtxConflicted);
+void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>>& pvtxConflicted) {
+ m_internals->m_schedulerClient.AddToProcessQueue([pblock, pindex, pvtxConflicted, this] {
+ m_internals->BlockConnected(pblock, pindex, *pvtxConflicted);
+ });
}
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock) {
- m_internals->BlockDisconnected(pblock);
+ m_internals->m_schedulerClient.AddToProcessQueue([pblock, this] {
+ m_internals->BlockDisconnected(pblock);
+ });
}
void CMainSignals::SetBestChain(const CBlockLocator &locator) {
- m_internals->SetBestChain(locator);
+ m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
+ m_internals->SetBestChain(locator);
+ });
}
void CMainSignals::Inventory(const uint256 &hash) {
- m_internals->Inventory(hash);
+ m_internals->m_schedulerClient.AddToProcessQueue([hash, this] {
+ m_internals->Inventory(hash);
+ });
}
void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
diff --git a/src/validationinterface.h b/src/validationinterface.h
index d6da2bc1fd..7b5d138414 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -6,9 +6,10 @@
#ifndef BITCOIN_VALIDATIONINTERFACE_H
#define BITCOIN_VALIDATIONINTERFACE_H
-#include <memory>
+#include <primitives/transaction.h> // CTransaction(Ref)
-#include "primitives/transaction.h" // CTransaction(Ref)
+#include <functional>
+#include <memory>
class CBlock;
class CBlockIndex;
@@ -20,6 +21,8 @@ class CValidationInterface;
class CValidationState;
class uint256;
class CScheduler;
+class CTxMemPool;
+enum class MemPoolRemovalReason;
// These functions dispatch to one or all registered wallets
@@ -29,23 +32,66 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn);
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister all wallets from core */
void UnregisterAllValidationInterfaces();
+/**
+ * Pushes a function to callback onto the notification queue, guaranteeing any
+ * callbacks generated prior to now are finished when the function is called.
+ *
+ * Be very careful blocking on func to be called if any locks are held -
+ * validation interface clients may not be able to make progress as they often
+ * wait for things like cs_main, so blocking until func is called with cs_main
+ * will result in a deadlock (that DEBUG_LOCKORDER will miss).
+ */
+void CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
class CValidationInterface {
protected:
- /** Notifies listeners of updated block chain tip */
+ /**
+ * Notifies listeners of updated block chain tip
+ *
+ * Called on a background thread.
+ */
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
- /** Notifies listeners of a transaction having been added to mempool. */
+ /**
+ * Notifies listeners of a transaction having been added to mempool.
+ *
+ * Called on a background thread.
+ */
virtual void TransactionAddedToMempool(const CTransactionRef &ptxn) {}
/**
+ * Notifies listeners of a transaction leaving mempool.
+ *
+ * This only fires for transactions which leave mempool because of expiry,
+ * size limiting, reorg (changes in lock times/coinbase maturity), or
+ * replacement. This does not include any transactions which are included
+ * in BlockConnectedDisconnected either in block->vtx or in txnConflicted.
+ *
+ * Called on a background thread.
+ */
+ virtual void TransactionRemovedFromMempool(const CTransactionRef &ptx) {}
+ /**
* Notifies listeners of a block being connected.
* Provides a vector of transactions evicted from the mempool as a result.
+ *
+ * Called on a background thread.
*/
virtual void BlockConnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex *pindex, const std::vector<CTransactionRef> &txnConflicted) {}
- /** Notifies listeners of a block being disconnected */
+ /**
+ * Notifies listeners of a block being disconnected
+ *
+ * Called on a background thread.
+ */
virtual void BlockDisconnected(const std::shared_ptr<const CBlock> &block) {}
- /** Notifies listeners of the new active block chain on-disk. */
+ /**
+ * Notifies listeners of the new active block chain on-disk.
+ *
+ * Called on a background thread.
+ */
virtual void SetBestChain(const CBlockLocator &locator) {}
- /** Notifies listeners about an inventory item being seen on the network. */
+ /**
+ * Notifies listeners about an inventory item being seen on the network.
+ *
+ * Called on a background thread.
+ */
virtual void Inventory(const uint256 &hash) {}
/** Tells listeners to broadcast their data. */
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
@@ -73,6 +119,9 @@ private:
friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*);
friend void ::UnregisterAllValidationInterfaces();
+ friend void ::CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
+
+ void MempoolEntryRemoved(CTransactionRef tx, MemPoolRemovalReason reason);
public:
/** Register a CScheduler to give callbacks which should run in the background (may only be called once) */
@@ -82,9 +131,14 @@ public:
/** Call any remaining callbacks on the calling thread */
void FlushBackgroundCallbacks();
+ /** Register with mempool to call TransactionRemovedFromMempool callbacks */
+ void RegisterWithMempoolSignals(CTxMemPool& pool);
+ /** Unregister with mempool */
+ void UnregisterWithMempoolSignals(CTxMemPool& pool);
+
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
void TransactionAddedToMempool(const CTransactionRef &);
- void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef> &);
+ void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
void SetBestChain(const CBlockLocator &);
void Inventory(const uint256 &);
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index 64ae939672..3bd00ccb23 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "versionbits.h"
-#include "consensus/params.h"
+#include <versionbits.h>
+#include <consensus/params.h>
const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
@@ -27,6 +27,11 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
int64_t nTimeStart = BeginTime(params);
int64_t nTimeTimeout = EndTime(params);
+ // Check if this deployment is always active.
+ if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
+ return THRESHOLD_ACTIVE;
+ }
+
// A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
if (pindexPrev != nullptr) {
pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
@@ -136,6 +141,11 @@ BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockI
int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
{
+ int64_t start_time = BeginTime(params);
+ if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
+ return 0;
+ }
+
const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
// BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
diff --git a/src/versionbits.h b/src/versionbits.h
index 71dc0c8500..0e111ed7a1 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_CONSENSUS_VERSIONBITS
#define BITCOIN_CONSENSUS_VERSIONBITS
-#include "chain.h"
+#include <chain.h>
#include <map>
/** What block version to use for new blocks (pre versionbits) */
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index fc0e7c519e..15fd105779 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -5,10 +5,10 @@
#ifndef BITCOIN_WALLET_COINCONTROL_H
#define BITCOIN_WALLET_COINCONTROL_H
-#include "policy/feerate.h"
-#include "policy/fees.h"
-#include "primitives/transaction.h"
-#include "wallet/wallet.h"
+#include <policy/feerate.h>
+#include <policy/fees.h>
+#include <primitives/transaction.h>
+#include <wallet/wallet.h>
#include <boost/optional.hpp>
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index 8db3bfd69c..4cd7db048b 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "crypter.h"
+#include <wallet/crypter.h>
-#include "crypto/aes.h"
-#include "crypto/sha512.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "util.h"
+#include <crypto/aes.h>
+#include <crypto/sha512.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <util.h>
#include <string>
#include <vector>
@@ -152,6 +152,15 @@ bool CCryptoKeyStore::SetCrypted()
return true;
}
+bool CCryptoKeyStore::IsLocked() const
+{
+ if (!IsCrypted()) {
+ return false;
+ }
+ LOCK(cs_KeyStore);
+ return vMasterKey.empty();
+}
+
bool CCryptoKeyStore::Lock()
{
if (!SetCrypted())
@@ -206,21 +215,23 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::AddKeyPubKey(key, pubkey);
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::AddKeyPubKey(key, pubkey);
+ }
- if (IsLocked())
- return false;
+ if (IsLocked()) {
+ return false;
+ }
- std::vector<unsigned char> vchCryptedSecret;
- CKeyingMaterial vchSecret(key.begin(), key.end());
- if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret))
- return false;
+ std::vector<unsigned char> vchCryptedSecret;
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) {
+ return false;
+ }
- if (!AddCryptedKey(pubkey, vchCryptedSecret))
- return false;
+ if (!AddCryptedKey(pubkey, vchCryptedSecret)) {
+ return false;
}
return true;
}
@@ -228,72 +239,88 @@ bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
- {
- LOCK(cs_KeyStore);
- if (!SetCrypted())
- return false;
-
- mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
+ LOCK(cs_KeyStore);
+ if (!SetCrypted()) {
+ return false;
}
+
+ mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret);
return true;
}
+bool CCryptoKeyStore::HaveKey(const CKeyID &address) const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::HaveKey(address);
+ }
+ return mapCryptedKeys.count(address) > 0;
+}
+
bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const
{
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::GetKey(address, keyOut);
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::GetKey(address, keyOut);
+ }
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- const CPubKey &vchPubKey = (*mi).second.first;
- const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
- return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
- }
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
+ {
+ const CPubKey &vchPubKey = (*mi).second.first;
+ const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
+ return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut);
}
return false;
}
bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted())
+ return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+
+ CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
+ if (mi != mapCryptedKeys.end())
{
- LOCK(cs_KeyStore);
- if (!IsCrypted())
- return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+ vchPubKeyOut = (*mi).second.first;
+ return true;
+ }
+ // Check for watch-only pubkeys
+ return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+}
- CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
- if (mi != mapCryptedKeys.end())
- {
- vchPubKeyOut = (*mi).second.first;
- return true;
- }
- // Check for watch-only pubkeys
- return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
+std::set<CKeyID> CCryptoKeyStore::GetKeys() const
+{
+ LOCK(cs_KeyStore);
+ if (!IsCrypted()) {
+ return CBasicKeyStore::GetKeys();
}
+ std::set<CKeyID> set_address;
+ for (const auto& mi : mapCryptedKeys) {
+ set_address.insert(mi.first);
+ }
+ return set_address;
}
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
+ LOCK(cs_KeyStore);
+ if (!mapCryptedKeys.empty() || IsCrypted())
+ return false;
+
+ fUseCrypto = true;
+ for (KeyMap::value_type& mKey : mapKeys)
{
- LOCK(cs_KeyStore);
- if (!mapCryptedKeys.empty() || IsCrypted())
+ const CKey &key = mKey.second;
+ CPubKey vchPubKey = key.GetPubKey();
+ CKeyingMaterial vchSecret(key.begin(), key.end());
+ std::vector<unsigned char> vchCryptedSecret;
+ if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
+ return false;
+ if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
-
- fUseCrypto = true;
- for (KeyMap::value_type& mKey : mapKeys)
- {
- const CKey &key = mKey.second;
- CPubKey vchPubKey = key.GetPubKey();
- CKeyingMaterial vchSecret(key.begin(), key.end());
- std::vector<unsigned char> vchCryptedSecret;
- if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret))
- return false;
- if (!AddCryptedKey(vchPubKey, vchCryptedSecret))
- return false;
- }
- mapKeys.clear();
}
+ mapKeys.clear();
return true;
}
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index 1416ae7d02..7b0936ba0d 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -5,9 +5,9 @@
#ifndef BITCOIN_WALLET_CRYPTER_H
#define BITCOIN_WALLET_CRYPTER_H
-#include "keystore.h"
-#include "serialize.h"
-#include "support/allocators/secure.h"
+#include <keystore.h>
+#include <serialize.h>
+#include <support/allocators/secure.h>
#include <atomic>
@@ -139,52 +139,16 @@ public:
{
}
- bool IsCrypted() const
- {
- return fUseCrypto;
- }
-
- bool IsLocked() const
- {
- if (!IsCrypted())
- return false;
- bool result;
- {
- LOCK(cs_KeyStore);
- result = vMasterKey.empty();
- }
- return result;
- }
-
+ bool IsCrypted() const { return fUseCrypto; }
+ bool IsLocked() const;
bool Lock();
virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override;
- bool HaveKey(const CKeyID &address) const override
- {
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted()) {
- return CBasicKeyStore::HaveKey(address);
- }
- return mapCryptedKeys.count(address) > 0;
- }
- return false;
- }
+ bool HaveKey(const CKeyID &address) const override;
bool GetKey(const CKeyID &address, CKey& keyOut) const override;
bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;
- std::set<CKeyID> GetKeys() const override
- {
- LOCK(cs_KeyStore);
- if (!IsCrypted()) {
- return CBasicKeyStore::GetKeys();
- }
- std::set<CKeyID> set_address;
- for (const auto& mi : mapCryptedKeys) {
- set_address.insert(mi.first);
- }
- return set_address;
- }
+ std::set<CKeyID> GetKeys() const override;
/**
* Wallet status (encrypted, locked) changed.
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index d66ba48421..c6fd95f250 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "db.h"
+#include <wallet/db.h>
-#include "addrman.h"
-#include "fs.h"
-#include "hash.h"
-#include "protocol.h"
-#include "util.h"
-#include "utilstrencodings.h"
+#include <addrman.h>
+#include <fs.h>
+#include <hash.h>
+#include <protocol.h>
+#include <util.h>
+#include <utilstrencodings.h>
#include <stdint.h>
@@ -20,6 +20,40 @@
#include <boost/thread.hpp>
+namespace {
+//! Make sure database has a unique fileid within the environment. If it
+//! doesn't, throw an error. BDB caches do not work properly when more than one
+//! open database has the same fileid (values written to one database may show
+//! up in reads to other databases).
+//!
+//! BerkeleyDB generates unique fileids by default
+//! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html),
+//! so bitcoin should never create different databases with the same fileid, but
+//! this error can be triggered if users manually copy database files.
+void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db)
+{
+ if (env.IsMock()) return;
+
+ u_int8_t fileid[DB_FILE_ID_LEN];
+ int ret = db.get_mpf()->get_fileid(fileid);
+ if (ret != 0) {
+ throw std::runtime_error(strprintf("CDB: Can't open database %s (get_fileid failed with %d)", filename, ret));
+ }
+
+ for (const auto& item : env.mapDb) {
+ u_int8_t item_fileid[DB_FILE_ID_LEN];
+ if (item.second && item.second->get_mpf()->get_fileid(item_fileid) == 0 &&
+ memcmp(fileid, item_fileid, sizeof(fileid)) == 0) {
+ const char* item_filename = nullptr;
+ item.second->get_dbname(&item_filename, nullptr);
+ throw std::runtime_error(strprintf("CDB: Can't open database %s (duplicates fileid %s from %s)", filename,
+ HexStr(std::begin(item_fileid), std::end(item_fileid)),
+ item_filename ? item_filename : "(unknown database)"));
+ }
+ }
+}
+} // namespace
+
//
// CDB
//
@@ -41,13 +75,12 @@ void CDBEnv::EnvShutdown()
void CDBEnv::Reset()
{
- delete dbenv;
- dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
+ dbenv.reset(new DbEnv(DB_CXX_NO_EXCEPTIONS));
fDbEnvInit = false;
fMockDb = false;
}
-CDBEnv::CDBEnv() : dbenv(nullptr)
+CDBEnv::CDBEnv()
{
Reset();
}
@@ -55,8 +88,6 @@ CDBEnv::CDBEnv() : dbenv(nullptr)
CDBEnv::~CDBEnv()
{
EnvShutdown();
- delete dbenv;
- dbenv = nullptr;
}
void CDBEnv::Close()
@@ -148,7 +179,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, recoverFunc_type
LOCK(cs_db);
assert(mapFileUseCount.count(strFile) == 0);
- Db db(dbenv, 0);
+ Db db(dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
if (result == 0)
return VERIFY_OK;
@@ -191,7 +222,7 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco
}
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
- std::unique_ptr<Db> pdbCopy(new Db(bitdb.dbenv, 0));
+ std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(bitdb.dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer
filename.c_str(), // Filename
"main", // Logical db name
@@ -300,7 +331,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C
std::stringstream strDump;
- Db db(dbenv, 0);
+ Db db(dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, &strDump, flags);
if (result == DB_VERIFY_BAD) {
LogPrintf("CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
@@ -379,35 +410,34 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb
if (!env->Open(GetDataDir()))
throw std::runtime_error("CDB: Failed to open database environment.");
- strFile = strFilename;
- ++env->mapFileUseCount[strFile];
- pdb = env->mapDb[strFile];
+ pdb = env->mapDb[strFilename];
if (pdb == nullptr) {
int ret;
- pdb = new Db(env->dbenv, 0);
+ std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0);
bool fMockDb = env->IsMock();
if (fMockDb) {
- DbMpoolFile* mpf = pdb->get_mpf();
+ DbMpoolFile* mpf = pdb_temp->get_mpf();
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
- if (ret != 0)
- throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile));
+ if (ret != 0) {
+ throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFilename));
+ }
}
- ret = pdb->open(nullptr, // Txn pointer
- fMockDb ? nullptr : strFile.c_str(), // Filename
- fMockDb ? strFile.c_str() : "main", // Logical db name
- DB_BTREE, // Database type
- nFlags, // Flags
+ ret = pdb_temp->open(nullptr, // Txn pointer
+ fMockDb ? nullptr : strFilename.c_str(), // Filename
+ fMockDb ? strFilename.c_str() : "main", // Logical db name
+ DB_BTREE, // Database type
+ nFlags, // Flags
0);
if (ret != 0) {
- delete pdb;
- pdb = nullptr;
- --env->mapFileUseCount[strFile];
- strFile = "";
throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename));
}
+ CheckUniqueFileid(*env, strFilename, *pdb_temp);
+
+ pdb = pdb_temp.release();
+ env->mapDb[strFilename] = pdb;
if (fCreate && !Exists(std::string("version"))) {
bool fTmp = fReadOnly;
@@ -415,9 +445,9 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb
WriteVersion(CLIENT_VERSION);
fReadOnly = fTmp;
}
-
- env->mapDb[strFile] = pdb;
}
+ ++env->mapFileUseCount[strFilename];
+ strFile = strFilename;
}
}
@@ -492,7 +522,7 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
std::string strFileRes = strFile + ".rewrite";
{ // surround usage of db with extra {}
CDB db(dbw, "r");
- Db* pdbCopy = new Db(env->dbenv, 0);
+ std::unique_ptr<Db> pdbCopy = MakeUnique<Db>(env->dbenv.get(), 0);
int ret = pdbCopy->open(nullptr, // Txn pointer
strFileRes.c_str(), // Filename
@@ -541,13 +571,12 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip)
} else {
pdbCopy->close(0);
}
- delete pdbCopy;
}
if (fSuccess) {
- Db dbA(env->dbenv, 0);
+ Db dbA(env->dbenv.get(), 0);
if (dbA.remove(strFile.c_str(), nullptr, 0))
fSuccess = false;
- Db dbB(env->dbenv, 0);
+ Db dbB(env->dbenv.get(), 0);
if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0))
fSuccess = false;
}
@@ -672,6 +701,11 @@ bool CWalletDBWrapper::Backup(const std::string& strDest)
pathDest /= strFile;
try {
+ if (fs::equivalent(pathSrc, pathDest)) {
+ LogPrintf("cannot backup to wallet source file %s\n", pathDest.string());
+ return false;
+ }
+
fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
LogPrintf("copied %s to %s\n", strFile, pathDest.string());
return true;
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 14283ac8f8..5c5948aa29 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -6,12 +6,12 @@
#ifndef BITCOIN_WALLET_DB_H
#define BITCOIN_WALLET_DB_H
-#include "clientversion.h"
-#include "fs.h"
-#include "serialize.h"
-#include "streams.h"
-#include "sync.h"
-#include "version.h"
+#include <clientversion.h>
+#include <fs.h>
+#include <serialize.h>
+#include <streams.h>
+#include <sync.h>
+#include <version.h>
#include <atomic>
#include <map>
@@ -36,7 +36,7 @@ private:
public:
mutable CCriticalSection cs_db;
- DbEnv *dbenv;
+ std::unique_ptr<DbEnv> dbenv;
std::map<std::string, int> mapFileUseCount;
std::map<std::string, Db*> mapDb;
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6abd060714..9bfcab54a5 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -2,19 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "consensus/validation.h"
-#include "wallet/coincontrol.h"
-#include "wallet/feebumper.h"
-#include "wallet/fees.h"
-#include "wallet/wallet.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "validation.h" //for mempool access
-#include "txmempool.h"
-#include "utilmoneystr.h"
-#include "util.h"
-#include "net.h"
+#include <consensus/validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/fees.h>
+#include <wallet/wallet.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <validation.h> //for mempool access
+#include <txmempool.h>
+#include <utilmoneystr.h>
+#include <util.h>
+#include <net.h>
// Calculate the size of the transaction assuming all signatures are max size
// Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
@@ -23,7 +23,7 @@
// calculation, but we should be able to refactor after priority is removed).
// NOTE: this requires that all inputs must be in mapWallet (eg the tx should
// be IsAllFromMe).
-int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet)
+static int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet)
{
CMutableTransaction txNew(tx);
std::vector<CInputCoin> vCoins;
@@ -31,11 +31,11 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWal
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
// wallet, with a valid index into the vout array.
for (auto& input : tx.vin) {
- const auto mi = pWallet->mapWallet.find(input.prevout.hash);
- assert(mi != pWallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
+ const auto mi = wallet->mapWallet.find(input.prevout.hash);
+ assert(mi != wallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
vCoins.emplace_back(CInputCoin(&(mi->second), input.prevout.n));
}
- if (!pWallet->DummySignTx(txNew, vCoins)) {
+ if (!wallet->DummySignTx(txNew, vCoins)) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input.
return -1;
@@ -43,103 +43,102 @@ int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWal
return GetVirtualTransactionSize(txNew);
}
-bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx) {
- if (pWallet->HasWalletSpend(wtx.GetHash())) {
- vErrors.push_back("Transaction has descendants in the wallet");
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return false;
+//! Check whether transaction has descendant in wallet or mempool, or has been
+//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
+static feebumper::Result PreconditionChecks(const CWallet* wallet, const CWalletTx& wtx, std::vector<std::string>& errors)
+{
+ if (wallet->HasWalletSpend(wtx.GetHash())) {
+ errors.push_back("Transaction has descendants in the wallet");
+ return feebumper::Result::INVALID_PARAMETER;
}
{
LOCK(mempool.cs);
auto it_mp = mempool.mapTx.find(wtx.GetHash());
if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
- vErrors.push_back("Transaction has descendants in the mempool");
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return false;
+ errors.push_back("Transaction has descendants in the mempool");
+ return feebumper::Result::INVALID_PARAMETER;
}
}
if (wtx.GetDepthInMainChain() != 0) {
- vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return false;
+ errors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
+ return feebumper::Result::WALLET_ERROR;
}
- return true;
+ return feebumper::Result::OK;
}
-CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee)
- :
- txid(std::move(txidIn)),
- nOldFee(0),
- nNewFee(0)
+namespace feebumper {
+
+bool TransactionCanBeBumped(CWallet* wallet, const uint256& txid)
{
- vErrors.clear();
- bumpedTxid.SetNull();
- AssertLockHeld(pWallet->cs_wallet);
- auto it = pWallet->mapWallet.find(txid);
- if (it == pWallet->mapWallet.end()) {
- vErrors.push_back("Invalid or non-wallet transaction id");
- currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
- return;
+ LOCK2(cs_main, wallet->cs_wallet);
+ const CWalletTx* wtx = wallet->GetWalletTx(txid);
+ return wtx && SignalsOptInRBF(*wtx->tx) && !wtx->mapValue.count("replaced_by_txid");
+}
+
+Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, CAmount total_fee, std::vector<std::string>& errors,
+ CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
+{
+ LOCK2(cs_main, wallet->cs_wallet);
+ errors.clear();
+ auto it = wallet->mapWallet.find(txid);
+ if (it == wallet->mapWallet.end()) {
+ errors.push_back("Invalid or non-wallet transaction id");
+ return Result::INVALID_ADDRESS_OR_KEY;
}
const CWalletTx& wtx = it->second;
- if (!preconditionChecks(pWallet, wtx)) {
- return;
+ Result result = PreconditionChecks(wallet, wtx, errors);
+ if (result != Result::OK) {
+ return result;
}
- if (!SignalsOptInRBF(wtx)) {
- vErrors.push_back("Transaction is not BIP 125 replaceable");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ if (!SignalsOptInRBF(*wtx.tx)) {
+ errors.push_back("Transaction is not BIP 125 replaceable");
+ return Result::WALLET_ERROR;
}
if (wtx.mapValue.count("replaced_by_txid")) {
- vErrors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
+ return Result::WALLET_ERROR;
}
// check that original tx consists entirely of our inputs
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
- if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
- vErrors.push_back("Transaction contains inputs that don't belong to this wallet");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ if (!wallet->IsAllFromMe(*wtx.tx, ISMINE_SPENDABLE)) {
+ errors.push_back("Transaction contains inputs that don't belong to this wallet");
+ return Result::WALLET_ERROR;
}
// figure out which output was change
// if there was no change output or multiple change outputs, fail
int nOutput = -1;
for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
- if (pWallet->IsChange(wtx.tx->vout[i])) {
+ if (wallet->IsChange(wtx.tx->vout[i])) {
if (nOutput != -1) {
- vErrors.push_back("Transaction has multiple change outputs");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back("Transaction has multiple change outputs");
+ return Result::WALLET_ERROR;
}
nOutput = i;
}
}
if (nOutput == -1) {
- vErrors.push_back("Transaction does not have a change output");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back("Transaction does not have a change output");
+ return Result::WALLET_ERROR;
}
// Calculate the expected size of the new transaction.
int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
- const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, pWallet);
+ const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, wallet);
if (maxNewTxSize < 0) {
- vErrors.push_back("Transaction contains inputs that cannot be signed");
- currentResult = BumpFeeResult::INVALID_ADDRESS_OR_KEY;
- return;
+ errors.push_back("Transaction contains inputs that cannot be signed");
+ return Result::INVALID_ADDRESS_OR_KEY;
}
// calculate the old fee and fee-rate
- nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
- CFeeRate nOldFeeRate(nOldFee, txSize);
+ old_fee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
+ CFeeRate nOldFeeRate(old_fee, txSize);
CFeeRate nNewFeeRate;
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
// future proof against changes to network wide policy for incremental relay
@@ -149,26 +148,24 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
walletIncrementalRelayFee = ::incrementalRelayFee;
}
- if (totalFee > 0) {
+ if (total_fee > 0) {
CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
- if (totalFee < minTotalFee) {
- vErrors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
+ if (total_fee < minTotalFee) {
+ errors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return;
+ return Result::INVALID_PARAMETER;
}
CAmount requiredFee = GetRequiredFee(maxNewTxSize);
- if (totalFee < requiredFee) {
- vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
+ if (total_fee < requiredFee) {
+ errors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
FormatMoney(requiredFee)));
- currentResult = BumpFeeResult::INVALID_PARAMETER;
- return;
+ return Result::INVALID_PARAMETER;
}
- nNewFee = totalFee;
- nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
+ new_fee = total_fee;
+ nNewFeeRate = CFeeRate(total_fee, maxNewTxSize);
} else {
- nNewFee = GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
- nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
+ new_fee = GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
+ nNewFeeRate = CFeeRate(new_fee, maxNewTxSize);
// New fee rate must be at least old rate + minimum incremental relay rate
// walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
@@ -177,47 +174,50 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
// add 1 satoshi to the result, because it may have been rounded down.
if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
- nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
+ new_fee = nNewFeeRate.GetFee(maxNewTxSize);
}
}
// Check that in all cases the new fee doesn't violate maxTxFee
- if (nNewFee > maxTxFee) {
- vErrors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
- FormatMoney(nNewFee), FormatMoney(maxTxFee)));
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ if (new_fee > maxTxFee) {
+ errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
+ FormatMoney(new_fee), FormatMoney(maxTxFee)));
+ return Result::WALLET_ERROR;
}
// check that fee rate is higher than mempool's minimum fee
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
- // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
+ // moment earlier. In this case, we report an error to the user, who may use total_fee to make an adjustment.
CFeeRate minMempoolFeeRate = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
- vErrors.push_back(strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back(strprintf(
+ "New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
+ "the totalFee value should be at least %s or the settxfee value should be at least %s to add transaction",
+ FormatMoney(nNewFeeRate.GetFeePerK()),
+ FormatMoney(minMempoolFeeRate.GetFeePerK()),
+ FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)),
+ FormatMoney(minMempoolFeeRate.GetFeePerK())));
+ return Result::WALLET_ERROR;
}
// Now modify the output to increase the fee.
// If the output is not large enough to pay the fee, fail.
- CAmount nDelta = nNewFee - nOldFee;
+ CAmount nDelta = new_fee - old_fee;
assert(nDelta > 0);
mtx = *wtx.tx;
CTxOut* poutput = &(mtx.vout[nOutput]);
if (poutput->nValue < nDelta) {
- vErrors.push_back("Change output is too small to bump the fee");
- currentResult = BumpFeeResult::WALLET_ERROR;
- return;
+ errors.push_back("Change output is too small to bump the fee");
+ return Result::WALLET_ERROR;
}
// If the output would become dust, discard it (converting the dust to fee)
poutput->nValue -= nDelta;
if (poutput->nValue <= GetDustThreshold(*poutput, ::dustRelayFee)) {
LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
- nNewFee += poutput->nValue;
+ new_fee += poutput->nValue;
mtx.vout.erase(mtx.vout.begin() + nOutput);
}
@@ -228,36 +228,36 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoin
}
}
- currentResult = BumpFeeResult::OK;
+ return Result::OK;
}
-bool CFeeBumper::signTransaction(CWallet *pWallet)
-{
- return pWallet->SignTransaction(mtx);
+bool SignTransaction(CWallet* wallet, CMutableTransaction& mtx) {
+ LOCK2(cs_main, wallet->cs_wallet);
+ return wallet->SignTransaction(mtx);
}
-bool CFeeBumper::commit(CWallet *pWallet)
+Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<std::string>& errors, uint256& bumped_txid)
{
- AssertLockHeld(pWallet->cs_wallet);
- if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {
- return false;
+ LOCK2(cs_main, wallet->cs_wallet);
+ if (!errors.empty()) {
+ return Result::MISC_ERROR;
}
- auto it = txid.IsNull() ? pWallet->mapWallet.end() : pWallet->mapWallet.find(txid);
- if (it == pWallet->mapWallet.end()) {
- vErrors.push_back("Invalid or non-wallet transaction id");
- currentResult = BumpFeeResult::MISC_ERROR;
- return false;
+ auto it = txid.IsNull() ? wallet->mapWallet.end() : wallet->mapWallet.find(txid);
+ if (it == wallet->mapWallet.end()) {
+ errors.push_back("Invalid or non-wallet transaction id");
+ return Result::MISC_ERROR;
}
CWalletTx& oldWtx = it->second;
// make sure the transaction still has no descendants and hasn't been mined in the meantime
- if (!preconditionChecks(pWallet, oldWtx)) {
- return false;
+ Result result = PreconditionChecks(wallet, oldWtx, errors);
+ if (result != Result::OK) {
+ return result;
}
- CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
+ CWalletTx wtxBumped(wallet, MakeTransactionRef(std::move(mtx)));
// commit/broadcast the tx
- CReserveKey reservekey(pWallet);
+ CReserveKey reservekey(wallet);
wtxBumped.mapValue = oldWtx.mapValue;
wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
wtxBumped.vOrderForm = oldWtx.vOrderForm;
@@ -265,27 +265,29 @@ bool CFeeBumper::commit(CWallet *pWallet)
wtxBumped.fTimeReceivedIsTxTime = true;
wtxBumped.fFromMe = true;
CValidationState state;
- if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
+ if (!wallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
// NOTE: CommitTransaction never returns false, so this should never happen.
- vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
- return false;
+ errors.push_back(strprintf("The transaction was rejected: %s", state.GetRejectReason()));
+ return Result::WALLET_ERROR;
}
- bumpedTxid = wtxBumped.GetHash();
+ bumped_txid = wtxBumped.GetHash();
if (state.IsInvalid()) {
// This can happen if the mempool rejected the transaction. Report
// what happened in the "errors" response.
- vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
+ errors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
}
// mark the original tx as bumped
- if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
+ if (!wallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
// TODO: see if JSON-RPC has a standard way of returning a response
// along with an exception. It would be good to return information about
// wtxBumped to the caller even if marking the original transaction
// replaced does not succeed for some reason.
- vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
+ errors.push_back("Created new bumpfee transaction but could not mark the original transaction as replaced");
}
- return true;
+ return Result::OK;
}
+} // namespace feebumper
+
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index 3d64e53c15..8eec30440c 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.h
@@ -13,7 +13,9 @@ class uint256;
class CCoinControl;
enum class FeeEstimateMode;
-enum class BumpFeeResult
+namespace feebumper {
+
+enum class Result
{
OK,
INVALID_ADDRESS_OR_KEY,
@@ -23,39 +25,34 @@ enum class BumpFeeResult
MISC_ERROR,
};
-class CFeeBumper
-{
-public:
- CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee);
- BumpFeeResult getResult() const { return currentResult; }
- const std::vector<std::string>& getErrors() const { return vErrors; }
- CAmount getOldFee() const { return nOldFee; }
- CAmount getNewFee() const { return nNewFee; }
- uint256 getBumpedTxId() const { return bumpedTxid; }
-
- /* signs the new transaction,
- * returns false if the tx couldn't be found or if it was
- * impossible to create the signature(s)
- */
- bool signTransaction(CWallet *pWallet);
-
- /* commits the fee bump,
- * returns true, in case of CWallet::CommitTransaction was successful
- * but, eventually sets vErrors if the tx could not be added to the mempool (will try later)
- * or if the old transaction could not be marked as replaced
- */
- bool commit(CWallet *pWalletNonConst);
-
-private:
- bool preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx);
-
- const uint256 txid;
- uint256 bumpedTxid;
- CMutableTransaction mtx;
- std::vector<std::string> vErrors;
- BumpFeeResult currentResult;
- CAmount nOldFee;
- CAmount nNewFee;
-};
+//! Return whether transaction can be bumped.
+bool TransactionCanBeBumped(CWallet* wallet, const uint256& txid);
+
+//! Create bumpfee transaction.
+Result CreateTransaction(const CWallet* wallet,
+ const uint256& txid,
+ const CCoinControl& coin_control,
+ CAmount total_fee,
+ std::vector<std::string>& errors,
+ CAmount& old_fee,
+ CAmount& new_fee,
+ CMutableTransaction& mtx);
+
+//! Sign the new transaction,
+//! @return false if the tx couldn't be found or if it was
+//! impossible to create the signature(s)
+bool SignTransaction(CWallet* wallet, CMutableTransaction& mtx);
+
+//! Commit the bumpfee transaction.
+//! @return success in case of CWallet::CommitTransaction was successful,
+//! but sets errors if the tx could not be added to the mempool (will try later)
+//! or if the old transaction could not be marked as replaced.
+Result CommitTransaction(CWallet* wallet,
+ const uint256& txid,
+ CMutableTransaction&& mtx,
+ std::vector<std::string>& errors,
+ uint256& bumped_txid);
+
+} // namespace feebumper
#endif // BITCOIN_WALLET_FEEBUMPER_H
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 76eeeeda05..73985dcf25 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/fees.h"
+#include <wallet/fees.h>
-#include "policy/policy.h"
-#include "txmempool.h"
-#include "util.h"
-#include "validation.h"
-#include "wallet/coincontrol.h"
-#include "wallet/wallet.h"
+#include <policy/policy.h>
+#include <txmempool.h>
+#include <util.h>
+#include <validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/wallet.h>
CAmount GetRequiredFee(unsigned int nTxBytes)
diff --git a/src/wallet/fees.h b/src/wallet/fees.h
index 7b8a7dc868..225aff08ad 100644
--- a/src/wallet/fees.h
+++ b/src/wallet/fees.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_WALLET_FEES_H
#define BITCOIN_WALLET_FEES_H
-#include "amount.h"
+#include <amount.h>
class CBlockPolicyEstimator;
class CCoinControl;
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index c984df1df8..ca6dcccf78 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -3,14 +3,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/init.h"
+#include <wallet/init.h>
-#include "net.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "validation.h"
-#include "wallet/wallet.h"
-#include "wallet/rpcwallet.h"
+#include <net.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <validation.h>
+#include <wallet/wallet.h>
+#include <wallet/rpcwallet.h>
std::string GetWalletHelpString(bool showDebug)
{
@@ -53,11 +53,16 @@ std::string GetWalletHelpString(bool showDebug)
bool WalletParameterInteraction()
{
- gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
- const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ for (const std::string& wallet : gArgs.GetArgs("-wallet")) {
+ LogPrintf("%s: parameter interaction: -disablewallet -> ignoring -wallet=%s\n", __func__, wallet);
+ }
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
return true;
+ }
+
+ gArgs.SoftSetArg("-wallet", DEFAULT_WALLET_DAT);
+ const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1;
if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) {
LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
@@ -173,15 +178,18 @@ bool WalletParameterInteraction()
void RegisterWalletRPC(CRPCTable &t)
{
- if (gArgs.GetBoolArg("-disablewallet", false)) return;
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
+ return;
+ }
RegisterWalletRPCCommands(t);
}
bool VerifyWallets()
{
- if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
+ if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) {
return true;
+ }
uiInterface.InitMessage(_("Verifying wallet(s)..."));
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index d6ea2a9db7..fcc4c43872 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -2,22 +2,22 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "base58.h"
-#include "chain.h"
-#include "rpc/safemode.h"
-#include "rpc/server.h"
-#include "init.h"
-#include "validation.h"
-#include "script/script.h"
-#include "script/standard.h"
-#include "sync.h"
-#include "util.h"
-#include "utiltime.h"
-#include "wallet.h"
-#include "merkleblock.h"
-#include "core_io.h"
-
-#include "rpcwallet.h"
+#include <base58.h>
+#include <chain.h>
+#include <rpc/safemode.h>
+#include <rpc/server.h>
+#include <wallet/init.h>
+#include <validation.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <sync.h>
+#include <util.h>
+#include <utiltime.h>
+#include <wallet/wallet.h>
+#include <merkleblock.h>
+#include <core_io.h>
+
+#include <wallet/rpcwallet.h>
#include <fstream>
#include <stdint.h>
@@ -81,7 +81,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
"importprivkey \"privkey\" ( \"label\" ) ( rescan )\n"
- "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
+ "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
"\nArguments:\n"
"1. \"privkey\" (string, required) The private key (see dumpprivkey)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
@@ -226,7 +226,7 @@ UniValue importaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
"importaddress \"address\" ( \"label\" rescan p2sh )\n"
- "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n"
+ "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nArguments:\n"
"1. \"script\" (string, required) The hex-encoded script (or address)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
@@ -340,7 +340,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (pwallet->IsMine(wtx)) {
+ if (pwallet->IsMine(*wtx.tx)) {
pwallet->AddToWallet(wtx, false);
return NullUniValue;
}
@@ -396,7 +396,7 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
- "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n"
+ "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nArguments:\n"
"1. \"pubkey\" (string, required) The hex-encoded public key\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
@@ -456,7 +456,7 @@ UniValue importwallet(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
"importwallet \"filename\"\n"
- "\nImports keys from a wallet dump file (see dumpwallet).\n"
+ "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The wallet file\n"
"\nExamples:\n"
@@ -601,6 +601,9 @@ UniValue dumpwallet(const JSONRPCRequest& request)
throw std::runtime_error(
"dumpwallet \"filename\"\n"
"\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
+ "Imported scripts are not currently included in wallet dumps, these must be backed up separately.\n"
+ "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n"
+ "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n"
"\nArguments:\n"
"1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n"
"\nResult:\n"
@@ -961,7 +964,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6
pwallet->SetAddressBook(vchAddress, label, "receive");
if (pwallet->HaveKey(vchAddress)) {
- return false;
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
}
pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
@@ -1039,7 +1042,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
throw std::runtime_error(
"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"
+ "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\n\n"
"Arguments:\n"
"1. requests (array, required) Data to be imported\n"
" [ (array of json objects)\n"
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 4c7264ba38..23559eb350 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3,29 +3,29 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "amount.h"
-#include "base58.h"
-#include "chain.h"
-#include "consensus/validation.h"
-#include "core_io.h"
-#include "httpserver.h"
-#include "validation.h"
-#include "net.h"
-#include "policy/feerate.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "rpc/mining.h"
-#include "rpc/safemode.h"
-#include "rpc/server.h"
-#include "script/sign.h"
-#include "timedata.h"
-#include "util.h"
-#include "utilmoneystr.h"
-#include "wallet/coincontrol.h"
-#include "wallet/feebumper.h"
-#include "wallet/wallet.h"
-#include "wallet/walletdb.h"
+#include <amount.h>
+#include <base58.h>
+#include <chain.h>
+#include <consensus/validation.h>
+#include <core_io.h>
+#include <httpserver.h>
+#include <validation.h>
+#include <net.h>
+#include <policy/feerate.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <rpc/mining.h>
+#include <rpc/safemode.h>
+#include <rpc/server.h>
+#include <script/sign.h>
+#include <timedata.h>
+#include <util.h>
+#include <utilmoneystr.h>
+#include <wallet/coincontrol.h>
+#include <wallet/feebumper.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
#include <init.h> // For StartShutdown
@@ -108,7 +108,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
std::string rbfStatus = "no";
if (confirms <= 0) {
LOCK(mempool.cs);
- RBFTransactionState rbfState = IsRBFOptIn(wtx, mempool);
+ RBFTransactionState rbfState = IsRBFOptIn(*wtx.tx, mempool);
if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN)
rbfStatus = "unknown";
else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125)
@@ -455,6 +455,11 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
CTxDestination dest = DecodeDestination(request.params[0].get_str());
@@ -533,6 +538,11 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
UniValue jsonGroupings(UniValue::VARR);
@@ -645,6 +655,11 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
// Bitcoin address
@@ -654,7 +669,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
}
CScript scriptPubKey = GetScriptForDestination(dest);
if (!IsMine(*pwallet, scriptPubKey)) {
- return ValueFromAmount(0);
+ throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
}
// Minimum confirmations
@@ -707,6 +722,11 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
// Minimum confirmations
@@ -780,6 +800,11 @@ UniValue getbalance(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
const UniValue& account_value = request.params[0];
@@ -825,6 +850,11 @@ UniValue getunconfirmedbalance(const JSONRPCRequest &request)
"Returns the server's total unconfirmed balance\n");
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
return ValueFromAmount(pwallet->GetUnconfirmedBalance());
@@ -919,6 +949,11 @@ UniValue sendfrom(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = AccountFromValue(request.params[0]);
@@ -1004,6 +1039,11 @@ UniValue sendmany(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
if (pwallet->GetBroadcastTransactions() && !g_connman) {
@@ -1110,7 +1150,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
{
std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
- "\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
+ "\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"If 'account' is specified (DEPRECATED), assign address to that account.\n"
@@ -1228,7 +1268,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
{
std::string msg = "addwitnessaddress \"address\" ( p2sh )\n"
- "\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
+ "\nAdd a witness address for a script (with pubkey or redeemscript known). Requires a new wallet backup.\n"
"It returns the witness script.\n"
"\nArguments:\n"
@@ -1455,6 +1495,11 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, false);
@@ -1495,6 +1540,11 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
return ListReceived(pwallet, request.params, true);
@@ -1683,6 +1733,11 @@ UniValue listtransactions(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
std::string strAccount = "*";
@@ -1777,6 +1832,11 @@ UniValue listaccounts(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
int nMinDepth = 1;
@@ -1886,6 +1946,11 @@ UniValue listsinceblock(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
const CBlockIndex* pindex = nullptr; // Block index of the specified block or the common ancestor, if the block provided was in a deactivated chain.
@@ -1893,19 +1958,20 @@ UniValue listsinceblock(const JSONRPCRequest& request)
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (!request.params[0].isNull()) {
+ if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
uint256 blockId;
blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
- if (it != mapBlockIndex.end()) {
- paltindex = pindex = it->second;
- if (chainActive[pindex->nHeight] != pindex) {
- // the block being asked for is a part of a deactivated chain;
- // we don't want to depend on its perceived height in the block
- // chain, we want to instead use the last common ancestor
- pindex = chainActive.FindFork(pindex);
- }
+ if (it == mapBlockIndex.end()) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
+ paltindex = pindex = it->second;
+ if (chainActive[pindex->nHeight] != pindex) {
+ // the block being asked for is a part of a deactivated chain;
+ // we don't want to depend on its perceived height in the block
+ // chain, we want to instead use the last common ancestor
+ pindex = chainActive.FindFork(pindex);
}
}
@@ -2018,6 +2084,11 @@ UniValue gettransaction(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -2050,7 +2121,7 @@ UniValue gettransaction(const JSONRPCRequest& request)
ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
- std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
entry.push_back(Pair("hex", strHex));
return entry;
@@ -2080,6 +2151,11 @@ UniValue abandontransaction(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash;
@@ -2114,6 +2190,10 @@ UniValue backupwallet(const JSONRPCRequest& request)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
);
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
std::string strDest = request.params[0].get_str();
@@ -2179,7 +2259,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
@@ -2243,7 +2323,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) {
+ if (request.fHelp || request.params.size() != 2) {
throw std::runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
@@ -2294,7 +2374,7 @@ UniValue walletlock(const JSONRPCRequest& request)
return NullUniValue;
}
- if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) {
+ if (request.fHelp || request.params.size() != 0) {
throw std::runtime_error(
"walletlock\n"
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
@@ -2334,7 +2414,7 @@ UniValue encryptwallet(const JSONRPCRequest& request)
return NullUniValue;
}
- if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) {
+ if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"encryptwallet \"passphrase\"\n"
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
@@ -2433,6 +2513,10 @@ UniValue lockunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
@@ -2625,6 +2709,11 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
);
ObserveSafeMode();
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
UniValue obj(UniValue::VOBJ);
@@ -2834,9 +2923,12 @@ UniValue listunspent(const JSONRPCRequest& request)
nMaximumCount = options["maximumCount"].get_int64();
}
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
UniValue results(UniValue::VARR);
std::vector<COutput> vecOutputs;
- assert(pwallet != nullptr);
LOCK2(cs_main, pwallet->cs_wallet);
pwallet->AvailableCoins(vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
@@ -2944,6 +3036,10 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
ObserveSafeMode();
RPCTypeCheck(request.params, {UniValue::VSTR});
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
CCoinControl coinControl;
int changePosition = -1;
bool lockUnspents = false;
@@ -3154,48 +3250,57 @@ UniValue bumpfee(const JSONRPCRequest& request)
}
}
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ pwallet->BlockUntilSyncedToCurrentChain();
+
LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- CFeeBumper feeBump(pwallet, hash, coin_control, totalFee);
- BumpFeeResult res = feeBump.getResult();
- if (res != BumpFeeResult::OK)
- {
+
+ std::vector<std::string> errors;
+ CAmount old_fee;
+ CAmount new_fee;
+ CMutableTransaction mtx;
+ feebumper::Result res = feebumper::CreateTransaction(pwallet, hash, coin_control, totalFee, errors, old_fee, new_fee, mtx);
+ if (res != feebumper::Result::OK) {
switch(res) {
- case BumpFeeResult::INVALID_ADDRESS_OR_KEY:
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, feeBump.getErrors()[0]);
+ case feebumper::Result::INVALID_ADDRESS_OR_KEY:
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0]);
break;
- case BumpFeeResult::INVALID_REQUEST:
- throw JSONRPCError(RPC_INVALID_REQUEST, feeBump.getErrors()[0]);
+ case feebumper::Result::INVALID_REQUEST:
+ throw JSONRPCError(RPC_INVALID_REQUEST, errors[0]);
break;
- case BumpFeeResult::INVALID_PARAMETER:
- throw JSONRPCError(RPC_INVALID_PARAMETER, feeBump.getErrors()[0]);
+ case feebumper::Result::INVALID_PARAMETER:
+ throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0]);
break;
- case BumpFeeResult::WALLET_ERROR:
- throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);
+ case feebumper::Result::WALLET_ERROR:
+ throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
break;
default:
- throw JSONRPCError(RPC_MISC_ERROR, feeBump.getErrors()[0]);
+ throw JSONRPCError(RPC_MISC_ERROR, errors[0]);
break;
}
}
// sign bumped transaction
- if (!feeBump.signTransaction(pwallet)) {
+ if (!feebumper::SignTransaction(pwallet, mtx)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
}
// commit the bumped transaction
- if(!feeBump.commit(pwallet)) {
- throw JSONRPCError(RPC_WALLET_ERROR, feeBump.getErrors()[0]);
+ uint256 txid;
+ if (feebumper::CommitTransaction(pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
+ throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
}
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("txid", feeBump.getBumpedTxId().GetHex()));
- result.push_back(Pair("origfee", ValueFromAmount(feeBump.getOldFee())));
- result.push_back(Pair("fee", ValueFromAmount(feeBump.getNewFee())));
- UniValue errors(UniValue::VARR);
- for (const std::string& err: feeBump.getErrors())
- errors.push_back(err);
- result.push_back(Pair("errors", errors));
+ result.push_back(Pair("txid", txid.GetHex()));
+ result.push_back(Pair("origfee", ValueFromAmount(old_fee)));
+ result.push_back(Pair("fee", ValueFromAmount(new_fee)));
+ UniValue result_errors(UniValue::VARR);
+ for (const std::string& error : errors) {
+ result_errors.push_back(error);
+ }
+ result.push_back(Pair("errors", result_errors));
return result;
}
@@ -3245,6 +3350,81 @@ UniValue generate(const JSONRPCRequest& request)
return generateBlocks(coinbase_script, num_generate, max_tries, true);
}
+UniValue rescanblockchain(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() > 2) {
+ throw std::runtime_error(
+ "rescanblockchain (\"start_height\") (\"stop_height\")\n"
+ "\nRescan the local blockchain for wallet related transactions.\n"
+ "\nArguments:\n"
+ "1. \"start_height\" (numeric, optional) block height where the rescan should start\n"
+ "2. \"stop_height\" (numeric, optional) the last block height that should be scanned\n"
+ "\nResult:\n"
+ "{\n"
+ " \"start_height\" (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
+ " \"stop_height\" (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("rescanblockchain", "100000 120000")
+ + HelpExampleRpc("rescanblockchain", "100000, 120000")
+ );
+ }
+
+ LOCK2(cs_main, pwallet->cs_wallet);
+
+ CBlockIndex *pindexStart = chainActive.Genesis();
+ CBlockIndex *pindexStop = nullptr;
+ if (!request.params[0].isNull()) {
+ pindexStart = chainActive[request.params[0].get_int()];
+ if (!pindexStart) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
+ }
+ }
+
+ if (!request.params[1].isNull()) {
+ pindexStop = chainActive[request.params[1].get_int()];
+ if (!pindexStop) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
+ }
+ else if (pindexStop->nHeight < pindexStart->nHeight) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height");
+ }
+ }
+
+ // We can't rescan beyond non-pruned blocks, stop and throw an error
+ if (fPruneMode) {
+ CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
+ while (block && block->nHeight >= pindexStart->nHeight) {
+ if (!(block->nStatus & BLOCK_HAVE_DATA)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
+ }
+ block = block->pprev;
+ }
+ }
+
+ CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
+ if (!stopBlock) {
+ if (pwallet->IsAbortingRescan()) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
+ }
+ // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
+ stopBlock = pindexStop ? pindexStop : chainActive.Tip();
+ }
+ else {
+ throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
+ }
+
+ UniValue response(UniValue::VOBJ);
+ response.pushKV("start_height", pindexStart->nHeight);
+ response.pushKV("stop_height", stopBlock->nHeight);
+ return response;
+}
+
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
@@ -3255,6 +3435,7 @@ extern UniValue importwallet(const JSONRPCRequest& request);
extern UniValue importprunedfunds(const JSONRPCRequest& request);
extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request);
+extern UniValue rescanblockchain(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@@ -3309,6 +3490,7 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+ { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
{ "generating", "generate", &generate, {"nblocks","maxtries"} },
};
diff --git a/src/wallet/test/accounting_tests.cpp b/src/wallet/test/accounting_tests.cpp
index 330878ceb5..a9cdc89e6f 100644
--- a/src/wallet/test/accounting_tests.cpp
+++ b/src/wallet/test/accounting_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
-#include "wallet/test/wallet_test_fixture.h"
+#include <wallet/test/wallet_test_fixture.h>
#include <stdint.h>
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "y";
{
- CMutableTransaction tx(wtx);
+ CMutableTransaction tx(*wtx.tx);
--tx.nLockTime; // Just to change the hash :)
wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
@@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade)
wtx.mapValue["comment"] = "x";
{
- CMutableTransaction tx(wtx);
+ CMutableTransaction tx(*wtx.tx);
--tx.nLockTime; // Just to change the hash :)
wtx.SetTx(MakeTransactionRef(std::move(tx)));
}
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index f4dabc50c0..3ff8c6d224 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -2,9 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "test/test_bitcoin.h"
-#include "utilstrencodings.h"
-#include "wallet/crypter.h"
+#include <test/test_bitcoin.h>
+#include <utilstrencodings.h>
+#include <wallet/crypter.h>
#include <vector>
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index e2f48c45ab..995ec640b1 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/test/wallet_test_fixture.h"
+#include <wallet/test/wallet_test_fixture.h>
-#include "rpc/server.h"
-#include "wallet/db.h"
-#include "wallet/wallet.h"
+#include <rpc/server.h>
+#include <wallet/db.h>
+#include <wallet/wallet.h>
-CWallet *pwalletMain;
+std::unique_ptr<CWallet> pwalletMain;
WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
TestingSetup(chainName)
@@ -17,18 +17,17 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
bool fFirstRun;
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
- pwalletMain = new CWallet(std::move(dbw));
+ pwalletMain = MakeUnique<CWallet>(std::move(dbw));
pwalletMain->LoadWallet(fFirstRun);
- RegisterValidationInterface(pwalletMain);
+ RegisterValidationInterface(pwalletMain.get());
RegisterWalletRPCCommands(tableRPC);
}
WalletTestingSetup::~WalletTestingSetup()
{
- UnregisterValidationInterface(pwalletMain);
- delete pwalletMain;
- pwalletMain = nullptr;
+ UnregisterValidationInterface(pwalletMain.get());
+ pwalletMain.reset();
bitdb.Flush(true);
bitdb.Reset();
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index 9373b7907c..a341bc698a 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_WALLET_TEST_FIXTURE_H
#define BITCOIN_WALLET_TEST_FIXTURE_H
-#include "test/test_bitcoin.h"
+#include <test/test_bitcoin.h>
/** Testing setup and teardown for wallet.
*/
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 5ebacd57d3..7ae1e74dbe 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -2,19 +2,19 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
+#include <wallet/wallet.h>
#include <set>
#include <stdint.h>
#include <utility>
#include <vector>
-#include "consensus/validation.h"
-#include "rpc/server.h"
-#include "test/test_bitcoin.h"
-#include "validation.h"
-#include "wallet/coincontrol.h"
-#include "wallet/test/wallet_test_fixture.h"
+#include <consensus/validation.h>
+#include <rpc/server.h>
+#include <test/test_bitcoin.h>
+#include <validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/test/wallet_test_fixture.h>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
@@ -386,7 +386,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
CWallet wallet;
AddKey(wallet, coinbaseKey);
- BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip));
+ BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
}
@@ -399,7 +399,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{
CWallet wallet;
AddKey(wallet, coinbaseKey);
- BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip));
+ BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
}
@@ -489,6 +489,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
vpwallets[0] = &wallet;
::importwallet(request);
+ LOCK(wallet.cs_wallet);
BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3);
BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103);
for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
@@ -534,6 +535,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
if (blockTime > 0) {
+ LOCK(cs_main);
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash = inserted.first->first;
@@ -547,6 +549,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
wtx.SetMerkleBranch(block, 0);
}
wallet.AddToWallet(wtx);
+ LOCK(wallet.cs_wallet);
return wallet.mapWallet.at(wtx.GetHash()).nTimeSmart;
}
@@ -583,6 +586,7 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
{
CTxDestination dest = CKeyID();
+ LOCK(pwalletMain->cs_wallet);
pwalletMain->AddDestData(dest, "misc", "val_misc");
pwalletMain->AddDestData(dest, "rr0", "val_rr0");
pwalletMain->AddDestData(dest, "rr1", "val_rr1");
@@ -604,7 +608,7 @@ public:
bool firstRun;
wallet->LoadWallet(firstRun);
AddKey(*wallet, coinbaseKey);
- wallet->ScanForWalletTransactions(chainActive.Genesis());
+ wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr);
}
~ListCoinsTestingSetup()
@@ -625,6 +629,7 @@ public:
BOOST_CHECK(wallet->CreateTransaction({recipient}, wtx, reservekey, fee, changePos, error, dummy));
CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(wtx, reservekey, nullptr, state));
+ LOCK(wallet->cs_wallet);
auto it = wallet->mapWallet.find(wtx.GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
CreateAndProcessBlock({CMutableTransaction(*it->second.tx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 50c1375f44..edc1ca6ef8 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3,36 +3,37 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/wallet.h"
-
-#include "base58.h"
-#include "checkpoints.h"
-#include "chain.h"
-#include "wallet/coincontrol.h"
-#include "consensus/consensus.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "init.h"
-#include "key.h"
-#include "keystore.h"
-#include "validation.h"
-#include "net.h"
-#include "policy/fees.h"
-#include "policy/policy.h"
-#include "policy/rbf.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "script/sign.h"
-#include "scheduler.h"
-#include "timedata.h"
-#include "txmempool.h"
-#include "util.h"
-#include "ui_interface.h"
-#include "utilmoneystr.h"
-#include "wallet/fees.h"
+#include <wallet/wallet.h>
+
+#include <base58.h>
+#include <checkpoints.h>
+#include <chain.h>
+#include <wallet/coincontrol.h>
+#include <consensus/consensus.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <wallet/init.h>
+#include <key.h>
+#include <keystore.h>
+#include <validation.h>
+#include <net.h>
+#include <policy/fees.h>
+#include <policy/policy.h>
+#include <policy/rbf.h>
+#include <primitives/block.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <script/sign.h>
+#include <scheduler.h>
+#include <timedata.h>
+#include <txmempool.h>
+#include <util.h>
+#include <ui_interface.h>
+#include <utilmoneystr.h>
+#include <wallet/fees.h>
#include <assert.h>
+#include <future>
#include <boost/algorithm/string/replace.hpp>
#include <boost/thread.hpp>
@@ -532,6 +533,9 @@ void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> ran
copyFrom = &mapWallet[hash];
}
}
+
+ assert(copyFrom);
+
// Now copy data from copyFrom to rest:
for (TxSpends::iterator it = range.first; it != range.second; ++it)
{
@@ -1214,6 +1218,19 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
LOCK2(cs_main, cs_wallet);
SyncTransaction(ptx);
+
+ auto it = mapWallet.find(ptx->GetHash());
+ if (it != mapWallet.end()) {
+ it->second.fInMempool = true;
+ }
+}
+
+void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
+ LOCK(cs_wallet);
+ auto it = mapWallet.find(ptx->GetHash());
+ if (it != mapWallet.end()) {
+ it->second.fInMempool = false;
+ }
}
void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
@@ -1228,10 +1245,14 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
for (const CTransactionRef& ptx : vtxConflicted) {
SyncTransaction(ptx);
+ TransactionRemovedFromMempool(ptx);
}
for (size_t i = 0; i < pblock->vtx.size(); i++) {
SyncTransaction(pblock->vtx[i], pindex, i);
+ TransactionRemovedFromMempool(pblock->vtx[i]);
}
+
+ m_last_block_processed = pindex;
}
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
@@ -1244,6 +1265,36 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
+void CWallet::BlockUntilSyncedToCurrentChain() {
+ AssertLockNotHeld(cs_main);
+ AssertLockNotHeld(cs_wallet);
+
+ {
+ // Skip the queue-draining stuff if we know we're caught up with
+ // chainActive.Tip()...
+ // We could also take cs_wallet here, and call m_last_block_processed
+ // protected by cs_wallet instead of cs_main, but as long as we need
+ // cs_main here anyway, its easier to just call it cs_main-protected.
+ LOCK(cs_main);
+ const CBlockIndex* initialChainTip = chainActive.Tip();
+
+ if (m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
+ return;
+ }
+ }
+
+ // ...otherwise put a callback in the validation interface queue and wait
+ // for the queue to drain enough to execute it (indicating we are caught up
+ // at least with the time we entered this function).
+
+ std::promise<void> promise;
+ CallFunctionInValidationInterfaceQueue([&promise] {
+ promise.set_value();
+ });
+ promise.get_future().wait();
+}
+
+
isminetype CWallet::IsMine(const CTxIn &txin) const
{
{
@@ -1568,7 +1619,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
if (startBlock) {
- const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update);
+ const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, update);
if (failedBlock) {
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
}
@@ -1584,12 +1635,19 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
* Returns null if scan was successful. Otherwise, if a complete rescan was not
* possible (due to pruning or corruption), returns pointer to the most recent
* block that could not be scanned.
+ *
+ * If pindexStop is not a nullptr, the scan will stop at the block-index
+ * defined by pindexStop
*/
-CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
+CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate)
{
int64_t nNow = GetTime();
const CChainParams& chainParams = Params();
+ if (pindexStop) {
+ assert(pindexStop->nHeight >= pindexStart->nHeight);
+ }
+
CBlockIndex* pindex = pindexStart;
CBlockIndex* ret = nullptr;
{
@@ -1617,6 +1675,9 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
} else {
ret = pindex;
}
+ if (pindex == pindexStop) {
+ break;
+ }
pindex = chainActive.Next(pindex);
}
if (pindex && fAbortRescan) {
@@ -1708,7 +1769,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
debit += nDebitCached;
else
{
- nDebitCached = pwallet->GetDebit(*this, ISMINE_SPENDABLE);
+ nDebitCached = pwallet->GetDebit(*tx, ISMINE_SPENDABLE);
fDebitCached = true;
debit += nDebitCached;
}
@@ -1719,7 +1780,7 @@ CAmount CWalletTx::GetDebit(const isminefilter& filter) const
debit += nWatchDebitCached;
else
{
- nWatchDebitCached = pwallet->GetDebit(*this, ISMINE_WATCH_ONLY);
+ nWatchDebitCached = pwallet->GetDebit(*tx, ISMINE_WATCH_ONLY);
fWatchDebitCached = true;
debit += nWatchDebitCached;
}
@@ -1741,7 +1802,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
credit += nCreditCached;
else
{
- nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
+ nCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
fCreditCached = true;
credit += nCreditCached;
}
@@ -1752,7 +1813,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const
credit += nWatchCreditCached;
else
{
- nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
+ nWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
fWatchCreditCached = true;
credit += nWatchCreditCached;
}
@@ -1766,7 +1827,7 @@ CAmount CWalletTx::GetImmatureCredit(bool fUseCache) const
{
if (fUseCache && fImmatureCreditCached)
return nImmatureCreditCached;
- nImmatureCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE);
+ nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
fImmatureCreditCached = true;
return nImmatureCreditCached;
}
@@ -1810,7 +1871,7 @@ CAmount CWalletTx::GetImmatureWatchOnlyCredit(const bool& fUseCache) const
{
if (fUseCache && fImmatureWatchCreditCached)
return nImmatureWatchCreditCached;
- nImmatureWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY);
+ nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
fImmatureWatchCreditCached = true;
return nImmatureWatchCreditCached;
}
@@ -1851,21 +1912,20 @@ CAmount CWalletTx::GetChange() const
{
if (fChangeCached)
return nChangeCached;
- nChangeCached = pwallet->GetChange(*this);
+ nChangeCached = pwallet->GetChange(*tx);
fChangeCached = true;
return nChangeCached;
}
bool CWalletTx::InMempool() const
{
- LOCK(mempool.cs);
- return mempool.exists(GetHash());
+ return fInMempool;
}
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
- if (!CheckFinalTx(*this))
+ if (!CheckFinalTx(*tx))
return false;
int nDepth = GetDepthInMainChain();
if (nDepth >= 1)
@@ -2123,7 +2183,7 @@ void CWallet::AvailableCoins(std::vector<COutput> &vCoins, bool fOnlySafe, const
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
- if (!CheckFinalTx(*pcoin))
+ if (!CheckFinalTx(*pcoin->tx))
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
@@ -2905,7 +2965,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
wtxNew.SetTx(MakeTransactionRef(std::move(txNew)));
// Limit size
- if (GetTransactionWeight(wtxNew) >= MAX_STANDARD_TX_WEIGHT)
+ if (GetTransactionWeight(*wtxNew.tx) >= MAX_STANDARD_TX_WEIGHT)
{
strFailReason = _("Transaction too large");
return false;
@@ -2967,14 +3027,18 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
// Track how many getdata requests our transaction gets
mapRequestCount[wtxNew.GetHash()] = 0;
+ // Get the inserted-CWalletTx from mapWallet so that the
+ // fInMempool flag is cached properly
+ CWalletTx& wtx = mapWallet[wtxNew.GetHash()];
+
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(maxTxFee, state)) {
+ if (!wtx.AcceptToMemoryPool(maxTxFee, state)) {
LogPrintf("CommitTransaction(): Transaction cannot be broadcast immediately, %s\n", state.GetRejectReason());
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
- wtxNew.RelayWalletTransaction(connman);
+ wtx.RelayWalletTransaction(connman);
}
}
}
@@ -3793,7 +3857,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, walletFile));
- std::unique_ptr<CWallet> tempWallet(new CWallet(std::move(dbw)));
+ std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(std::move(dbw));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DB_LOAD_OK) {
InitError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
@@ -3871,7 +3935,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
// Top up the keypool
if (!walletInstance->TopUpKeyPool()) {
InitError(_("Unable to generate initial keys") += "\n");
- return NULL;
+ return nullptr;
}
walletInstance->SetBestChain(chainActive.GetLocator());
@@ -3890,8 +3954,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
- RegisterValidationInterface(walletInstance);
-
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
@@ -3903,6 +3965,10 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator);
}
+
+ walletInstance->m_last_block_processed = chainActive.Tip();
+ RegisterValidationInterface(walletInstance);
+
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
@@ -3930,7 +3996,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
}
nStart = GetTimeMillis();
- walletInstance->ScanForWalletTransactions(pindexRescan, true);
+ walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator());
walletInstance->dbw->IncrementUpdateCounter();
@@ -4046,8 +4112,15 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
+bool CWalletTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state)
{
- return ::AcceptToMemoryPool(mempool, state, tx, nullptr /* pfMissingInputs */,
+ // We must set fInMempool here - while it will be re-set to true by the
+ // entered-mempool callback, if we did not there would be a race where a
+ // user could call sendmoney in a loop and hit spurious out of funds errors
+ // because we think that the transaction they just generated's change is
+ // unavailable as we're not yet aware its in mempool.
+ bool ret = ::AcceptToMemoryPool(mempool, state, tx, nullptr /* pfMissingInputs */,
nullptr /* plTxnReplaced */, false /* bypass_limits */, nAbsurdFee);
+ fInMempool = ret;
+ return ret;
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index c4af192f36..1bd0be7bd0 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -6,18 +6,18 @@
#ifndef BITCOIN_WALLET_WALLET_H
#define BITCOIN_WALLET_WALLET_H
-#include "amount.h"
-#include "policy/feerate.h"
-#include "streams.h"
-#include "tinyformat.h"
-#include "ui_interface.h"
-#include "utilstrencodings.h"
-#include "validationinterface.h"
-#include "script/ismine.h"
-#include "script/sign.h"
-#include "wallet/crypter.h"
-#include "wallet/walletdb.h"
-#include "wallet/rpcwallet.h"
+#include <amount.h>
+#include <policy/feerate.h>
+#include <streams.h>
+#include <tinyformat.h>
+#include <ui_interface.h>
+#include <utilstrencodings.h>
+#include <validationinterface.h>
+#include <script/ismine.h>
+#include <script/sign.h>
+#include <wallet/crypter.h>
+#include <wallet/walletdb.h>
+#include <wallet/rpcwallet.h>
#include <algorithm>
#include <atomic>
@@ -214,10 +214,6 @@ public:
Init();
}
- /** Helper conversion operator to allow passing CMerkleTx where CTransaction is expected.
- * TODO: adapt callers and remove this operator. */
- operator const CTransaction&() const { return *tx; }
-
void Init()
{
hashBlock = uint256();
@@ -252,8 +248,6 @@ public:
int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
int GetBlocksToMaturity() const;
- /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
@@ -330,6 +324,7 @@ public:
mutable bool fImmatureWatchCreditCached;
mutable bool fAvailableWatchCreditCached;
mutable bool fChangeCached;
+ mutable bool fInMempool;
mutable CAmount nDebitCached;
mutable CAmount nCreditCached;
mutable CAmount nImmatureCreditCached;
@@ -369,6 +364,7 @@ public:
fImmatureWatchCreditCached = false;
fAvailableWatchCreditCached = false;
fChangeCached = false;
+ fInMempool = false;
nDebitCached = 0;
nCreditCached = 0;
nImmatureCreditCached = 0;
@@ -473,6 +469,9 @@ public:
// RelayWalletTransaction may only be called if fBroadcastTransactions!
bool RelayWalletTransaction(CConnman* connman);
+ /** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
+ bool AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& state);
+
std::set<uint256> GetConflicts() const;
};
@@ -722,6 +721,18 @@ private:
std::unique_ptr<CWalletDBWrapper> dbw;
+ /**
+ * The following is used to keep track of how far behind the wallet is
+ * from the chain sync, and to allow clients to block on us being caught up.
+ *
+ * Note that this is *not* how far we've processed, we may need some rescan
+ * to have seen all transactions in the chain, but is only used to track
+ * live BlockConnected callbacks.
+ *
+ * Protected by cs_main (see BlockUntilSyncedToCurrentChain)
+ */
+ const CBlockIndex* m_last_block_processed;
+
public:
/*
* Main wallet lock.
@@ -919,7 +930,8 @@ public:
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
int64_t RescanFromTime(int64_t startTime, bool update);
- CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
+ CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false);
+ void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
@@ -1106,6 +1118,14 @@ public:
caller must ensure the current wallet version is correct before calling
this function). */
bool SetHDMasterKey(const CPubKey& key);
+
+ /**
+ * Blocks until the wallet state is up-to-date to /at least/ the current
+ * chain at the time this function is entered
+ * Obviously holding cs_main/cs_wallet when going into this call may cause
+ * deadlock
+ */
+ void BlockUntilSyncedToCurrentChain();
};
/** A key allocated from the key pool. */
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index b7f873c1e4..66b8dea4ad 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -3,18 +3,18 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "wallet/walletdb.h"
-
-#include "base58.h"
-#include "consensus/tx_verify.h"
-#include "consensus/validation.h"
-#include "fs.h"
-#include "protocol.h"
-#include "serialize.h"
-#include "sync.h"
-#include "util.h"
-#include "utiltime.h"
-#include "wallet/wallet.h"
+#include <wallet/walletdb.h>
+
+#include <base58.h>
+#include <consensus/tx_verify.h>
+#include <consensus/validation.h>
+#include <fs.h>
+#include <protocol.h>
+#include <serialize.h>
+#include <sync.h>
+#include <util.h>
+#include <utiltime.h>
+#include <wallet/wallet.h>
#include <atomic>
@@ -268,7 +268,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx wtx;
ssValue >> wtx;
CValidationState state;
- if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
+ if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
return false;
// Undo serialize changes in 31600
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 3a146179af..0a85fc3bc0 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -6,10 +6,10 @@
#ifndef BITCOIN_WALLET_WALLETDB_H
#define BITCOIN_WALLET_WALLETDB_H
-#include "amount.h"
-#include "primitives/transaction.h"
-#include "wallet/db.h"
-#include "key.h"
+#include <amount.h>
+#include <primitives/transaction.h>
+#include <wallet/db.h>
+#include <key.h>
#include <list>
#include <stdint.h>
diff --git a/src/warnings.cpp b/src/warnings.cpp
index d4e33b701a..c52a1fdb47 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -3,10 +3,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "sync.h"
-#include "clientversion.h"
-#include "util.h"
-#include "warnings.h"
+#include <sync.h>
+#include <clientversion.h>
+#include <util.h>
+#include <warnings.h>
CCriticalSection cs_warnings;
std::string strMiscWarning;
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index 9f5cb3ba67..ce5c753eb4 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -2,8 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "zmqabstractnotifier.h"
-#include "util.h"
+#include <zmq/zmqabstractnotifier.h>
+#include <util.h>
CZMQAbstractNotifier::~CZMQAbstractNotifier()
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index 7828822149..6fbaba2036 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
-#include "zmqconfig.h"
+#include <zmq/zmqconfig.h>
class CBlockIndex;
class CZMQAbstractNotifier;
diff --git a/src/zmq/zmqconfig.h b/src/zmq/zmqconfig.h
index 610d7fbda4..ce8f3e13db 100644
--- a/src/zmq/zmqconfig.h
+++ b/src/zmq/zmqconfig.h
@@ -6,7 +6,7 @@
#define BITCOIN_ZMQ_ZMQCONFIG_H
#if defined(HAVE_CONFIG_H)
-#include "config/bitcoin-config.h"
+#include <config/bitcoin-config.h>
#endif
#include <stdarg.h>
@@ -16,8 +16,8 @@
#include <zmq.h>
#endif
-#include "primitives/block.h"
-#include "primitives/transaction.h"
+#include <primitives/block.h>
+#include <primitives/transaction.h>
void zmqError(const char *str);
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 9909395d84..26587d38a3 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "zmqnotificationinterface.h"
-#include "zmqpublishnotifier.h"
+#include <zmq/zmqnotificationinterface.h>
+#include <zmq/zmqpublishnotifier.h>
-#include "version.h"
-#include "validation.h"
-#include "streams.h"
-#include "util.h"
+#include <version.h>
+#include <validation.h>
+#include <streams.h>
+#include <util.h>
void zmqError(const char *str)
{
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index cb92216fa4..222d31e2ad 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
#define BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
-#include "validationinterface.h"
+#include <validationinterface.h>
#include <string>
#include <map>
#include <list>
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index ab54e2bb8b..acccb896c0 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -2,13 +2,13 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "chain.h"
-#include "chainparams.h"
-#include "streams.h"
-#include "zmqpublishnotifier.h"
-#include "validation.h"
-#include "util.h"
-#include "rpc/server.h"
+#include <chain.h>
+#include <chainparams.h>
+#include <streams.h>
+#include <zmq/zmqpublishnotifier.h>
+#include <validation.h>
+#include <util.h>
+#include <rpc/server.h>
static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index 1790fe5698..0e9bb23e5b 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
#define BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
-#include "zmqabstractnotifier.h"
+#include <zmq/zmqabstractnotifier.h>
class CBlockIndex;
diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py
index 65685c48b7..36761d359e 100755
--- a/test/functional/assumevalid.py
+++ b/test/functional/assumevalid.py
@@ -39,13 +39,12 @@ from test_framework.mininode import (CBlockHeader,
CTxIn,
CTxOut,
NetworkThread,
- NodeConn,
NodeConnCB,
msg_block,
msg_headers)
from test_framework.script import (CScript, OP_TRUE)
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (p2p_port, assert_equal)
+from test_framework.util import assert_equal
class BaseNode(NodeConnCB):
def send_header_for_blocks(self, new_blocks):
@@ -65,13 +64,13 @@ class AssumeValidTest(BitcoinTestFramework):
# signature so we can pass in the block hash as assumevalid.
self.start_node(0)
- def send_blocks_until_disconnected(self, node):
+ def send_blocks_until_disconnected(self, p2p_conn):
"""Keep sending blocks to the node until we're disconnected."""
for i in range(len(self.blocks)):
- if not node.connection:
+ if not p2p_conn.connection:
break
try:
- node.send_message(msg_block(self.blocks[i]))
+ p2p_conn.send_message(msg_block(self.blocks[i]))
except IOError as e:
assert str(e) == 'Not connected, no pushbuf'
break
@@ -97,13 +96,10 @@ class AssumeValidTest(BitcoinTestFramework):
def run_test(self):
# Connect to node0
- node0 = BaseNode()
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
- node0.add_connection(connections[0])
+ p2p0 = self.nodes[0].add_p2p_connection(BaseNode())
NetworkThread().start() # Start up network handling in another thread
- node0.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
# Build the blockchain
self.tip = int(self.nodes[0].getbestblockhash(), 16)
@@ -165,37 +161,33 @@ class AssumeValidTest(BitcoinTestFramework):
# Start node1 and node2 with assumevalid so they accept a block with a bad signature.
self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)])
- node1 = BaseNode() # connects to node1
- connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1))
- node1.add_connection(connections[1])
- node1.wait_for_verack()
+ p2p1 = self.nodes[1].add_p2p_connection(BaseNode())
+ p2p1.wait_for_verack()
self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)])
- node2 = BaseNode() # connects to node2
- connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
- node2.add_connection(connections[2])
- node2.wait_for_verack()
+ p2p2 = self.nodes[2].add_p2p_connection(BaseNode())
+ p2p2.wait_for_verack()
# send header lists to all three nodes
- node0.send_header_for_blocks(self.blocks[0:2000])
- node0.send_header_for_blocks(self.blocks[2000:])
- node1.send_header_for_blocks(self.blocks[0:2000])
- node1.send_header_for_blocks(self.blocks[2000:])
- node2.send_header_for_blocks(self.blocks[0:200])
+ p2p0.send_header_for_blocks(self.blocks[0:2000])
+ p2p0.send_header_for_blocks(self.blocks[2000:])
+ p2p1.send_header_for_blocks(self.blocks[0:2000])
+ p2p1.send_header_for_blocks(self.blocks[2000:])
+ p2p2.send_header_for_blocks(self.blocks[0:200])
# Send blocks to node0. Block 102 will be rejected.
- self.send_blocks_until_disconnected(node0)
+ self.send_blocks_until_disconnected(p2p0)
self.assert_blockchain_height(self.nodes[0], 101)
# Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
- node1.send_message(msg_block(self.blocks[i]))
+ p2p1.send_message(msg_block(self.blocks[i]))
# Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
- node1.sync_with_ping(120)
+ p2p1.sync_with_ping(120)
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
# Send blocks to node2. Block 102 will be rejected.
- self.send_blocks_until_disconnected(node2)
+ self.send_blocks_until_disconnected(p2p2)
self.assert_blockchain_height(self.nodes[2], 101)
if __name__ == '__main__':
diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py
index 2cd6df6e37..3073324798 100755
--- a/test/functional/bip65-cltv-p2p.py
+++ b/test/functional/bip65-cltv-p2p.py
@@ -66,15 +66,12 @@ class BIP65Test(BitcoinTestFramework):
self.setup_clean_chain = True
def run_test(self):
- node0 = NodeConnCB()
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
- node0.add_connection(connections[0])
+ self.nodes[0].add_p2p_connection(NodeConnCB())
NetworkThread().start() # Start up network handling in another thread
# wait_for_verack ensures that the P2P connection is fully up.
- node0.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
self.log.info("Mining %d blocks", CLTV_HEIGHT - 2)
self.coinbase_blocks = self.nodes[0].generate(CLTV_HEIGHT - 2)
@@ -95,7 +92,7 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 4")
@@ -104,15 +101,15 @@ class BIP65Test(BitcoinTestFramework):
block = create_block(tip, create_coinbase(CLTV_HEIGHT), block_time)
block.nVersion = 3
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
+ wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
with mininode_lock:
- assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
- assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)')
- assert_equal(node0.last_message["reject"].data, block.sha256)
- del node0.last_message["reject"]
+ assert_equal(self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
+ assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000003)')
+ assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
+ del self.nodes[0].p2p.last_message["reject"]
self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block")
block.nVersion = 4
@@ -125,7 +122,7 @@ class BIP65Test(BitcoinTestFramework):
# First we show that this tx is valid except for CLTV by getting it
# accepted to the mempool (which we can achieve with
# -promiscuousmempoolflags).
- node0.send_and_ping(msg_tx(spendtx))
+ self.nodes[0].p2p.send_and_ping(msg_tx(spendtx))
assert spendtx.hash in self.nodes[0].getrawmempool()
# Now we verify that a block with this transaction is invalid.
@@ -133,18 +130,18 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
+ wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
with mininode_lock:
- assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
- assert_equal(node0.last_message["reject"].data, block.sha256)
- if node0.last_message["reject"].code == REJECT_INVALID:
+ assert self.nodes[0].p2p.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
+ assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
+ if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
# Generic rejection when a block is invalid
- assert_equal(node0.last_message["reject"].reason, b'block-validation-failed')
+ assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'block-validation-failed')
else:
- assert b'Negative locktime' in node0.last_message["reject"].reason
+ assert b'Negative locktime' in self.nodes[0].p2p.last_message["reject"].reason
self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted")
spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1)
@@ -155,7 +152,7 @@ class BIP65Test(BitcoinTestFramework):
block.hashMerkleRoot = block.calc_merkle_root()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py
index c620d3e155..e5febde42d 100755
--- a/test/functional/bipdersig-p2p.py
+++ b/test/functional/bipdersig-p2p.py
@@ -54,14 +54,12 @@ class BIP66Test(BitcoinTestFramework):
self.setup_clean_chain = True
def run_test(self):
- node0 = NodeConnCB()
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
- node0.add_connection(connections[0])
+ self.nodes[0].add_p2p_connection(NodeConnCB())
+
NetworkThread().start() # Start up network handling in another thread
# wait_for_verack ensures that the P2P connection is fully up.
- node0.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
self.log.info("Mining %d blocks", DERSIG_HEIGHT - 2)
self.coinbase_blocks = self.nodes[0].generate(DERSIG_HEIGHT - 2)
@@ -83,7 +81,7 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
self.log.info("Test that blocks must now be at least version 3")
@@ -93,15 +91,15 @@ class BIP66Test(BitcoinTestFramework):
block.nVersion = 2
block.rehash()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
+ wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
with mininode_lock:
- assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE)
- assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)')
- assert_equal(node0.last_message["reject"].data, block.sha256)
- del node0.last_message["reject"]
+ assert_equal(self.nodes[0].p2p.last_message["reject"].code, REJECT_OBSOLETE)
+ assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'bad-version(0x00000002)')
+ assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
+ del self.nodes[0].p2p.last_message["reject"]
self.log.info("Test that transactions with non-DER signatures cannot appear in a block")
block.nVersion = 3
@@ -114,7 +112,7 @@ class BIP66Test(BitcoinTestFramework):
# First we show that this tx is valid except for DERSIG by getting it
# accepted to the mempool (which we can achieve with
# -promiscuousmempoolflags).
- node0.send_and_ping(msg_tx(spendtx))
+ self.nodes[0].p2p.send_and_ping(msg_tx(spendtx))
assert spendtx.hash in self.nodes[0].getrawmempool()
# Now we verify that a block with this transaction is invalid.
@@ -123,23 +121,23 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
- wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock)
+ wait_until(lambda: "reject" in self.nodes[0].p2p.last_message.keys(), lock=mininode_lock)
with mininode_lock:
# We can receive different reject messages depending on whether
# bitcoind is running with multiple script check threads. If script
# check threads are not in use, then transaction script validation
# happens sequentially, and bitcoind produces more specific reject
# reasons.
- assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
- assert_equal(node0.last_message["reject"].data, block.sha256)
- if node0.last_message["reject"].code == REJECT_INVALID:
+ assert self.nodes[0].p2p.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD]
+ assert_equal(self.nodes[0].p2p.last_message["reject"].data, block.sha256)
+ if self.nodes[0].p2p.last_message["reject"].code == REJECT_INVALID:
# Generic rejection when a block is invalid
- assert_equal(node0.last_message["reject"].reason, b'block-validation-failed')
+ assert_equal(self.nodes[0].p2p.last_message["reject"].reason, b'block-validation-failed')
else:
- assert b'Non-canonical DER signature' in node0.last_message["reject"].reason
+ assert b'Non-canonical DER signature' in self.nodes[0].p2p.last_message["reject"].reason
self.log.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted")
block.vtx[1] = create_transaction(self.nodes[0],
@@ -148,7 +146,7 @@ class BIP66Test(BitcoinTestFramework):
block.rehash()
block.solve()
- node0.send_and_ping(msg_block(block))
+ self.nodes[0].p2p.send_and_ping(msg_block(block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
if __name__ == '__main__':
diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py
index 4576cb036a..49fafbc9aa 100755
--- a/test/functional/blockchain.py
+++ b/test/functional/blockchain.py
@@ -5,6 +5,7 @@
"""Test RPCs related to blockchainstate.
Test the following RPCs:
+ - getblockchaininfo
- gettxoutsetinfo
- getdifficulty
- getbestblockhash
@@ -58,6 +59,7 @@ class BlockchainTest(BitcoinTestFramework):
'chainwork',
'difficulty',
'headers',
+ 'initialblockdownload',
'mediantime',
'pruned',
'size_on_disk',
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index 87d73ad14a..ba40f33016 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -18,7 +18,6 @@ from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.mininode import (
CInv,
NetworkThread,
- NodeConn,
NodeConnCB,
mininode_lock,
msg_block,
@@ -28,7 +27,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes,
- p2p_port,
wait_until,
)
@@ -134,16 +132,13 @@ class ExampleTest(BitcoinTestFramework):
"""Main test logic"""
# Create a P2P connection to one of the nodes
- node0 = BaseNode()
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
- node0.add_connection(connections[0])
+ self.nodes[0].add_p2p_connection(BaseNode())
# Start up network handling in another thread. This needs to be called
# after the P2P connections have been created.
NetworkThread().start()
# wait_for_verack ensures that the P2P connection is fully up.
- node0.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
# Generating a block on one of the nodes will get us out of IBD
blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
@@ -180,7 +175,7 @@ class ExampleTest(BitcoinTestFramework):
block.solve()
block_message = msg_block(block)
# Send message is used to send a P2P message to the node over our NodeConn connection
- node0.send_message(block_message)
+ self.nodes[0].p2p.send_message(block_message)
self.tip = block.sha256
blocks.append(self.tip)
self.block_time += 1
@@ -193,28 +188,26 @@ class ExampleTest(BitcoinTestFramework):
connect_nodes(self.nodes[1], 2)
self.log.info("Add P2P connection to node2")
- node2 = BaseNode()
- connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2))
- node2.add_connection(connections[1])
- node2.wait_for_verack()
+ self.nodes[2].add_p2p_connection(BaseNode())
+ self.nodes[2].p2p.wait_for_verack()
self.log.info("Wait for node2 reach current tip. Test that it has propagated all the blocks to us")
getdata_request = msg_getdata()
for block in blocks:
getdata_request.inv.append(CInv(2, block))
- node2.send_message(getdata_request)
+ self.nodes[2].p2p.send_message(getdata_request)
# wait_until() will loop until a predicate condition is met. Use it to test properties of the
# NodeConnCB objects.
- wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5, lock=mininode_lock)
+ wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock)
self.log.info("Check that each block was received only once")
# The network thread uses a global lock on data access to the NodeConn objects when sending and receiving
# messages. The test thread should acquire the global lock before accessing any NodeConn data to avoid locking
# and synchronization issues. Note wait_until() acquires this global lock when testing the predicate.
with mininode_lock:
- for block in node2.block_receive_map.values():
+ for block in self.nodes[2].p2p.block_receive_map.values():
assert_equal(block, 1)
if __name__ == '__main__':
diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py
index c1a42870ec..a691595f15 100755
--- a/test/functional/importmulti.py
+++ b/test/functional/importmulti.py
@@ -160,6 +160,18 @@ class ImportMultiTest (BitcoinTestFramework):
assert_equal(address_assert['ismine'], True)
assert_equal(address_assert['timestamp'], timestamp)
+ self.log.info("Should not import an address with private key if is already imported")
+ result = self.nodes[1].importmulti([{
+ "scriptPubKey": {
+ "address": address['address']
+ },
+ "timestamp": "now",
+ "keys": [ self.nodes[0].dumpprivkey(address['address']) ]
+ }])
+ assert_equal(result[0]['success'], False)
+ assert_equal(result[0]['error']['code'], -4)
+ assert_equal(result[0]['error']['message'], 'The wallet already contains the private key for this address or script')
+
# Address + Private key + watchonly
self.log.info("Should not import an address with private key and with watchonly")
address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress())
diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py
index 6f428388ec..67e7744bf8 100755
--- a/test/functional/listsinceblock.py
+++ b/test/functional/listsinceblock.py
@@ -5,7 +5,7 @@
"""Test the listsincelast RPC."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
+from test_framework.util import assert_equal, assert_array_result, assert_raises_rpc_error
class ListSinceBlockTest (BitcoinTestFramework):
def set_test_params(self):
@@ -16,10 +16,43 @@ class ListSinceBlockTest (BitcoinTestFramework):
self.nodes[2].generate(101)
self.sync_all()
+ self.test_no_blockhash()
+ self.test_invalid_blockhash()
self.test_reorg()
self.test_double_spend()
self.test_double_send()
+ def test_no_blockhash(self):
+ txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ blockhash, = self.nodes[2].generate(1)
+ self.sync_all()
+
+ txs = self.nodes[0].listtransactions()
+ assert_array_result(txs, {"txid": txid}, {
+ "category": "receive",
+ "amount": 1,
+ "blockhash": blockhash,
+ "confirmations": 1,
+ })
+ assert_equal(
+ self.nodes[0].listsinceblock(),
+ {"lastblock": blockhash,
+ "removed": [],
+ "transactions": txs})
+ assert_equal(
+ self.nodes[0].listsinceblock(""),
+ {"lastblock": blockhash,
+ "removed": [],
+ "transactions": txs})
+
+ def test_invalid_blockhash(self):
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
+ "42759cde25462784395a337460bde75f58e73d3f08bd31fdc3507cbac856a2c4")
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
+ "0000000000000000000000000000000000000000000000000000000000000000")
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].listsinceblock,
+ "invalid-hex")
+
def test_reorg(self):
'''
`listsinceblock` did not behave correctly when handed a block that was
diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py
index 1f402798e7..88e2ff2e16 100755
--- a/test/functional/maxuploadtarget.py
+++ b/test/functional/maxuploadtarget.py
@@ -49,19 +49,17 @@ class MaxUploadTest(BitcoinTestFramework):
# Generate some old blocks
self.nodes[0].generate(130)
- # test_nodes[0] will only request old blocks
- # test_nodes[1] will only request new blocks
- # test_nodes[2] will test resetting the counters
- test_nodes = []
- connections = []
+ # p2p_conns[0] will only request old blocks
+ # p2p_conns[1] will only request new blocks
+ # p2p_conns[2] will test resetting the counters
+ p2p_conns = []
- for i in range(3):
- test_nodes.append(TestNode())
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i]))
- test_nodes[i].add_connection(connections[i])
+ for _ in range(3):
+ p2p_conns.append(self.nodes[0].add_p2p_connection(TestNode()))
NetworkThread().start() # Start up network handling in another thread
- [x.wait_for_verack() for x in test_nodes]
+ for p2pc in p2p_conns:
+ p2pc.wait_for_verack()
# Test logic begins here
@@ -83,7 +81,7 @@ class MaxUploadTest(BitcoinTestFramework):
big_new_block = self.nodes[0].getbestblockhash()
big_new_block = int(big_new_block, 16)
- # test_nodes[0] will test what happens if we just keep requesting the
+ # p2p_conns[0] will test what happens if we just keep requesting the
# the same big old block too many times (expect: disconnect)
getdata_request = msg_getdata()
@@ -97,34 +95,34 @@ class MaxUploadTest(BitcoinTestFramework):
# 576MB will be reserved for relaying new blocks, so expect this to
# succeed for ~235 tries.
for i in range(success_count):
- test_nodes[0].send_message(getdata_request)
- test_nodes[0].sync_with_ping()
- assert_equal(test_nodes[0].block_receive_map[big_old_block], i+1)
+ p2p_conns[0].send_message(getdata_request)
+ p2p_conns[0].sync_with_ping()
+ assert_equal(p2p_conns[0].block_receive_map[big_old_block], i+1)
assert_equal(len(self.nodes[0].getpeerinfo()), 3)
# At most a couple more tries should succeed (depending on how long
# the test has been running so far).
for i in range(3):
- test_nodes[0].send_message(getdata_request)
- test_nodes[0].wait_for_disconnect()
+ p2p_conns[0].send_message(getdata_request)
+ p2p_conns[0].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 2)
self.log.info("Peer 0 disconnected after downloading old block too many times")
- # Requesting the current block on test_nodes[1] should succeed indefinitely,
+ # Requesting the current block on p2p_conns[1] should succeed indefinitely,
# even when over the max upload target.
# We'll try 800 times
getdata_request.inv = [CInv(2, big_new_block)]
for i in range(800):
- test_nodes[1].send_message(getdata_request)
- test_nodes[1].sync_with_ping()
- assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1)
+ p2p_conns[1].send_message(getdata_request)
+ p2p_conns[1].sync_with_ping()
+ assert_equal(p2p_conns[1].block_receive_map[big_new_block], i+1)
self.log.info("Peer 1 able to repeatedly download new block")
- # But if test_nodes[1] tries for an old block, it gets disconnected too.
+ # But if p2p_conns[1] tries for an old block, it gets disconnected too.
getdata_request.inv = [CInv(2, big_old_block)]
- test_nodes[1].send_message(getdata_request)
- test_nodes[1].wait_for_disconnect()
+ p2p_conns[1].send_message(getdata_request)
+ p2p_conns[1].wait_for_disconnect()
assert_equal(len(self.nodes[0].getpeerinfo()), 1)
self.log.info("Peer 1 disconnected after trying to download old block")
@@ -132,39 +130,37 @@ class MaxUploadTest(BitcoinTestFramework):
self.log.info("Advancing system time on node to clear counters...")
# If we advance the time by 24 hours, then the counters should reset,
- # and test_nodes[2] should be able to retrieve the old block.
+ # and p2p_conns[2] should be able to retrieve the old block.
self.nodes[0].setmocktime(int(time.time()))
- test_nodes[2].sync_with_ping()
- test_nodes[2].send_message(getdata_request)
- test_nodes[2].sync_with_ping()
- assert_equal(test_nodes[2].block_receive_map[big_old_block], 1)
+ p2p_conns[2].sync_with_ping()
+ p2p_conns[2].send_message(getdata_request)
+ p2p_conns[2].sync_with_ping()
+ assert_equal(p2p_conns[2].block_receive_map[big_old_block], 1)
self.log.info("Peer 2 able to download old block")
- [c.disconnect_node() for c in connections]
+ self.nodes[0].disconnect_p2ps()
#stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1
self.log.info("Restarting nodes with -whitelist=127.0.0.1")
self.stop_node(0)
self.start_node(0, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"])
- #recreate/reconnect a test node
- test_nodes = [TestNode()]
- connections = [NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[0])]
- test_nodes[0].add_connection(connections[0])
+ # Reconnect to self.nodes[0]
+ self.nodes[0].add_p2p_connection(TestNode())
NetworkThread().start() # Start up network handling in another thread
- test_nodes[0].wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
#retrieve 20 blocks which should be enough to break the 1MB limit
getdata_request.inv = [CInv(2, big_new_block)]
for i in range(20):
- test_nodes[0].send_message(getdata_request)
- test_nodes[0].sync_with_ping()
- assert_equal(test_nodes[0].block_receive_map[big_new_block], i+1)
+ self.nodes[0].p2p.send_message(getdata_request)
+ self.nodes[0].p2p.sync_with_ping()
+ assert_equal(self.nodes[0].p2p.block_receive_map[big_new_block], i+1)
getdata_request.inv = [CInv(2, big_old_block)]
- test_nodes[0].send_and_ping(getdata_request)
+ self.nodes[0].p2p.send_and_ping(getdata_request)
assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the whitelist
self.log.info("Peer still connected after trying to download old block (whitelisted)")
diff --git a/test/functional/minchainwork.py b/test/functional/minchainwork.py
index c7579d2548..35cd7ad141 100755
--- a/test/functional/minchainwork.py
+++ b/test/functional/minchainwork.py
@@ -27,6 +27,7 @@ class MinimumChainWorkTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
+
self.extra_args = [[], ["-minimumchainwork=0x65"], ["-minimumchainwork=0x65"]]
self.node_min_work = [0, 101, 101]
@@ -74,6 +75,13 @@ class MinimumChainWorkTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.log.info("Verifying nodes are all synced")
+
+ # Because nodes in regtest are all manual connections (eg using
+ # addnode), node1 should not have disconnected node0. If not for that,
+ # we'd expect node1 to have disconnected node0 for serving an
+ # insufficient work chain, in which case we'd need to reconnect them to
+ # continue the test.
+
self.sync_all()
self.log.info("Blockcounts: %s", [n.getblockcount() for n in self.nodes])
diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py
index f55da76819..7a0fbce477 100755
--- a/test/functional/multiwallet.py
+++ b/test/functional/multiwallet.py
@@ -7,6 +7,7 @@
Verify that a bitcoind node can load multiple wallet files
"""
import os
+import shutil
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
@@ -29,6 +30,11 @@ class MultiWalletTest(BitcoinTestFramework):
os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11'))
self.assert_start_raises_init_error(0, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.')
+ # should not initialize if one wallet is a copy of another
+ shutil.copyfile(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w2'),
+ os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w22'))
+ self.assert_start_raises_init_error(0, ['-wallet=w2', '-wallet=w22'], 'duplicates fileid')
+
# should not initialize if wallet file is a symlink
os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12'))
self.assert_start_raises_init_error(0, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.')
diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py
index 91c4550653..7bc7c168f4 100755
--- a/test/functional/nulldummy.py
+++ b/test/functional/nulldummy.py
@@ -40,7 +40,9 @@ class NULLDUMMYTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
- self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness']]
+ # This script tests NULLDUMMY activation, which is part of the 'segwit' deployment, so we go through
+ # normal segwit activation here (and don't use the default always-on behaviour).
+ self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness', '-vbparams=segwit:0:999999999999']]
def run_test(self):
self.address = self.nodes[0].getnewaddress()
diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py
index 5b6429b410..ca0e0080a1 100755
--- a/test/functional/p2p-acceptblock.py
+++ b/test/functional/p2p-acceptblock.py
@@ -4,37 +4,32 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test processing of unrequested blocks.
-Since behavior differs when receiving unrequested blocks from whitelisted peers
-versus non-whitelisted peers, this tests the behavior of both (effectively two
-separate tests running in parallel).
+Setup: two nodes, node0+node1, not connected to each other. Node1 will have
+nMinimumChainWork set to 0x10, so it won't process low-work unrequested blocks.
-Setup: two nodes, node0 and node1, not connected to each other. Node0 does not
-whitelist localhost, but node1 does. They will each be on their own chain for
-this test.
-
-We have one NodeConn connection to each, test_node and white_node respectively.
+We have one NodeConn connection to node0 called test_node, and one to node1
+called min_work_node.
The test:
1. Generate one block on each node, to leave IBD.
2. Mine a new block on each tip, and deliver to each node from node's peer.
- The tip should advance.
+ The tip should advance for node0, but node1 should skip processing due to
+ nMinimumChainWork.
+
+Node1 is unused in tests 3-7:
-3. Mine a block that forks the previous block, and deliver to each node from
- corresponding peer.
- Node0 should not process this block (just accept the header), because it is
- unrequested and doesn't have more work than the tip.
- Node1 should process because this is coming from a whitelisted peer.
+3. Mine a block that forks from the genesis block, and deliver to test_node.
+ Node0 should not process this block (just accept the header), because it
+ is unrequested and doesn't have more or equal work to the tip.
-4. Send another block that builds on the forking block.
- Node0 should process this block but be stuck on the shorter chain, because
- it's missing an intermediate block.
- Node1 should reorg to this longer chain.
+4a,b. Send another two blocks that build on the forking block.
+ Node0 should process the second block but be stuck on the shorter chain,
+ because it's missing an intermediate block.
-4b.Send 288 more blocks on the longer chain.
+4c.Send 288 more blocks on the longer chain (the number of blocks ahead
+ we currently store).
Node0 should process all but the last block (too far ahead in height).
- Send all headers to Node1, and then send the last block in that chain.
- Node1 should accept the block because it's coming from a whitelisted peer.
5. Send a duplicate of the block in #3 to Node0.
Node0 should not process the block because it is unrequested, and stay on
@@ -46,13 +41,21 @@ The test:
7. Send Node0 the missing block again.
Node0 should process and the tip should advance.
+
+8. Create a fork which is invalid at a height longer than the current chain
+ (ie to which the node will try to reorg) but which has headers built on top
+ of the invalid block. Check that we get disconnected if we send more headers
+ on the chain the node now knows to be invalid.
+
+9. Test Node1 is able to sync when connected to node0 (which should have sufficient
+ work on its chain).
"""
from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
import time
-from test_framework.blocktools import create_block, create_coinbase
+from test_framework.blocktools import create_block, create_coinbase, create_transaction
class AcceptBlockTest(BitcoinTestFramework):
def add_options(self, parser):
@@ -63,37 +66,35 @@ class AcceptBlockTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.extra_args = [[], ["-whitelist=127.0.0.1"]]
+ self.extra_args = [[], ["-minimumchainwork=0x10"]]
def setup_network(self):
# Node0 will be used to test behavior of processing unrequested blocks
# from peers which are not whitelisted, while Node1 will be used for
# the whitelisted case.
+ # Node2 will be used for non-whitelisted peers to test the interaction
+ # with nMinimumChainWork.
self.setup_nodes()
def run_test(self):
# Setup the p2p connections and start up the network thread.
- test_node = NodeConnCB() # connects to node0 (not whitelisted)
- white_node = NodeConnCB() # connects to node1 (whitelisted)
-
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
- connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node))
- test_node.add_connection(connections[0])
- white_node.add_connection(connections[1])
+ # test_node connects to node0 (not whitelisted)
+ test_node = self.nodes[0].add_p2p_connection(NodeConnCB())
+ # min_work_node connects to node1
+ min_work_node = self.nodes[1].add_p2p_connection(NodeConnCB())
NetworkThread().start() # Start up network handling in another thread
# Test logic begins here
test_node.wait_for_verack()
- white_node.wait_for_verack()
+ min_work_node.wait_for_verack()
- # 1. Have both nodes mine a block (leave IBD)
+ # 1. Have nodes mine a block (leave IBD)
[ n.generate(1) for n in self.nodes ]
tips = [ int("0x" + n.getbestblockhash(), 0) for n in self.nodes ]
# 2. Send one block that builds on each tip.
- # This should be accepted.
+ # This should be accepted by node0
blocks_h2 = [] # the height 2 blocks on each node's chain
block_time = int(time.time()) + 1
for i in range(2):
@@ -101,95 +102,116 @@ class AcceptBlockTest(BitcoinTestFramework):
blocks_h2[i].solve()
block_time += 1
test_node.send_message(msg_block(blocks_h2[0]))
- white_node.send_message(msg_block(blocks_h2[1]))
+ min_work_node.send_message(msg_block(blocks_h2[1]))
- [ x.sync_with_ping() for x in [test_node, white_node] ]
+ for x in [test_node, min_work_node]:
+ x.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 2)
- assert_equal(self.nodes[1].getblockcount(), 2)
- self.log.info("First height 2 block accepted by both nodes")
+ assert_equal(self.nodes[1].getblockcount(), 1)
+ self.log.info("First height 2 block accepted by node0; correctly rejected by node1")
- # 3. Send another block that builds on the original tip.
- blocks_h2f = [] # Blocks at height 2 that fork off the main chain
- for i in range(2):
- blocks_h2f.append(create_block(tips[i], create_coinbase(2), blocks_h2[i].nTime+1))
- blocks_h2f[i].solve()
- test_node.send_message(msg_block(blocks_h2f[0]))
- white_node.send_message(msg_block(blocks_h2f[1]))
+ # 3. Send another block that builds on genesis.
+ block_h1f = create_block(int("0x" + self.nodes[0].getblockhash(0), 0), create_coinbase(1), block_time)
+ block_time += 1
+ block_h1f.solve()
+ test_node.send_message(msg_block(block_h1f))
- [ x.sync_with_ping() for x in [test_node, white_node] ]
+ test_node.sync_with_ping()
+ tip_entry_found = False
for x in self.nodes[0].getchaintips():
- if x['hash'] == blocks_h2f[0].hash:
+ if x['hash'] == block_h1f.hash:
assert_equal(x['status'], "headers-only")
+ tip_entry_found = True
+ assert(tip_entry_found)
+ assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_h1f.hash)
+
+ # 4. Send another two block that build on the fork.
+ block_h2f = create_block(block_h1f.sha256, create_coinbase(2), block_time)
+ block_time += 1
+ block_h2f.solve()
+ test_node.send_message(msg_block(block_h2f))
- for x in self.nodes[1].getchaintips():
- if x['hash'] == blocks_h2f[1].hash:
- assert_equal(x['status'], "valid-headers")
+ test_node.sync_with_ping()
+ # Since the earlier block was not processed by node, the new block
+ # can't be fully validated.
+ tip_entry_found = False
+ for x in self.nodes[0].getchaintips():
+ if x['hash'] == block_h2f.hash:
+ assert_equal(x['status'], "headers-only")
+ tip_entry_found = True
+ assert(tip_entry_found)
- self.log.info("Second height 2 block accepted only from whitelisted peer")
+ # But this block should be accepted by node since it has equal work.
+ self.nodes[0].getblock(block_h2f.hash)
+ self.log.info("Second height 2 block accepted, but not reorg'ed to")
- # 4. Now send another block that builds on the forking chain.
- blocks_h3 = []
- for i in range(2):
- blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(3), blocks_h2f[i].nTime+1))
- blocks_h3[i].solve()
- test_node.send_message(msg_block(blocks_h3[0]))
- white_node.send_message(msg_block(blocks_h3[1]))
+ # 4b. Now send another block that builds on the forking chain.
+ block_h3 = create_block(block_h2f.sha256, create_coinbase(3), block_h2f.nTime+1)
+ block_h3.solve()
+ test_node.send_message(msg_block(block_h3))
- [ x.sync_with_ping() for x in [test_node, white_node] ]
- # Since the earlier block was not processed by node0, the new block
+ test_node.sync_with_ping()
+ # Since the earlier block was not processed by node, the new block
# can't be fully validated.
+ tip_entry_found = False
for x in self.nodes[0].getchaintips():
- if x['hash'] == blocks_h3[0].hash:
+ if x['hash'] == block_h3.hash:
assert_equal(x['status'], "headers-only")
+ tip_entry_found = True
+ assert(tip_entry_found)
+ self.nodes[0].getblock(block_h3.hash)
+
+ # But this block should be accepted by node since it has more work.
+ self.nodes[0].getblock(block_h3.hash)
+ self.log.info("Unrequested more-work block accepted")
+
+ # 4c. Now mine 288 more blocks and deliver; all should be processed but
+ # the last (height-too-high) on node (as long as its not missing any headers)
+ tip = block_h3
+ all_blocks = []
+ for i in range(288):
+ next_block = create_block(tip.sha256, create_coinbase(i + 4), tip.nTime+1)
+ next_block.solve()
+ all_blocks.append(next_block)
+ tip = next_block
+
+ # Now send the block at height 5 and check that it wasn't accepted (missing header)
+ test_node.send_message(msg_block(all_blocks[1]))
+ test_node.sync_with_ping()
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblock, all_blocks[1].hash)
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblockheader, all_blocks[1].hash)
- # But this block should be accepted by node0 since it has more work.
- self.nodes[0].getblock(blocks_h3[0].hash)
- self.log.info("Unrequested more-work block accepted from non-whitelisted peer")
+ # The block at height 5 should be accepted if we provide the missing header, though
+ headers_message = msg_headers()
+ headers_message.headers.append(CBlockHeader(all_blocks[0]))
+ test_node.send_message(headers_message)
+ test_node.send_message(msg_block(all_blocks[1]))
+ test_node.sync_with_ping()
+ self.nodes[0].getblock(all_blocks[1].hash)
- # Node1 should have accepted and reorged.
- assert_equal(self.nodes[1].getblockcount(), 3)
- self.log.info("Successfully reorged to length 3 chain from whitelisted peer")
+ # Now send the blocks in all_blocks
+ for i in range(288):
+ test_node.send_message(msg_block(all_blocks[i]))
+ test_node.sync_with_ping()
- # 4b. Now mine 288 more blocks and deliver; all should be processed but
- # the last (height-too-high) on node0. Node1 should process the tip if
- # we give it the headers chain leading to the tip.
- tips = blocks_h3
- headers_message = msg_headers()
- all_blocks = [] # node0's blocks
- for j in range(2):
- for i in range(288):
- next_block = create_block(tips[j].sha256, create_coinbase(i + 4), tips[j].nTime+1)
- next_block.solve()
- if j==0:
- test_node.send_message(msg_block(next_block))
- all_blocks.append(next_block)
- else:
- headers_message.headers.append(CBlockHeader(next_block))
- tips[j] = next_block
-
- time.sleep(2)
# Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead
for x in all_blocks[:-1]:
self.nodes[0].getblock(x.hash)
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash)
- headers_message.headers.pop() # Ensure the last block is unrequested
- white_node.send_message(headers_message) # Send headers leading to tip
- white_node.send_message(msg_block(tips[1])) # Now deliver the tip
- white_node.sync_with_ping()
- self.nodes[1].getblock(tips[1].hash)
- self.log.info("Unrequested block far ahead of tip accepted from whitelisted peer")
-
# 5. Test handling of unrequested block on the node that didn't process
# Should still not be processed (even though it has a child that has more
# work).
- test_node.send_message(msg_block(blocks_h2f[0]))
- # Here, if the sleep is too short, the test could falsely succeed (if the
- # node hasn't processed the block by the time the sleep returns, and then
- # the node processes it and incorrectly advances the tip).
- # But this would be caught later on, when we verify that an inv triggers
- # a getdata request for this block.
+ # The node should have requested the blocks at some point, so
+ # disconnect/reconnect first
+
+ self.nodes[0].disconnect_p2ps()
+ test_node = self.nodes[0].add_p2p_connection(NodeConnCB())
+
+ test_node.wait_for_verack()
+ test_node.send_message(msg_block(block_h1f))
+
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 2)
self.log.info("Unrequested block that would complete more-work chain was ignored")
@@ -200,24 +222,98 @@ class AcceptBlockTest(BitcoinTestFramework):
with mininode_lock:
# Clear state so we can check the getdata request
test_node.last_message.pop("getdata", None)
- test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))
+ test_node.send_message(msg_inv([CInv(2, block_h3.sha256)]))
test_node.sync_with_ping()
with mininode_lock:
getdata = test_node.last_message["getdata"]
# Check that the getdata includes the right block
- assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
+ assert_equal(getdata.inv[0].hash, block_h1f.sha256)
self.log.info("Inv at tip triggered getdata for unprocessed block")
# 7. Send the missing block for the third time (now it is requested)
- test_node.send_message(msg_block(blocks_h2f[0]))
+ test_node.send_message(msg_block(block_h1f))
test_node.sync_with_ping()
assert_equal(self.nodes[0].getblockcount(), 290)
+ self.nodes[0].getblock(all_blocks[286].hash)
+ assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
+ assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[287].hash)
self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
- [ c.disconnect_node() for c in connections ]
+ # 8. Create a chain which is invalid at a height longer than the
+ # current chain, but which has more blocks on top of that
+ block_289f = create_block(all_blocks[284].sha256, create_coinbase(289), all_blocks[284].nTime+1)
+ block_289f.solve()
+ block_290f = create_block(block_289f.sha256, create_coinbase(290), block_289f.nTime+1)
+ block_290f.solve()
+ block_291 = create_block(block_290f.sha256, create_coinbase(291), block_290f.nTime+1)
+ # block_291 spends a coinbase below maturity!
+ block_291.vtx.append(create_transaction(block_290f.vtx[0], 0, b"42", 1))
+ block_291.hashMerkleRoot = block_291.calc_merkle_root()
+ block_291.solve()
+ block_292 = create_block(block_291.sha256, create_coinbase(292), block_291.nTime+1)
+ block_292.solve()
+
+ # Now send all the headers on the chain and enough blocks to trigger reorg
+ headers_message = msg_headers()
+ headers_message.headers.append(CBlockHeader(block_289f))
+ headers_message.headers.append(CBlockHeader(block_290f))
+ headers_message.headers.append(CBlockHeader(block_291))
+ headers_message.headers.append(CBlockHeader(block_292))
+ test_node.send_message(headers_message)
+
+ test_node.sync_with_ping()
+ tip_entry_found = False
+ for x in self.nodes[0].getchaintips():
+ if x['hash'] == block_292.hash:
+ assert_equal(x['status'], "headers-only")
+ tip_entry_found = True
+ assert(tip_entry_found)
+ assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash)
+
+ test_node.send_message(msg_block(block_289f))
+ test_node.send_message(msg_block(block_290f))
+
+ test_node.sync_with_ping()
+ self.nodes[0].getblock(block_289f.hash)
+ self.nodes[0].getblock(block_290f.hash)
+
+ test_node.send_message(msg_block(block_291))
+
+ # At this point we've sent an obviously-bogus block, wait for full processing
+ # without assuming whether we will be disconnected or not
+ try:
+ # Only wait a short while so the test doesn't take forever if we do get
+ # disconnected
+ test_node.sync_with_ping(timeout=1)
+ except AssertionError:
+ test_node.wait_for_disconnect()
+
+ self.nodes[0].disconnect_p2ps()
+ test_node = self.nodes[0].add_p2p_connection(NodeConnCB())
+
+ NetworkThread().start() # Start up network handling in another thread
+ test_node.wait_for_verack()
+
+ # We should have failed reorg and switched back to 290 (but have block 291)
+ assert_equal(self.nodes[0].getblockcount(), 290)
+ assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
+ assert_equal(self.nodes[0].getblock(block_291.hash)["confirmations"], -1)
+
+ # Now send a new header on the invalid chain, indicating we're forked off, and expect to get disconnected
+ block_293 = create_block(block_292.sha256, create_coinbase(293), block_292.nTime+1)
+ block_293.solve()
+ headers_message = msg_headers()
+ headers_message.headers.append(CBlockHeader(block_293))
+ test_node.send_message(headers_message)
+ test_node.wait_for_disconnect()
+
+ # 9. Connect node1 to node0 and ensure it is able to sync
+ connect_nodes(self.nodes[0], 1)
+ sync_blocks([self.nodes[0], self.nodes[1]])
+ self.log.info("Successfully synced nodes 1 and 0")
if __name__ == '__main__':
AcceptBlockTest().main()
diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py
index 94513d3f43..d2c4d39305 100755
--- a/test/functional/p2p-compactblocks.py
+++ b/test/functional/p2p-compactblocks.py
@@ -93,7 +93,9 @@ class CompactBlocksTest(BitcoinTestFramework):
self.setup_clean_chain = True
# Node0 = pre-segwit, node1 = segwit-aware
self.num_nodes = 2
- self.extra_args = [["-vbparams=segwit:0:0"], ["-txindex"]]
+ # This test was written assuming SegWit is activated using BIP9 at height 432 (3x confirmation window).
+ # TODO: Rewrite this test to support SegWit being always active.
+ self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex"]]
self.utxos = []
def build_block_on_tip(self, node, segwit=False):
@@ -786,23 +788,12 @@ class CompactBlocksTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- self.test_node = TestNode()
- self.segwit_node = TestNode()
- self.old_node = TestNode() # version 1 peer <--> segwit node
-
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.test_node))
- connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1],
- self.segwit_node, services=NODE_NETWORK|NODE_WITNESS))
- connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1],
- self.old_node, services=NODE_NETWORK))
- self.test_node.add_connection(connections[0])
- self.segwit_node.add_connection(connections[1])
- self.old_node.add_connection(connections[2])
+ self.test_node = self.nodes[0].add_p2p_connection(TestNode())
+ self.segwit_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK|NODE_WITNESS)
+ self.old_node = self.nodes[1].add_p2p_connection(TestNode(), services=NODE_NETWORK)
NetworkThread().start() # Start up network handling in another thread
- # Test logic begins here
self.test_node.wait_for_verack()
# We will need UTXOs to construct transactions in later tests.
diff --git a/test/functional/p2p-feefilter.py b/test/functional/p2p-feefilter.py
index 8c92365ced..624278df40 100755
--- a/test/functional/p2p-feefilter.py
+++ b/test/functional/p2p-feefilter.py
@@ -48,25 +48,23 @@ class FeeFilterTest(BitcoinTestFramework):
sync_blocks(self.nodes)
# Setup the p2p connections and start up the network thread.
- test_node = TestNode()
- connection = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node)
- test_node.add_connection(connection)
+ self.nodes[0].add_p2p_connection(TestNode())
NetworkThread().start()
- test_node.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
# Test that invs are received for all txs at feerate of 20 sat/byte
node1.settxfee(Decimal("0.00020000"))
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- assert(allInvsMatch(txids, test_node))
- test_node.clear_invs()
+ assert(allInvsMatch(txids, self.nodes[0].p2p))
+ self.nodes[0].p2p.clear_invs()
# Set a filter of 15 sat/byte
- test_node.send_and_ping(msg_feefilter(15000))
+ self.nodes[0].p2p.send_and_ping(msg_feefilter(15000))
# Test that txs are still being received (paying 20 sat/byte)
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- assert(allInvsMatch(txids, test_node))
- test_node.clear_invs()
+ assert(allInvsMatch(txids, self.nodes[0].p2p))
+ self.nodes[0].p2p.clear_invs()
# Change tx fee rate to 10 sat/byte and test they are no longer received
node1.settxfee(Decimal("0.00010000"))
@@ -82,14 +80,14 @@ class FeeFilterTest(BitcoinTestFramework):
# as well.
node0.settxfee(Decimal("0.00020000"))
txids = [node0.sendtoaddress(node0.getnewaddress(), 1)]
- assert(allInvsMatch(txids, test_node))
- test_node.clear_invs()
+ assert(allInvsMatch(txids, self.nodes[0].p2p))
+ self.nodes[0].p2p.clear_invs()
# Remove fee filter and check that txs are received again
- test_node.send_and_ping(msg_feefilter(0))
+ self.nodes[0].p2p.send_and_ping(msg_feefilter(0))
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- assert(allInvsMatch(txids, test_node))
- test_node.clear_invs()
+ assert(allInvsMatch(txids, self.nodes[0].p2p))
+ self.nodes[0].p2p.clear_invs()
if __name__ == '__main__':
FeeFilterTest().main()
diff --git a/test/functional/p2p-fingerprint.py b/test/functional/p2p-fingerprint.py
index fe60c6cd46..4b6446fc5b 100755
--- a/test/functional/p2p-fingerprint.py
+++ b/test/functional/p2p-fingerprint.py
@@ -14,7 +14,6 @@ from test_framework.blocktools import (create_block, create_coinbase)
from test_framework.mininode import (
CInv,
NetworkThread,
- NodeConn,
NodeConnCB,
msg_headers,
msg_block,
@@ -77,11 +76,7 @@ class P2PFingerprintTest(BitcoinTestFramework):
# This does not currently test that stale blocks timestamped within the
# last month but that have over a month's worth of work are also withheld.
def run_test(self):
- node0 = NodeConnCB()
-
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0))
- node0.add_connection(connections[0])
+ node0 = self.nodes[0].add_p2p_connection(NodeConnCB())
NetworkThread().start()
node0.wait_for_verack()
diff --git a/test/functional/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py
index 1d969fc7c1..f19b845a32 100755
--- a/test/functional/p2p-fullblocktest.py
+++ b/test/functional/p2p-fullblocktest.py
@@ -20,7 +20,7 @@ from test_framework.key import CECKey
from test_framework.script import *
import struct
-class PreviousSpendableOutput(object):
+class PreviousSpendableOutput():
def __init__(self, tx = CTransaction(), n = -1):
self.tx = tx
self.n = n # the output we're spending
diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py
index 1dc8f72cd6..719a03914d 100755
--- a/test/functional/p2p-leaktests.py
+++ b/test/functional/p2p-leaktests.py
@@ -39,7 +39,6 @@ class CLazyNode(NodeConnCB):
def on_reject(self, conn, message): self.bad_message(message)
def on_inv(self, conn, message): self.bad_message(message)
def on_addr(self, conn, message): self.bad_message(message)
- def on_alert(self, conn, message): self.bad_message(message)
def on_getdata(self, conn, message): self.bad_message(message)
def on_getblocks(self, conn, message): self.bad_message(message)
def on_tx(self, conn, message): self.bad_message(message)
@@ -97,24 +96,13 @@ class P2PLeakTest(BitcoinTestFramework):
self.extra_args = [['-banscore='+str(banscore)]]
def run_test(self):
- no_version_bannode = CNodeNoVersionBan()
- no_version_idlenode = CNodeNoVersionIdle()
- no_verack_idlenode = CNodeNoVerackIdle()
- unsupported_service_bit5_node = CLazyNode()
- unsupported_service_bit7_node = CLazyNode()
-
self.nodes[0].setmocktime(1501545600) # August 1st 2017
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_bannode, send_version=False))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_version_idlenode, send_version=False))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], no_verack_idlenode))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], unsupported_service_bit5_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], unsupported_service_bit7_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7))
- no_version_bannode.add_connection(connections[0])
- no_version_idlenode.add_connection(connections[1])
- no_verack_idlenode.add_connection(connections[2])
- unsupported_service_bit5_node.add_connection(connections[3])
- unsupported_service_bit7_node.add_connection(connections[4])
+
+ no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False)
+ no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False)
+ no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle())
+ unsupported_service_bit5_node = self.nodes[0].add_p2p_connection(CLazyNode(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)
+ unsupported_service_bit7_node = self.nodes[0].add_p2p_connection(CLazyNode(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)
NetworkThread().start() # Start up network handling in another thread
@@ -137,7 +125,7 @@ class P2PLeakTest(BitcoinTestFramework):
assert not unsupported_service_bit5_node.connected
assert not unsupported_service_bit7_node.connected
- [conn.disconnect_node() for conn in connections]
+ self.nodes[0].disconnect_p2ps()
# Wait until all connections are closed
wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0)
@@ -152,13 +140,8 @@ class P2PLeakTest(BitcoinTestFramework):
self.log.info("Service bits 5 and 7 are allowed after August 1st 2018")
self.nodes[0].setmocktime(1533168000) # August 2nd 2018
- allowed_service_bit5_node = NodeConnCB()
- allowed_service_bit7_node = NodeConnCB()
-
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], allowed_service_bit5_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], allowed_service_bit7_node, services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7))
- allowed_service_bit5_node.add_connection(connections[5])
- allowed_service_bit7_node.add_connection(connections[6])
+ allowed_service_bit5_node = self.nodes[0].add_p2p_connection(NodeConnCB(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5)
+ allowed_service_bit7_node = self.nodes[0].add_p2p_connection(NodeConnCB(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7)
NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it
diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py
index 40fcde2605..be467c4223 100755
--- a/test/functional/p2p-mempool.py
+++ b/test/functional/p2p-mempool.py
@@ -19,16 +19,14 @@ class P2PMempoolTests(BitcoinTestFramework):
self.extra_args = [["-peerbloomfilters=0"]]
def run_test(self):
- #connect a mininode
- aTestNode = NodeConnCB()
- node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode)
- aTestNode.add_connection(node)
+ # Add a p2p connection
+ self.nodes[0].add_p2p_connection(NodeConnCB())
NetworkThread().start()
- aTestNode.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
#request mempool
- aTestNode.send_message(msg_mempool())
- aTestNode.wait_for_disconnect()
+ self.nodes[0].p2p.send_message(msg_mempool())
+ self.nodes[0].p2p.wait_for_disconnect()
#mininode must be disconnected at this point
assert_equal(len(self.nodes[0].getpeerinfo()), 0)
diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py
index a9ef47559b..b940bc4096 100755
--- a/test/functional/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -32,9 +32,10 @@ def get_virtual_size(witness_block):
return vsize
class TestNode(NodeConnCB):
- def __init__(self):
+ def __init__(self, rpc):
super().__init__()
self.getdataset = set()
+ self.rpc = rpc
def on_getdata(self, conn, message):
for inv in message.inv:
@@ -73,7 +74,7 @@ class TestNode(NodeConnCB):
tx_message = msg_witness_tx(tx)
self.send_message(tx_message)
self.sync_with_ping()
- assert_equal(tx.hash in self.connection.rpc.getrawmempool(), accepted)
+ assert_equal(tx.hash in self.rpc.getrawmempool(), accepted)
if (reason != None and not accepted):
# Check the rejection reason as well.
with mininode_lock:
@@ -86,10 +87,10 @@ class TestNode(NodeConnCB):
else:
self.send_message(msg_block(block))
self.sync_with_ping()
- assert_equal(self.connection.rpc.getbestblockhash() == block.hash, accepted)
+ assert_equal(self.rpc.getbestblockhash() == block.hash, accepted)
# Used to keep track of anyone-can-spend outputs that we can use in the tests
-class UTXO(object):
+class UTXO():
def __init__(self, sha256, n, nValue):
self.sha256 = sha256
self.n = n
@@ -111,7 +112,8 @@ class SegWitTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
- self.extra_args = [["-whitelist=127.0.0.1"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]]
+ # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
+ self.extra_args = [["-whitelist=127.0.0.1", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0", "-vbparams=segwit:0:999999999999"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]]
def setup_network(self):
self.setup_nodes()
@@ -1493,7 +1495,7 @@ class SegWitTest(BitcoinTestFramework):
# Restart with the new binary
self.stop_node(node_id)
- self.start_node(node_id, extra_args=[])
+ self.start_node(node_id, extra_args=["-vbparams=segwit:0:999999999999"])
connect_nodes(self.nodes[0], node_id)
sync_blocks(self.nodes)
@@ -1867,19 +1869,12 @@ class SegWitTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- self.test_node = TestNode() # sets NODE_WITNESS|NODE_NETWORK
- self.old_node = TestNode() # only NODE_NETWORK
- self.std_node = TestNode() # for testing node1 (fRequireStandard=true)
-
- self.p2p_connections = [self.test_node, self.old_node]
-
- self.connections = []
- self.connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.test_node, services=NODE_NETWORK|NODE_WITNESS))
- self.connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.old_node, services=NODE_NETWORK))
- self.connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], self.std_node, services=NODE_NETWORK|NODE_WITNESS))
- self.test_node.add_connection(self.connections[0])
- self.old_node.add_connection(self.connections[1])
- self.std_node.add_connection(self.connections[2])
+ # self.test_node sets NODE_WITNESS|NODE_NETWORK
+ self.test_node = self.nodes[0].add_p2p_connection(TestNode(self.nodes[0].rpc), services=NODE_NETWORK|NODE_WITNESS)
+ # self.old_node sets only NODE_NETWORK
+ self.old_node = self.nodes[0].add_p2p_connection(TestNode(self.nodes[0].rpc), services=NODE_NETWORK)
+ # self.std_node is for testing node1 (fRequireStandard=true)
+ self.std_node = self.nodes[1].add_p2p_connection(TestNode(self.nodes[1].rpc), services=NODE_NETWORK|NODE_WITNESS)
NetworkThread().start() # Start up network handling in another thread
diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py
index 51d4769efc..14a3bf48fb 100755
--- a/test/functional/p2p-timeouts.py
+++ b/test/functional/p2p-timeouts.py
@@ -39,46 +39,37 @@ class TimeoutsTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- self.no_verack_node = TestNode() # never send verack
- self.no_version_node = TestNode() # never send version (just ping)
- self.no_send_node = TestNode() # never send anything
-
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_verack_node))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_version_node, send_version=False))
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], self.no_send_node, send_version=False))
- self.no_verack_node.add_connection(connections[0])
- self.no_version_node.add_connection(connections[1])
- self.no_send_node.add_connection(connections[2])
+ no_verack_node = self.nodes[0].add_p2p_connection(TestNode())
+ no_version_node = self.nodes[0].add_p2p_connection(TestNode(), send_version=False)
+ no_send_node = self.nodes[0].add_p2p_connection(TestNode(), send_version=False)
NetworkThread().start() # Start up network handling in another thread
sleep(1)
- assert(self.no_verack_node.connected)
- assert(self.no_version_node.connected)
- assert(self.no_send_node.connected)
+ assert no_verack_node.connected
+ assert no_version_node.connected
+ assert no_send_node.connected
- ping_msg = msg_ping()
- connections[0].send_message(ping_msg)
- connections[1].send_message(ping_msg)
+ no_verack_node.send_message(msg_ping())
+ no_version_node.send_message(msg_ping())
sleep(30)
- assert "version" in self.no_verack_node.last_message
+ assert "version" in no_verack_node.last_message
- assert(self.no_verack_node.connected)
- assert(self.no_version_node.connected)
- assert(self.no_send_node.connected)
+ assert no_verack_node.connected
+ assert no_version_node.connected
+ assert no_send_node.connected
- connections[0].send_message(ping_msg)
- connections[1].send_message(ping_msg)
+ no_verack_node.send_message(msg_ping())
+ no_version_node.send_message(msg_ping())
sleep(31)
- assert(not self.no_verack_node.connected)
- assert(not self.no_version_node.connected)
- assert(not self.no_send_node.connected)
+ assert not no_verack_node.connected
+ assert not no_version_node.connected
+ assert not no_send_node.connected
if __name__ == '__main__':
TimeoutsTest().main()
diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py
index f9bef2580a..464ca5a312 100755
--- a/test/functional/p2p-versionbits-warning.py
+++ b/test/functional/p2p-versionbits-warning.py
@@ -64,16 +64,12 @@ class VersionBitsWarningTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connection and start up the network thread.
- test_node = TestNode()
-
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
- test_node.add_connection(connections[0])
+ self.nodes[0].add_p2p_connection(TestNode())
NetworkThread().start() # Start up network handling in another thread
# Test logic begins here
- test_node.wait_for_verack()
+ self.nodes[0].p2p.wait_for_verack()
# 1. Have the node mine one period worth of blocks
self.nodes[0].generate(VB_PERIOD)
@@ -81,7 +77,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# 2. Now build one period of blocks on the tip, with < VB_THRESHOLD
# blocks signaling some unknown bit.
nVersion = VB_TOP_BITS | (1<<VB_UNKNOWN_BIT)
- self.send_blocks_with_version(test_node, VB_THRESHOLD-1, nVersion)
+ self.send_blocks_with_version(self.nodes[0].p2p, VB_THRESHOLD-1, nVersion)
# Fill rest of period with regular version blocks
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1)
@@ -92,7 +88,7 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling
# some unknown bit
- self.send_blocks_with_version(test_node, VB_THRESHOLD, nVersion)
+ self.send_blocks_with_version(self.nodes[0].p2p, VB_THRESHOLD, nVersion)
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD)
# Might not get a versionbits-related alert yet, as we should
# have gotten a different alert due to more than 51/100 blocks
diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py
index db6fc86b82..97da19546f 100755
--- a/test/functional/receivedby.py
+++ b/test/functional/receivedby.py
@@ -3,97 +3,83 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the listreceivedbyaddress RPC."""
+from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-def get_sub_array_from_array(object_array, to_match):
- '''
- Finds and returns a sub array from an array of arrays.
- to_match should be a unique idetifier of a sub array
- '''
- for item in object_array:
- all_match = True
- for key,value in to_match.items():
- if item[key] != value:
- all_match = False
- if not all_match:
- continue
- return item
- return []
+from test_framework.util import (assert_array_result,
+ assert_equal,
+ assert_raises_rpc_error,
+ )
class ReceivedByTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.enable_mocktime()
def run_test(self):
- '''
- listreceivedbyaddress Test
- '''
+ # Generate block to get out of IBD
+ self.nodes[0].generate(1)
+
+ self.log.info("listreceivedbyaddress Test")
+
# Send from node 0 to 1
addr = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(addr, 0.1)
self.sync_all()
- #Check not listed in listreceivedbyaddress because has 0 confirmations
+ # Check not listed in listreceivedbyaddress because has 0 confirmations
assert_array_result(self.nodes[1].listreceivedbyaddress(),
- {"address":addr},
- { },
- True)
- #Bury Tx under 10 block so it will be returned by listreceivedbyaddress
+ {"address": addr},
+ {},
+ True)
+ # Bury Tx under 10 block so it will be returned by listreceivedbyaddress
self.nodes[1].generate(10)
self.sync_all()
assert_array_result(self.nodes[1].listreceivedbyaddress(),
- {"address":addr},
- {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]})
- #With min confidence < 10
+ {"address": addr},
+ {"address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]})
+ # With min confidence < 10
assert_array_result(self.nodes[1].listreceivedbyaddress(5),
- {"address":addr},
- {"address":addr, "account":"", "amount":Decimal("0.1"), "confirmations":10, "txids":[txid,]})
- #With min confidence > 10, should not find Tx
- assert_array_result(self.nodes[1].listreceivedbyaddress(11),{"address":addr},{ },True)
+ {"address": addr},
+ {"address": addr, "account": "", "amount": Decimal("0.1"), "confirmations": 10, "txids": [txid, ]})
+ # With min confidence > 10, should not find Tx
+ assert_array_result(self.nodes[1].listreceivedbyaddress(11), {"address": addr}, {}, True)
- #Empty Tx
+ # Empty Tx
addr = self.nodes[1].getnewaddress()
- assert_array_result(self.nodes[1].listreceivedbyaddress(0,True),
- {"address":addr},
- {"address":addr, "account":"", "amount":0, "confirmations":0, "txids":[]})
+ assert_array_result(self.nodes[1].listreceivedbyaddress(0, True),
+ {"address": addr},
+ {"address": addr, "account": "", "amount": 0, "confirmations": 0, "txids": []})
+
+ self.log.info("getreceivedbyaddress Test")
- '''
- getreceivedbyaddress Test
- '''
# Send from node 0 to 1
addr = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(addr, 0.1)
self.sync_all()
- #Check balance is 0 because of 0 confirmations
+ # Check balance is 0 because of 0 confirmations
balance = self.nodes[1].getreceivedbyaddress(addr)
- if balance != Decimal("0.0"):
- raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+ assert_equal(balance, Decimal("0.0"))
- #Check balance is 0.1
- balance = self.nodes[1].getreceivedbyaddress(addr,0)
- if balance != Decimal("0.1"):
- raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+ # Check balance is 0.1
+ balance = self.nodes[1].getreceivedbyaddress(addr, 0)
+ assert_equal(balance, Decimal("0.1"))
- #Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress
+ # Bury Tx under 10 block so it will be returned by the default getreceivedbyaddress
self.nodes[1].generate(10)
self.sync_all()
balance = self.nodes[1].getreceivedbyaddress(addr)
- if balance != Decimal("0.1"):
- raise AssertionError("Wrong balance returned by getreceivedbyaddress, %0.2f"%(balance))
+ assert_equal(balance, Decimal("0.1"))
+
+ # Trying to getreceivedby for an address the wallet doesn't own should return an error
+ assert_raises_rpc_error(-4, "Address not found in wallet", self.nodes[0].getreceivedbyaddress, addr)
+
+ self.log.info("listreceivedbyaccount + getreceivedbyaccount Test")
- '''
- listreceivedbyaccount + getreceivedbyaccount Test
- '''
- #set pre-state
+ # set pre-state
addrArr = self.nodes[1].getnewaddress()
account = self.nodes[1].getaccount(addrArr)
- received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(),{"account":account})
- if len(received_by_account_json) == 0:
- raise AssertionError("No accounts found in node")
+ received_by_account_json = [r for r in self.nodes[1].listreceivedbyaccount() if r["account"] == account][0]
balance_by_account = self.nodes[1].getreceivedbyaccount(account)
txid = self.nodes[0].sendtoaddress(addr, 0.1)
@@ -101,40 +87,34 @@ class ReceivedByTest(BitcoinTestFramework):
# listreceivedbyaccount should return received_by_account_json because of 0 confirmations
assert_array_result(self.nodes[1].listreceivedbyaccount(),
- {"account":account},
- received_by_account_json)
+ {"account": account},
+ received_by_account_json)
# getreceivedbyaddress should return same balance because of 0 confirmations
balance = self.nodes[1].getreceivedbyaccount(account)
- if balance != balance_by_account:
- raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+ assert_equal(balance, balance_by_account)
self.nodes[1].generate(10)
self.sync_all()
# listreceivedbyaccount should return updated account balance
assert_array_result(self.nodes[1].listreceivedbyaccount(),
- {"account":account},
- {"account":received_by_account_json["account"], "amount":(received_by_account_json["amount"] + Decimal("0.1"))})
+ {"account": account},
+ {"account": received_by_account_json["account"], "amount": (received_by_account_json["amount"] + Decimal("0.1"))})
# getreceivedbyaddress should return updates balance
balance = self.nodes[1].getreceivedbyaccount(account)
- if balance != balance_by_account + Decimal("0.1"):
- raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+ assert_equal(balance, balance_by_account + Decimal("0.1"))
- #Create a new account named "mynewaccount" that has a 0 balance
+ # Create a new account named "mynewaccount" that has a 0 balance
self.nodes[1].getaccountaddress("mynewaccount")
- received_by_account_json = get_sub_array_from_array(self.nodes[1].listreceivedbyaccount(0,True),{"account":"mynewaccount"})
- if len(received_by_account_json) == 0:
- raise AssertionError("No accounts found in node")
+ received_by_account_json = [r for r in self.nodes[1].listreceivedbyaccount(0, True) if r["account"] == "mynewaccount"][0]
# Test includeempty of listreceivedbyaccount
- if received_by_account_json["amount"] != Decimal("0.0"):
- raise AssertionError("Wrong balance returned by listreceivedbyaccount, %0.2f"%(received_by_account_json["amount"]))
+ assert_equal(received_by_account_json["amount"], Decimal("0.0"))
# Test getreceivedbyaccount for 0 amount accounts
balance = self.nodes[1].getreceivedbyaccount("mynewaccount")
- if balance != Decimal("0.0"):
- raise AssertionError("Wrong balance returned by getreceivedbyaccount, %0.2f"%(balance))
+ assert_equal(balance, Decimal("0.0"))
if __name__ == '__main__':
ReceivedByTest().main()
diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py
index 269d57775c..815e964848 100755
--- a/test/functional/replace-by-fee.py
+++ b/test/functional/replace-by-fee.py
@@ -72,8 +72,14 @@ class ReplaceByFeeTest(BitcoinTestFramework):
["-mempoolreplacement=0"]]
def run_test(self):
+ # Leave IBD
+ self.nodes[0].generate(1)
+
make_utxo(self.nodes[0], 1*COIN)
+ # Ensure nodes are synced
+ self.sync_all()
+
self.log.info("Running test simple doublespend...")
self.test_simple_doublespend()
@@ -110,13 +116,18 @@ class ReplaceByFeeTest(BitcoinTestFramework):
"""Simple doublespend"""
tx0_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
+ # make_utxo may have generated a bunch of blocks, so we need to sync
+ # before we can spend the coins generated, or else the resulting
+ # transactions might not be accepted by our peers.
+ self.sync_all()
+
tx1a = CTransaction()
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
tx1a.vout = [CTxOut(1*COIN, CScript([b'a']))]
tx1a_hex = txToHex(tx1a)
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
- self.sync_all([self.nodes])
+ self.sync_all()
# Should fail because we haven't changed the fee
tx1b = CTransaction()
diff --git a/test/functional/segwit.py b/test/functional/segwit.py
index 6ecade7cb6..338fa1bc52 100755
--- a/test/functional/segwit.py
+++ b/test/functional/segwit.py
@@ -77,9 +77,10 @@ class SegWitTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
- self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0"],
- ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"],
- ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"]]
+ # This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
+ self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0", "-vbparams=segwit:0:999999999999"],
+ ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1", "-vbparams=segwit:0:999999999999"],
+ ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-vbparams=segwit:0:999999999999"]]
def setup_network(self):
super().setup_network()
diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py
index fe577dc20a..55bb80ea00 100755
--- a/test/functional/sendheaders.py
+++ b/test/functional/sendheaders.py
@@ -10,6 +10,17 @@ Setup:
receive inv's (omitted from testing description below, this is our control).
Second node is used for creating reorgs.
+test_null_locators
+==================
+
+Sends two getheaders requests with null locator values. First request's hashstop
+value refers to validated block, while second request's hashstop value refers to
+a block which hasn't been validated. Verifies only the first request returns
+headers.
+
+test_nonnull_locators
+=====================
+
Part 1: No headers announcements before "sendheaders"
a. node mines a block [expect: inv]
send getdata for the block [expect: block]
@@ -181,7 +192,7 @@ class SendHeadersTest(BitcoinTestFramework):
# mine count blocks and return the new tip
def mine_blocks(self, count):
# Clear out last block announcement from each p2p listener
- [ x.clear_last_announcement() for x in self.p2p_connections ]
+ [x.clear_last_announcement() for x in self.nodes[0].p2ps]
self.nodes[0].generate(count)
return int(self.nodes[0].getbestblockhash(), 16)
@@ -193,7 +204,7 @@ class SendHeadersTest(BitcoinTestFramework):
def mine_reorg(self, length):
self.nodes[0].generate(length) # make sure all invalidated blocks are node0's
sync_blocks(self.nodes, wait=0.1)
- for x in self.p2p_connections:
+ for x in self.nodes[0].p2ps:
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
x.clear_last_announcement()
@@ -206,18 +217,10 @@ class SendHeadersTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections and start up the network thread.
- inv_node = TestNode()
- test_node = TestNode()
-
- self.p2p_connections = [inv_node, test_node]
-
- connections = []
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], inv_node))
+ inv_node = self.nodes[0].add_p2p_connection(TestNode())
# Set nServices to 0 for test_node, so no block download will occur outside of
# direct fetching
- connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node, services=0))
- inv_node.add_connection(connections[0])
- test_node.add_connection(connections[1])
+ test_node = self.nodes[0].add_p2p_connection(TestNode(), services=NODE_WITNESS)
NetworkThread().start() # Start up network handling in another thread
@@ -225,6 +228,33 @@ class SendHeadersTest(BitcoinTestFramework):
inv_node.wait_for_verack()
test_node.wait_for_verack()
+ # Ensure verack's have been processed by our peer
+ inv_node.sync_with_ping()
+ test_node.sync_with_ping()
+
+ self.test_null_locators(test_node)
+ self.test_nonnull_locators(test_node, inv_node)
+
+ def test_null_locators(self, test_node):
+ tip = self.nodes[0].getblockheader(self.nodes[0].generate(1)[0])
+ tip_hash = int(tip["hash"], 16)
+
+ self.log.info("Verify getheaders with null locator and valid hashstop returns headers.")
+ test_node.clear_last_announcement()
+ test_node.get_headers(locator=[], hashstop=tip_hash)
+ assert_equal(test_node.check_last_announcement(headers=[tip_hash]), True)
+
+ self.log.info("Verify getheaders with null locator and invalid hashstop does not return headers.")
+ block = create_block(int(tip["hash"], 16), create_coinbase(tip["height"] + 1), tip["mediantime"] + 1)
+ block.solve()
+ test_node.send_header_for_blocks([block])
+ test_node.clear_last_announcement()
+ test_node.get_headers(locator=[], hashstop=int(block.hash, 16))
+ test_node.sync_with_ping()
+ assert_equal(test_node.block_announced, False)
+ test_node.send_message(msg_block(block))
+
+ def test_nonnull_locators(self, test_node, inv_node):
tip = int(self.nodes[0].getbestblockhash(), 16)
# PART 1
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index 747bda309c..bd3a3b3fab 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -33,24 +33,17 @@ ServiceProxy class:
- uses standard Python json lib
"""
-try:
- import http.client as httplib
-except ImportError:
- import httplib
import base64
import decimal
+import http.client
import json
import logging
import socket
import time
-try:
- import urllib.parse as urlparse
-except ImportError:
- import urlparse
-
-USER_AGENT = "AuthServiceProxy/0.1"
+import urllib.parse
HTTP_TIMEOUT = 30
+USER_AGENT = "AuthServiceProxy/0.1"
log = logging.getLogger("BitcoinRPC")
@@ -60,7 +53,7 @@ class JSONRPCException(Exception):
errmsg = '%(message)s (%(code)i)' % rpc_error
except (KeyError, TypeError):
errmsg = ''
- Exception.__init__(self, errmsg)
+ super().__init__(errmsg)
self.error = rpc_error
@@ -69,28 +62,18 @@ def EncodeDecimal(o):
return str(o)
raise TypeError(repr(o) + " is not JSON serializable")
-class AuthServiceProxy(object):
+class AuthServiceProxy():
__id_count = 0
# ensure_ascii: escape unicode as \uXXXX, passed to json.dumps
def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True):
self.__service_url = service_url
self._service_name = service_name
- self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests
- self.__url = urlparse.urlparse(service_url)
- if self.__url.port is None:
- port = 80
- else:
- port = self.__url.port
- (user, passwd) = (self.__url.username, self.__url.password)
- try:
- user = user.encode('utf8')
- except AttributeError:
- pass
- try:
- passwd = passwd.encode('utf8')
- except AttributeError:
- pass
+ self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests
+ self.__url = urllib.parse.urlparse(service_url)
+ port = 80 if self.__url.port is None else self.__url.port
+ user = None if self.__url.username is None else self.__url.username.encode('utf8')
+ passwd = None if self.__url.password is None else self.__url.password.encode('utf8')
authpair = user + b':' + passwd
self.__auth_header = b'Basic ' + base64.b64encode(authpair)
@@ -98,11 +81,9 @@ class AuthServiceProxy(object):
# Callables re-use the connection of the original proxy
self.__conn = connection
elif self.__url.scheme == 'https':
- self.__conn = httplib.HTTPSConnection(self.__url.hostname, port,
- timeout=timeout)
+ self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=timeout)
else:
- self.__conn = httplib.HTTPConnection(self.__url.hostname, port,
- timeout=timeout)
+ self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=timeout)
def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'):
@@ -124,14 +105,14 @@ class AuthServiceProxy(object):
try:
self.__conn.request(method, path, postdata, headers)
return self._get_response()
- except httplib.BadStatusLine as e:
- if e.line == "''": # if connection was closed, try again
+ except http.client.BadStatusLine as e:
+ if e.line == "''": # if connection was closed, try again
self.__conn.close()
self.__conn.request(method, path, postdata, headers)
return self._get_response()
else:
raise
- except (BrokenPipeError,ConnectionResetError):
+ except (BrokenPipeError, ConnectionResetError):
# Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset
# ConnectionResetError happens on FreeBSD with Python 3.4
self.__conn.close()
@@ -141,8 +122,8 @@ class AuthServiceProxy(object):
def get_request(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)))
+ 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')
return {'version': '1.1',
@@ -163,7 +144,7 @@ class AuthServiceProxy(object):
def batch(self, rpc_call_list):
postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
- log.debug("--> "+postdata)
+ log.debug("--> " + postdata)
return self._request('POST', self.__url.path, postdata.encode('utf-8'))
def _get_response(self):
@@ -190,9 +171,9 @@ class AuthServiceProxy(object):
response = json.loads(responsedata, parse_float=decimal.Decimal)
elapsed = time.time() - req_start_time
if "error" in response and response["error"] is None:
- log.debug("<-%s- [%.6f] %s"%(response["id"], elapsed, json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
+ log.debug("<-%s- [%.6f] %s" % (response["id"], elapsed, json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
else:
- log.debug("<-- [%.6f] %s"%(elapsed,responsedata))
+ log.debug("<-- [%.6f] %s" % (elapsed, responsedata))
return response
def __truediv__(self, relative_uri):
diff --git a/test/functional/test_framework/blockstore.py b/test/functional/test_framework/blockstore.py
index 4b2170a03f..051c57a6c7 100644
--- a/test/functional/test_framework/blockstore.py
+++ b/test/functional/test_framework/blockstore.py
@@ -10,7 +10,7 @@ import dbm.dumb as dbmd
logger = logging.getLogger("TestFramework.blockstore")
-class BlockStore(object):
+class BlockStore():
"""BlockStore helper class.
BlockStore keeps a map of blocks and implements helper functions for
@@ -100,7 +100,7 @@ class BlockStore(object):
def get_blocks(self, inv):
responses = []
for i in inv:
- if (i.type == 2): # MSG_BLOCK
+ if (i.type == 2 or i.type == (2 | (1 << 30))): # MSG_BLOCK or MSG_WITNESS_BLOCK
data = self.get(i.hash)
if data is not None:
# Use msg_generic to avoid re-serialization
@@ -127,7 +127,7 @@ class BlockStore(object):
locator.vHave = r
return locator
-class TxStore(object):
+class TxStore():
def __init__(self, datadir):
self.txDB = dbmd.open(datadir + "/transactions", 'c')
@@ -153,7 +153,7 @@ class TxStore(object):
def get_transactions(self, inv):
responses = []
for i in inv:
- if (i.type == 1): # MSG_TX
+ if (i.type == 1 or i.type == (1 | (1 << 30))): # MSG_TX or MSG_WITNESS_TX
tx = self.get(i.hash)
if tx is not None:
responses.append(msg_generic(b"tx", tx))
diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py
index bfbc0c3b03..723826bae4 100755
--- a/test/functional/test_framework/comptool.py
+++ b/test/functional/test_framework/comptool.py
@@ -27,7 +27,7 @@ logger=logging.getLogger("TestFramework.comptool")
global mininode_lock
-class RejectResult(object):
+class RejectResult():
"""Outcome that expects rejection of a transaction or block."""
def __init__(self, code, reason=b''):
self.code = code
@@ -80,9 +80,9 @@ class TestNode(NodeConnCB):
[conn.send_message(r) for r in self.tx_store.get_transactions(message.inv)]
for i in message.inv:
- if i.type == 1:
+ if i.type == 1 or i.type == 1 | (1 << 30): # MSG_TX or MSG_WITNESS_TX
self.tx_request_map[i.hash] = True
- elif i.type == 2:
+ elif i.type == 2 or i.type == 2 | (1 << 30): # MSG_BLOCK or MSG_WITNESS_BLOCK
self.block_request_map[i.hash] = True
def on_inv(self, conn, message):
@@ -156,13 +156,13 @@ class TestNode(NodeConnCB):
# across all connections. (If outcome of final tx is specified as true
# or false, then only the last tx is tested against outcome.)
-class TestInstance(object):
+class TestInstance():
def __init__(self, objects=None, sync_every_block=True, sync_every_tx=False):
self.blocks_and_transactions = objects if objects else []
self.sync_every_block = sync_every_block
self.sync_every_tx = sync_every_tx
-class TestManager(object):
+class TestManager():
def __init__(self, testgen, datadir):
self.test_generator = testgen
@@ -177,7 +177,7 @@ class TestManager(object):
# Create a p2p connection to each node
test_node = TestNode(self.block_store, self.tx_store)
self.test_nodes.append(test_node)
- self.connections.append(NodeConn('127.0.0.1', p2p_port(i), nodes[i], test_node))
+ self.connections.append(NodeConn('127.0.0.1', p2p_port(i), test_node))
# Make sure the TestNode (callback class) has a reference to its
# associated NodeConn
test_node.add_connection(self.connections[-1])
@@ -295,8 +295,11 @@ class TestManager(object):
# Wait until verack is received
self.wait_for_verack()
- test_number = 1
- for test_instance in self.test_generator.get_tests():
+ test_number = 0
+ tests = self.test_generator.get_tests()
+ for test_instance in tests:
+ test_number += 1
+ logger.info("Running test %d: %s line %s" % (test_number, tests.gi_code.co_filename, tests.gi_frame.f_lineno))
# We use these variables to keep track of the last block
# and last transaction in the tests, which are used
# if we're not syncing on every block or every tx.
@@ -397,9 +400,6 @@ class TestManager(object):
if (not self.check_mempool(tx.sha256, tx_outcome)):
raise AssertionError("Mempool test failed at test %d" % test_number)
- logger.info("Test %d: PASS" % test_number)
- test_number += 1
-
[ c.disconnect_node() for c in self.connections ]
self.wait_for_disconnections()
self.block_store.close()
diff --git a/test/functional/test_framework/coverage.py b/test/functional/test_framework/coverage.py
index 84049e76bc..ddc3c515b2 100644
--- a/test/functional/test_framework/coverage.py
+++ b/test/functional/test_framework/coverage.py
@@ -14,7 +14,7 @@ import os
REFERENCE_FILENAME = 'rpc_interface.txt'
-class AuthServiceProxyWrapper(object):
+class AuthServiceProxyWrapper():
"""
An object that wraps AuthServiceProxy to record specific RPC calls.
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index 85a6158a2f..aa91fb5b0d 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -84,7 +84,7 @@ def _check_result(val, func, args):
ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
-class CECKey(object):
+class CECKey():
"""Wrapper around OpenSSL's EC_KEY"""
POINT_CONVERSION_COMPRESSED = 2
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index c6f596156a..24ee09b81c 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -37,7 +37,7 @@ from threading import RLock, Thread
from test_framework.siphash import siphash256
from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, wait_until
-BIP0031_VERSION = 60000
+MIN_VERSION_SUPPORTED = 60001
MY_VERSION = 70014 # past bip-31 for ping/pong
MY_SUBVERSION = b"/python-mininode-tester:0.0.3/"
MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37)
@@ -219,7 +219,7 @@ def ToHex(obj):
# Objects that map to bitcoind objects, which can be serialized/deserialized
-class CAddress(object):
+class CAddress():
def __init__(self):
self.nServices = 1
self.pchReserved = b"\x00" * 10 + b"\xff" * 2
@@ -246,7 +246,7 @@ class CAddress(object):
MSG_WITNESS_FLAG = 1<<30
-class CInv(object):
+class CInv():
typemap = {
0: "Error",
1: "TX",
@@ -275,7 +275,7 @@ class CInv(object):
% (self.typemap[self.type], self.hash)
-class CBlockLocator(object):
+class CBlockLocator():
def __init__(self):
self.nVersion = MY_VERSION
self.vHave = []
@@ -295,7 +295,7 @@ class CBlockLocator(object):
% (self.nVersion, repr(self.vHave))
-class COutPoint(object):
+class COutPoint():
def __init__(self, hash=0, n=0):
self.hash = hash
self.n = n
@@ -314,7 +314,7 @@ class COutPoint(object):
return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n)
-class CTxIn(object):
+class CTxIn():
def __init__(self, outpoint=None, scriptSig=b"", nSequence=0):
if outpoint is None:
self.prevout = COutPoint()
@@ -342,7 +342,7 @@ class CTxIn(object):
self.nSequence)
-class CTxOut(object):
+class CTxOut():
def __init__(self, nValue=0, scriptPubKey=b""):
self.nValue = nValue
self.scriptPubKey = scriptPubKey
@@ -363,7 +363,7 @@ class CTxOut(object):
bytes_to_hex_str(self.scriptPubKey))
-class CScriptWitness(object):
+class CScriptWitness():
def __init__(self):
# stack is a vector of strings
self.stack = []
@@ -378,7 +378,7 @@ class CScriptWitness(object):
return True
-class CTxInWitness(object):
+class CTxInWitness():
def __init__(self):
self.scriptWitness = CScriptWitness()
@@ -395,7 +395,7 @@ class CTxInWitness(object):
return self.scriptWitness.is_null()
-class CTxWitness(object):
+class CTxWitness():
def __init__(self):
self.vtxinwit = []
@@ -423,7 +423,7 @@ class CTxWitness(object):
return True
-class CTransaction(object):
+class CTransaction():
def __init__(self, tx=None):
if tx is None:
self.nVersion = 1
@@ -526,7 +526,7 @@ class CTransaction(object):
% (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime)
-class CBlockHeader(object):
+class CBlockHeader():
def __init__(self, header=None):
if header is None:
self.set_null()
@@ -666,82 +666,7 @@ class CBlock(CBlockHeader):
time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx))
-class CUnsignedAlert(object):
- def __init__(self):
- self.nVersion = 1
- self.nRelayUntil = 0
- self.nExpiration = 0
- self.nID = 0
- self.nCancel = 0
- self.setCancel = []
- self.nMinVer = 0
- self.nMaxVer = 0
- self.setSubVer = []
- self.nPriority = 0
- self.strComment = b""
- self.strStatusBar = b""
- self.strReserved = b""
-
- def deserialize(self, f):
- self.nVersion = struct.unpack("<i", f.read(4))[0]
- self.nRelayUntil = struct.unpack("<q", f.read(8))[0]
- self.nExpiration = struct.unpack("<q", f.read(8))[0]
- self.nID = struct.unpack("<i", f.read(4))[0]
- self.nCancel = struct.unpack("<i", f.read(4))[0]
- self.setCancel = deser_int_vector(f)
- self.nMinVer = struct.unpack("<i", f.read(4))[0]
- self.nMaxVer = struct.unpack("<i", f.read(4))[0]
- self.setSubVer = deser_string_vector(f)
- self.nPriority = struct.unpack("<i", f.read(4))[0]
- self.strComment = deser_string(f)
- self.strStatusBar = deser_string(f)
- self.strReserved = deser_string(f)
-
- def serialize(self):
- r = b""
- r += struct.pack("<i", self.nVersion)
- r += struct.pack("<q", self.nRelayUntil)
- r += struct.pack("<q", self.nExpiration)
- r += struct.pack("<i", self.nID)
- r += struct.pack("<i", self.nCancel)
- r += ser_int_vector(self.setCancel)
- r += struct.pack("<i", self.nMinVer)
- r += struct.pack("<i", self.nMaxVer)
- r += ser_string_vector(self.setSubVer)
- r += struct.pack("<i", self.nPriority)
- r += ser_string(self.strComment)
- r += ser_string(self.strStatusBar)
- r += ser_string(self.strReserved)
- return r
-
- def __repr__(self):
- return "CUnsignedAlert(nVersion %d, nRelayUntil %d, nExpiration %d, nID %d, nCancel %d, nMinVer %d, nMaxVer %d, nPriority %d, strComment %s, strStatusBar %s, strReserved %s)" \
- % (self.nVersion, self.nRelayUntil, self.nExpiration, self.nID,
- self.nCancel, self.nMinVer, self.nMaxVer, self.nPriority,
- self.strComment, self.strStatusBar, self.strReserved)
-
-
-class CAlert(object):
- def __init__(self):
- self.vchMsg = b""
- self.vchSig = b""
-
- def deserialize(self, f):
- self.vchMsg = deser_string(f)
- self.vchSig = deser_string(f)
-
- def serialize(self):
- r = b""
- r += ser_string(self.vchMsg)
- r += ser_string(self.vchSig)
- return r
-
- def __repr__(self):
- return "CAlert(vchMsg.sz %d, vchSig.sz %d)" \
- % (len(self.vchMsg), len(self.vchSig))
-
-
-class PrefilledTransaction(object):
+class PrefilledTransaction():
def __init__(self, index=0, tx = None):
self.index = index
self.tx = tx
@@ -767,7 +692,7 @@ class PrefilledTransaction(object):
return "PrefilledTransaction(index=%d, tx=%s)" % (self.index, repr(self.tx))
# This is what we send on the wire, in a cmpctblock message.
-class P2PHeaderAndShortIDs(object):
+class P2PHeaderAndShortIDs():
def __init__(self):
self.header = CBlockHeader()
self.nonce = 0
@@ -819,7 +744,7 @@ def calculate_shortid(k0, k1, tx_hash):
# This version gets rid of the array lengths, and reinterprets the differential
# encoding into indices that can be used for lookup.
-class HeaderAndShortIDs(object):
+class HeaderAndShortIDs():
def __init__(self, p2pheaders_and_shortids = None):
self.header = CBlockHeader()
self.nonce = 0
@@ -880,7 +805,7 @@ class HeaderAndShortIDs(object):
return "HeaderAndShortIDs(header=%s, nonce=%d, shortids=%s, prefilledtxn=%s" % (repr(self.header), self.nonce, repr(self.shortids), repr(self.prefilled_txn))
-class BlockTransactionsRequest(object):
+class BlockTransactionsRequest():
def __init__(self, blockhash=0, indexes = None):
self.blockhash = blockhash
@@ -920,7 +845,7 @@ class BlockTransactionsRequest(object):
return "BlockTransactionsRequest(hash=%064x indexes=%s)" % (self.blockhash, repr(self.indexes))
-class BlockTransactions(object):
+class BlockTransactions():
def __init__(self, blockhash=0, transactions = None):
self.blockhash = blockhash
@@ -944,12 +869,12 @@ class BlockTransactions(object):
# Objects that correspond to messages on the wire
-class msg_version(object):
+class msg_version():
command = b"version"
def __init__(self):
self.nVersion = MY_VERSION
- self.nServices = 1
+ self.nServices = NODE_NETWORK | NODE_WITNESS
self.nTime = int(time.time())
self.addrTo = CAddress()
self.addrFrom = CAddress()
@@ -1012,7 +937,7 @@ class msg_version(object):
self.strSubVer, self.nStartingHeight, self.nRelay)
-class msg_verack(object):
+class msg_verack():
command = b"verack"
def __init__(self):
@@ -1028,7 +953,7 @@ class msg_verack(object):
return "msg_verack()"
-class msg_addr(object):
+class msg_addr():
command = b"addr"
def __init__(self):
@@ -1044,26 +969,7 @@ class msg_addr(object):
return "msg_addr(addrs=%s)" % (repr(self.addrs))
-class msg_alert(object):
- command = b"alert"
-
- def __init__(self):
- self.alert = CAlert()
-
- def deserialize(self, f):
- self.alert = CAlert()
- self.alert.deserialize(f)
-
- def serialize(self):
- r = b""
- r += self.alert.serialize()
- return r
-
- def __repr__(self):
- return "msg_alert(alert=%s)" % (repr(self.alert), )
-
-
-class msg_inv(object):
+class msg_inv():
command = b"inv"
def __init__(self, inv=None):
@@ -1082,7 +988,7 @@ class msg_inv(object):
return "msg_inv(inv=%s)" % (repr(self.inv))
-class msg_getdata(object):
+class msg_getdata():
command = b"getdata"
def __init__(self, inv=None):
@@ -1098,7 +1004,7 @@ class msg_getdata(object):
return "msg_getdata(inv=%s)" % (repr(self.inv))
-class msg_getblocks(object):
+class msg_getblocks():
command = b"getblocks"
def __init__(self):
@@ -1121,7 +1027,7 @@ class msg_getblocks(object):
% (repr(self.locator), self.hashstop)
-class msg_tx(object):
+class msg_tx():
command = b"tx"
def __init__(self, tx=CTransaction()):
@@ -1142,7 +1048,7 @@ class msg_witness_tx(msg_tx):
return self.tx.serialize_with_witness()
-class msg_block(object):
+class msg_block():
command = b"block"
def __init__(self, block=None):
@@ -1162,7 +1068,7 @@ class msg_block(object):
# for cases where a user needs tighter control over what is sent over the wire
# note that the user must supply the name of the command, and the data
-class msg_generic(object):
+class msg_generic():
def __init__(self, command, data=None):
self.command = command
self.data = data
@@ -1179,7 +1085,7 @@ class msg_witness_block(msg_block):
r = self.block.serialize(with_witness=True)
return r
-class msg_getaddr(object):
+class msg_getaddr():
command = b"getaddr"
def __init__(self):
@@ -1195,23 +1101,7 @@ class msg_getaddr(object):
return "msg_getaddr()"
-class msg_ping_prebip31(object):
- command = b"ping"
-
- def __init__(self):
- pass
-
- def deserialize(self, f):
- pass
-
- def serialize(self):
- return b""
-
- def __repr__(self):
- return "msg_ping() (pre-bip31)"
-
-
-class msg_ping(object):
+class msg_ping():
command = b"ping"
def __init__(self, nonce=0):
@@ -1229,7 +1119,7 @@ class msg_ping(object):
return "msg_ping(nonce=%08x)" % self.nonce
-class msg_pong(object):
+class msg_pong():
command = b"pong"
def __init__(self, nonce=0):
@@ -1247,7 +1137,7 @@ class msg_pong(object):
return "msg_pong(nonce=%08x)" % self.nonce
-class msg_mempool(object):
+class msg_mempool():
command = b"mempool"
def __init__(self):
@@ -1262,7 +1152,7 @@ class msg_mempool(object):
def __repr__(self):
return "msg_mempool()"
-class msg_sendheaders(object):
+class msg_sendheaders():
command = b"sendheaders"
def __init__(self):
@@ -1282,7 +1172,7 @@ class msg_sendheaders(object):
# number of entries
# vector of hashes
# hash_stop (hash of last desired block header, 0 to get as many as possible)
-class msg_getheaders(object):
+class msg_getheaders():
command = b"getheaders"
def __init__(self):
@@ -1307,7 +1197,7 @@ class msg_getheaders(object):
# headers message has
# <count> <vector of block headers>
-class msg_headers(object):
+class msg_headers():
command = b"headers"
def __init__(self, headers=None):
@@ -1327,7 +1217,7 @@ class msg_headers(object):
return "msg_headers(headers=%s)" % repr(self.headers)
-class msg_reject(object):
+class msg_reject():
command = b"reject"
REJECT_MALFORMED = 1
@@ -1358,7 +1248,7 @@ class msg_reject(object):
return "msg_reject: %s %d %s [%064x]" \
% (self.message, self.code, self.reason, self.data)
-class msg_feefilter(object):
+class msg_feefilter():
command = b"feefilter"
def __init__(self, feerate=0):
@@ -1375,7 +1265,7 @@ class msg_feefilter(object):
def __repr__(self):
return "msg_feefilter(feerate=%08x)" % self.feerate
-class msg_sendcmpct(object):
+class msg_sendcmpct():
command = b"sendcmpct"
def __init__(self):
@@ -1395,7 +1285,7 @@ class msg_sendcmpct(object):
def __repr__(self):
return "msg_sendcmpct(announce=%s, version=%lu)" % (self.announce, self.version)
-class msg_cmpctblock(object):
+class msg_cmpctblock():
command = b"cmpctblock"
def __init__(self, header_and_shortids = None):
@@ -1413,7 +1303,7 @@ class msg_cmpctblock(object):
def __repr__(self):
return "msg_cmpctblock(HeaderAndShortIDs=%s)" % repr(self.header_and_shortids)
-class msg_getblocktxn(object):
+class msg_getblocktxn():
command = b"getblocktxn"
def __init__(self):
@@ -1431,7 +1321,7 @@ class msg_getblocktxn(object):
def __repr__(self):
return "msg_getblocktxn(block_txn_request=%s)" % (repr(self.block_txn_request))
-class msg_blocktxn(object):
+class msg_blocktxn():
command = b"blocktxn"
def __init__(self):
@@ -1454,13 +1344,11 @@ class msg_witness_blocktxn(msg_blocktxn):
r += self.block_transactions.serialize(with_witness=True)
return r
-class NodeConnCB(object):
+class NodeConnCB():
"""Callback and helper functions for P2P connection to a bitcoind node.
Individual testcases should subclass this and override the on_* methods
- if they want to alter message handling behaviour.
- """
-
+ if they want to alter message handling behaviour."""
def __init__(self):
# Track whether we have a P2P connection open to the node
self.connected = False
@@ -1474,25 +1362,13 @@ class NodeConnCB(object):
# A count of the number of ping messages we've sent to the node
self.ping_counter = 1
- # deliver_sleep_time is helpful for debugging race conditions in p2p
- # tests; it causes message delivery to sleep for the specified time
- # before acquiring the global lock and delivering the next message.
- self.deliver_sleep_time = None
-
# Message receiving methods
def deliver(self, conn, message):
"""Receive message and dispatch message to appropriate callback.
We keep a count of how many of each message type has been received
- and the most recent message of each type.
-
- Optionally waits for deliver_sleep_time before dispatching message.
- """
-
- deliver_sleep = self.get_deliver_sleep_time()
- if deliver_sleep is not None:
- time.sleep(deliver_sleep)
+ and the most recent message of each type."""
with mininode_lock:
try:
command = message.command.decode('ascii')
@@ -1504,10 +1380,6 @@ class NodeConnCB(object):
sys.exc_info()[0]))
raise
- def get_deliver_sleep_time(self):
- with mininode_lock:
- return self.deliver_sleep_time
-
# Callback methods. Can be overridden by subclasses in individual test
# cases to provide custom message handling behaviour.
@@ -1519,7 +1391,6 @@ class NodeConnCB(object):
self.connection = None
def on_addr(self, conn, message): pass
- def on_alert(self, conn, message): pass
def on_block(self, conn, message): pass
def on_blocktxn(self, conn, message): pass
def on_cmpctblock(self, conn, message): pass
@@ -1546,19 +1417,14 @@ class NodeConnCB(object):
conn.send_message(want)
def on_ping(self, conn, message):
- if conn.ver_send > BIP0031_VERSION:
- conn.send_message(msg_pong(message.nonce))
+ conn.send_message(msg_pong(message.nonce))
def on_verack(self, conn, message):
- conn.ver_recv = conn.ver_send
self.verack_received = True
def on_version(self, conn, message):
- if message.nVersion >= 209:
- conn.send_message(msg_verack())
- conn.ver_send = min(MY_VERSION, message.nVersion)
- if message.nVersion < 209:
- conn.ver_recv = conn.ver_send
+ assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED)
+ conn.send_message(msg_verack())
conn.nServices = message.nServices
# Connection helper methods
@@ -1615,16 +1481,15 @@ class NodeConnCB(object):
test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
wait_until(test_function, timeout=timeout, lock=mininode_lock)
self.ping_counter += 1
- return True
-# The actual NodeConn class
-# This class provides an interface for a p2p connection to a specified node
class NodeConn(asyncore.dispatcher):
+ """The actual NodeConn class
+
+ This class provides an interface for a p2p connection to a specified node."""
messagemap = {
b"version": msg_version,
b"verack": msg_verack,
b"addr": msg_addr,
- b"alert": msg_alert,
b"inv": msg_inv,
b"getdata": msg_getdata,
b"getblocks": msg_getblocks,
@@ -1650,7 +1515,7 @@ class NodeConn(asyncore.dispatcher):
"regtest": b"\xfa\xbf\xb5\xda", # regtest
}
- def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True):
+ def __init__(self, dstaddr, dstport, callback, net="regtest", services=NODE_NETWORK|NODE_WITNESS, send_version=True):
asyncore.dispatcher.__init__(self, map=mininode_socket_map)
self.dstaddr = dstaddr
self.dstport = dstport
@@ -1658,8 +1523,6 @@ class NodeConn(asyncore.dispatcher):
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.sendbuf = b""
self.recvbuf = b""
- self.ver_send = 209
- self.ver_recv = 209
self.last_sent = 0
self.state = "connecting"
self.network = net
@@ -1683,7 +1546,6 @@ class NodeConn(asyncore.dispatcher):
self.connect((dstaddr, dstport))
except:
self.handle_close()
- self.rpc = rpc
def handle_connect(self):
if self.state != "connected":
@@ -1741,40 +1603,27 @@ class NodeConn(asyncore.dispatcher):
return
if self.recvbuf[:4] != self.MAGIC_BYTES[self.network]:
raise ValueError("got garbage %s" % repr(self.recvbuf))
- if self.ver_recv < 209:
- if len(self.recvbuf) < 4 + 12 + 4:
- return
- command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
- msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
- checksum = None
- if len(self.recvbuf) < 4 + 12 + 4 + msglen:
- return
- msg = self.recvbuf[4+12+4:4+12+4+msglen]
- self.recvbuf = self.recvbuf[4+12+4+msglen:]
- else:
- if len(self.recvbuf) < 4 + 12 + 4 + 4:
- return
- command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
- msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
- checksum = self.recvbuf[4+12+4:4+12+4+4]
- if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:
- return
- msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]
- th = sha256(msg)
- h = sha256(th)
- if checksum != h[:4]:
- raise ValueError("got bad checksum " + repr(self.recvbuf))
- self.recvbuf = self.recvbuf[4+12+4+4+msglen:]
- if command in self.messagemap:
- f = BytesIO(msg)
- t = self.messagemap[command]()
- t.deserialize(f)
- self.got_message(t)
- else:
- logger.warning("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg)))
- raise ValueError("Unknown command: '%s'" % (command))
+ if len(self.recvbuf) < 4 + 12 + 4 + 4:
+ return
+ command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
+ msglen = struct.unpack("<i", self.recvbuf[4+12:4+12+4])[0]
+ checksum = self.recvbuf[4+12+4:4+12+4+4]
+ if len(self.recvbuf) < 4 + 12 + 4 + 4 + msglen:
+ return
+ msg = self.recvbuf[4+12+4+4:4+12+4+4+msglen]
+ th = sha256(msg)
+ h = sha256(th)
+ if checksum != h[:4]:
+ raise ValueError("got bad checksum " + repr(self.recvbuf))
+ self.recvbuf = self.recvbuf[4+12+4+4+msglen:]
+ if command not in self.messagemap:
+ raise ValueError("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg)))
+ f = BytesIO(msg)
+ t = self.messagemap[command]()
+ t.deserialize(f)
+ self.got_message(t)
except Exception as e:
- logger.exception('got_data:', repr(e))
+ logger.exception('Error reading message:', repr(e))
raise
def send_message(self, message, pushbuf=False):
@@ -1787,10 +1636,9 @@ class NodeConn(asyncore.dispatcher):
tmsg += command
tmsg += b"\x00" * (12 - len(command))
tmsg += struct.pack("<I", len(data))
- if self.ver_send >= 209:
- th = sha256(data)
- h = sha256(th)
- tmsg += h[:4]
+ th = sha256(data)
+ h = sha256(th)
+ tmsg += h[:4]
tmsg += data
with mininode_lock:
if (len(self.sendbuf) == 0 and not pushbuf):
@@ -1804,9 +1652,6 @@ class NodeConn(asyncore.dispatcher):
self.last_sent = time.time()
def got_message(self, message):
- if message.command == b"version":
- if message.nVersion <= BIP0031_VERSION:
- self.messagemap[b'ping'] = msg_ping_prebip31
if self.last_sent + 30 * 60 < time.time():
self.send_message(self.messagemap[b'ping']())
self._log_message("receive", message)
@@ -1839,13 +1684,3 @@ class NetworkThread(Thread):
[ obj.handle_close() for obj in disconnected ]
asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1)
logger.debug("Network thread closing")
-
-
-# An exception we can raise if we detect a potential disconnect
-# (p2p or rpc) before the test is complete
-class EarlyDisconnectError(Exception):
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return repr(self.value)
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 8f5339a02a..a4c046bd3d 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -370,7 +370,7 @@ class CScriptTruncatedPushDataError(CScriptInvalidError):
super(CScriptTruncatedPushDataError, self).__init__(msg)
# This is used, eg, for blockchain heights in coinbase scripts (bip34)
-class CScriptNum(object):
+class CScriptNum():
def __init__(self, d=0):
self.value = d
diff --git a/test/functional/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index 0070844168..7b40c47fbf 100644
--- a/test/functional/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -31,7 +31,7 @@ def recvall(s, n):
return rv
### Implementation classes
-class Socks5Configuration(object):
+class Socks5Configuration():
"""Proxy configuration."""
def __init__(self):
self.addr = None # Bind address (must be set)
@@ -39,7 +39,7 @@ class Socks5Configuration(object):
self.unauth = False # Support unauthenticated
self.auth = False # Support authentication
-class Socks5Command(object):
+class Socks5Command():
"""Information about an incoming socks5 command."""
def __init__(self, cmd, atyp, addr, port, username, password):
self.cmd = cmd # Command (one of Command.*)
@@ -51,7 +51,7 @@ class Socks5Command(object):
def __repr__(self):
return 'Socks5Command(%s,%s,%s,%s,%s,%s)' % (self.cmd, self.atyp, self.addr, self.port, self.username, self.password)
-class Socks5Connection(object):
+class Socks5Connection():
def __init__(self, serv, conn, peer):
self.serv = serv
self.conn = conn
@@ -122,7 +122,7 @@ class Socks5Connection(object):
finally:
self.conn.close()
-class Socks5Server(object):
+class Socks5Server():
def __init__(self, conf):
self.conf = conf
self.s = socket.socket(conf.af)
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 381513ab9e..8df50474f3 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -43,7 +43,7 @@ TEST_EXIT_PASSED = 0
TEST_EXIT_FAILED = 1
TEST_EXIT_SKIPPED = 77
-class BitcoinTestFramework(object):
+class BitcoinTestFramework():
"""Base class for a bitcoin test script.
Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods.
@@ -102,8 +102,11 @@ class BitcoinTestFramework(object):
check_json_precision()
+ self.options.cachedir = os.path.abspath(self.options.cachedir)
+
# Set up temp directory and start logging
if self.options.tmpdir:
+ self.options.tmpdir = os.path.abspath(self.options.tmpdir)
os.makedirs(self.options.tmpdir, exist_ok=False)
else:
self.options.tmpdir = tempfile.mkdtemp(prefix="test")
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 12dab57a02..34b458482a 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -13,13 +13,15 @@ import os
import subprocess
import time
+from .authproxy import JSONRPCException
+from .mininode import NodeConn
from .util import (
assert_equal,
get_rpc_proxy,
rpc_url,
wait_until,
+ p2p_port,
)
-from .authproxy import JSONRPCException
BITCOIND_PROC_WAIT_TIMEOUT = 60
@@ -31,9 +33,11 @@ class TestNode():
- state about the node (whether it's running, etc)
- a Python subprocess.Popen object representing the running process
- an RPC connection to the node
+ - one or more P2P connections to the node
+
- To make things easier for the test writer, a bit of magic is happening under the covers.
- Any unrecognised messages will be dispatched to the RPC connection."""
+ To make things easier for the test writer, any unrecognised messages will
+ be dispatched to the RPC connection."""
def __init__(self, i, dirname, extra_args, rpchost, timewait, binary, stderr, mocktime, coverage_dir):
self.index = i
@@ -63,10 +67,12 @@ class TestNode():
self.url = None
self.log = logging.getLogger('TestFramework.node%d' % i)
- def __getattr__(self, *args, **kwargs):
+ self.p2ps = []
+
+ def __getattr__(self, name):
"""Dispatches any unrecognised messages to the RPC connection."""
assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection"
- return self.rpc.__getattr__(*args, **kwargs)
+ return getattr(self.rpc, name)
def start(self, extra_args=None, stderr=None):
"""Start the node."""
@@ -119,6 +125,7 @@ class TestNode():
self.stop()
except http.client.CannotSendRequest:
self.log.exception("Unable to stop node.")
+ del self.p2ps[:]
def is_node_stopped(self):
"""Checks whether the node has stopped.
@@ -151,6 +158,39 @@ class TestNode():
self.encryptwallet(passphrase)
self.wait_until_stopped()
+ def add_p2p_connection(self, p2p_conn, **kwargs):
+ """Add a p2p connection to the node.
+
+ This method adds the p2p connection to the self.p2ps list and also
+ returns the connection to the caller."""
+ if 'dstport' not in kwargs:
+ kwargs['dstport'] = p2p_port(self.index)
+ if 'dstaddr' not in kwargs:
+ kwargs['dstaddr'] = '127.0.0.1'
+ self.p2ps.append(p2p_conn)
+ kwargs.update({'callback': p2p_conn})
+ p2p_conn.add_connection(NodeConn(**kwargs))
+
+ return p2p_conn
+
+ @property
+ def p2p(self):
+ """Return the first p2p connection
+
+ Convenience property - most tests only use a single p2p connection to each
+ node, so this saves having to write node.p2ps[0] many times."""
+ assert self.p2ps, "No p2p connection"
+ return self.p2ps[0]
+
+ def disconnect_p2ps(self):
+ """Close all p2p connections to the node."""
+ for p in self.p2ps:
+ # Connection could have already been closed by other end.
+ if p.connection is not None:
+ p.connection.disconnect_node()
+ self.p2ps = []
+
+
class TestNodeCLI():
"""Interface to bitcoin-cli for an individual node"""
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 8c4651f6e0..ca36426a0a 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -124,6 +124,8 @@ BASE_SCRIPTS= [
'resendwallettransactions.py',
'minchainwork.py',
'p2p-fingerprint.py',
+ 'uacomment.py',
+ 'p2p-acceptblock.py',
]
EXTENDED_SCRIPTS = [
@@ -151,7 +153,6 @@ EXTENDED_SCRIPTS = [
'txn_clone.py --mineblock',
'notifications.py',
'invalidateblock.py',
- 'p2p-acceptblock.py',
'replace-by-fee.py',
]
@@ -459,7 +460,7 @@ def check_script_list(src_dir):
# On travis this warning is an error to prevent merging incomplete commits into master
sys.exit(1)
-class RPCCoverage(object):
+class RPCCoverage():
"""
Coverage reporting utilities for test_runner.
diff --git a/test/functional/uacomment.py b/test/functional/uacomment.py
new file mode 100755
index 0000000000..0b2c64ab69
--- /dev/null
+++ b/test/functional/uacomment.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test the -uacomment option."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class UacommentTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+ self.setup_clean_chain = True
+
+ def run_test(self):
+ self.log.info("test multiple -uacomment")
+ test_uacomment = self.nodes[0].getnetworkinfo()["subversion"][-12:-1]
+ assert_equal(test_uacomment, "(testnode0)")
+
+ self.restart_node(0, ["-uacomment=foo"])
+ foo_uacomment = self.nodes[0].getnetworkinfo()["subversion"][-17:-1]
+ assert_equal(foo_uacomment, "(testnode0; foo)")
+
+ self.log.info("test -uacomment max length")
+ self.stop_node(0)
+ expected = "Total length of network version string (286) exceeds maximum length (256). Reduce the number or size of uacomments."
+ self.assert_start_raises_init_error(0, ["-uacomment=" + 'a' * 256], expected)
+
+ self.log.info("test -uacomment unsafe characters")
+ for unsafe_char in ['/', ':', '(', ')']:
+ expected = "User Agent comment (" + unsafe_char + ") contains unsafe characters"
+ self.assert_start_raises_init_error(0, ["-uacomment=" + unsafe_char], expected)
+
+if __name__ == '__main__':
+ UacommentTest().main()
diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py
index 40726d2a76..bc1efaee15 100755
--- a/test/functional/wallet-accounts.py
+++ b/test/functional/wallet-accounts.py
@@ -72,62 +72,135 @@ class WalletAccountsTest(BitcoinTestFramework):
# otherwise we're off by exactly the fee amount as that's mined
# and matures in the next 100 blocks
node.sendfrom("", common_address, fee)
- accounts = ["a", "b", "c", "d", "e"]
amount_to_send = 1.0
- account_addresses = dict()
+
+ # Create accounts and make sure subsequent account API calls
+ # recognize the account/address associations.
+ accounts = [Account(name) for name in ("a", "b", "c", "d", "e")]
for account in accounts:
- address = node.getaccountaddress(account)
- account_addresses[account] = address
-
- node.getnewaddress(account)
- assert_equal(node.getaccount(address), account)
- assert(address in node.getaddressesbyaccount(account))
-
- node.sendfrom("", address, amount_to_send)
-
+ account.add_receive_address(node.getaccountaddress(account.name))
+ account.verify(node)
+
+ # Send a transaction to each account, and make sure this forces
+ # getaccountaddress to generate a new receiving address.
+ for account in accounts:
+ node.sendtoaddress(account.receive_address, amount_to_send)
+ account.add_receive_address(node.getaccountaddress(account.name))
+ account.verify(node)
+
+ # Check the amounts received.
node.generate(1)
+ for account in accounts:
+ assert_equal(
+ node.getreceivedbyaddress(account.addresses[0]), amount_to_send)
+ assert_equal(node.getreceivedbyaccount(account.name), amount_to_send)
- for i in range(len(accounts)):
- from_account = accounts[i]
+ # Check that sendfrom account reduces listaccounts balances.
+ for i, account in enumerate(accounts):
to_account = accounts[(i+1) % len(accounts)]
- to_address = account_addresses[to_account]
- node.sendfrom(from_account, to_address, amount_to_send)
-
+ node.sendfrom(account.name, to_account.receive_address, amount_to_send)
node.generate(1)
-
for account in accounts:
- address = node.getaccountaddress(account)
- assert(address != account_addresses[account])
- assert_equal(node.getreceivedbyaccount(account), 2)
- node.move(account, "", node.getbalance(account))
-
+ account.add_receive_address(node.getaccountaddress(account.name))
+ account.verify(node)
+ assert_equal(node.getreceivedbyaccount(account.name), 2)
+ node.move(account.name, "", node.getbalance(account.name))
+ account.verify(node)
node.generate(101)
-
expected_account_balances = {"": 5200}
for account in accounts:
- expected_account_balances[account] = 0
-
+ expected_account_balances[account.name] = 0
assert_equal(node.listaccounts(), expected_account_balances)
-
assert_equal(node.getbalance(""), 5200)
+ # Check that setaccount can assign an account to a new unused address.
for account in accounts:
address = node.getaccountaddress("")
- node.setaccount(address, account)
- assert(address in node.getaddressesbyaccount(account))
+ node.setaccount(address, account.name)
+ account.add_address(address)
+ account.verify(node)
assert(address not in node.getaddressesbyaccount(""))
+ # Check that addmultisigaddress can assign accounts.
for account in accounts:
addresses = []
for x in range(10):
addresses.append(node.getnewaddress())
- multisig_address = node.addmultisigaddress(5, addresses, account)
+ multisig_address = node.addmultisigaddress(5, addresses, account.name)
+ account.add_address(multisig_address)
+ account.verify(node)
node.sendfrom("", multisig_address, 50)
-
node.generate(101)
-
for account in accounts:
- assert_equal(node.getbalance(account), 50)
+ assert_equal(node.getbalance(account.name), 50)
+
+ # Check that setaccount can change the account of an address from a
+ # different account.
+ change_account(node, accounts[0].addresses[0], accounts[0], accounts[1])
+
+ # Check that setaccount can change the account of an address which
+ # is the receiving address of a different account.
+ change_account(node, accounts[0].receive_address, accounts[0], accounts[1])
+
+ # Check that setaccount can set the account of an address already
+ # in the account. This is a no-op.
+ change_account(node, accounts[2].addresses[0], accounts[2], accounts[2])
+
+ # Check that setaccount can set the account of an address which is
+ # already the receiving address of the account. It would probably make
+ # sense for this to be a no-op, but right now it resets the receiving
+ # address, causing getaccountaddress to return a brand new address.
+ change_account(node, accounts[2].receive_address, accounts[2], accounts[2])
+
+class Account:
+ def __init__(self, name):
+ # Account name
+ self.name = name
+ # Current receiving address associated with this account.
+ self.receive_address = None
+ # List of all addresses assigned with this account
+ self.addresses = []
+
+ def add_address(self, address):
+ assert_equal(address not in self.addresses, True)
+ self.addresses.append(address)
+
+ def add_receive_address(self, address):
+ self.add_address(address)
+ self.receive_address = address
+
+ def verify(self, node):
+ if self.receive_address is not None:
+ assert self.receive_address in self.addresses
+ assert_equal(node.getaccountaddress(self.name), self.receive_address)
+
+ for address in self.addresses:
+ assert_equal(node.getaccount(address), self.name)
+
+ assert_equal(
+ set(node.getaddressesbyaccount(self.name)), set(self.addresses))
+
+
+def change_account(node, address, old_account, new_account):
+ assert_equal(address in old_account.addresses, True)
+ node.setaccount(address, new_account.name)
+
+ old_account.addresses.remove(address)
+ new_account.add_address(address)
+
+ # Calling setaccount on an address which was previously the receiving
+ # address of a different account should reset the receiving address of
+ # the old account, causing getaccountaddress to return a brand new
+ # address.
+ if address == old_account.receive_address:
+ new_address = node.getaccountaddress(old_account.name)
+ assert_equal(new_address not in old_account.addresses, True)
+ assert_equal(new_address not in new_account.addresses, True)
+ old_account.add_receive_address(new_address)
+
+ old_account.verify(node)
+ new_account.verify(node)
+
if __name__ == '__main__':
WalletAccountsTest().main()
diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py
index 5ef3bf5bff..9b6ce68609 100755
--- a/test/functional/wallet-hd.py
+++ b/test/functional/wallet-hd.py
@@ -10,6 +10,7 @@ from test_framework.util import (
connect_nodes_bi,
)
import shutil
+import os
class WalletHDTest(BitcoinTestFramework):
def set_test_params(self):
@@ -70,9 +71,9 @@ class WalletHDTest(BitcoinTestFramework):
self.stop_node(1)
# we need to delete the complete regtest directory
# otherwise node1 would auto-recover all funds in flag the keypool keys as used
- shutil.rmtree(tmpdir + "/node1/regtest/blocks")
- shutil.rmtree(tmpdir + "/node1/regtest/chainstate")
- shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
+ shutil.rmtree(os.path.join(tmpdir, "node1/regtest/blocks"))
+ shutil.rmtree(os.path.join(tmpdir, "node1/regtest/chainstate"))
+ shutil.copyfile(os.path.join(tmpdir, "hd.bak"), os.path.join(tmpdir, "node1/regtest/wallet.dat"))
self.start_node(1)
# Assert that derivation is deterministic
@@ -91,6 +92,22 @@ class WalletHDTest(BitcoinTestFramework):
self.start_node(1, extra_args=self.extra_args[1] + ['-rescan'])
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
+ # Try a RPC based rescan
+ self.stop_node(1)
+ shutil.rmtree(os.path.join(tmpdir, "node1/regtest/blocks"))
+ shutil.rmtree(os.path.join(tmpdir, "node1/regtest/chainstate"))
+ shutil.copyfile(os.path.join(tmpdir, "hd.bak"), os.path.join(tmpdir, "node1/regtest/wallet.dat"))
+ self.start_node(1, extra_args=self.extra_args[1])
+ connect_nodes_bi(self.nodes, 0, 1)
+ self.sync_all()
+ out = self.nodes[1].rescanblockchain(0, 1)
+ assert_equal(out['start_height'], 0)
+ assert_equal(out['stop_height'], 1)
+ out = self.nodes[1].rescanblockchain()
+ assert_equal(out['start_height'], 0)
+ assert_equal(out['stop_height'], self.nodes[1].getblockcount())
+ assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
+
# send a tx and make sure its using the internal chain for the changeoutput
txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']
diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py
index 15ea26afa1..85a149793e 100755
--- a/test/functional/walletbackup.py
+++ b/test/functional/walletbackup.py
@@ -190,6 +190,16 @@ class WalletBackupTest(BitcoinTestFramework):
assert_equal(self.nodes[1].getbalance(), balance1)
assert_equal(self.nodes[2].getbalance(), balance2)
+ # Backup to source wallet file must fail
+ sourcePaths = [
+ tmpdir + "/node0/regtest/wallet.dat",
+ tmpdir + "/node0/./regtest/wallet.dat",
+ tmpdir + "/node0/regtest/",
+ tmpdir + "/node0/regtest"]
+
+ for sourcePath in sourcePaths:
+ assert_raises_rpc_error(-4, "backup failed", self.nodes[0].backupwallet, sourcePath)
+
if __name__ == '__main__':
WalletBackupTest().main()
diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py
index 382ef5bae2..fa30318416 100755
--- a/test/functional/zmq_test.py
+++ b/test/functional/zmq_test.py
@@ -2,16 +2,37 @@
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test the ZMQ API."""
+"""Test the ZMQ notification interface."""
import configparser
import os
import struct
from test_framework.test_framework import BitcoinTestFramework, SkipTest
+from test_framework.mininode import CTransaction
from test_framework.util import (assert_equal,
bytes_to_hex_str,
hash256,
)
+from io import BytesIO
+
+class ZMQSubscriber:
+ def __init__(self, socket, topic):
+ self.sequence = 0
+ self.socket = socket
+ self.topic = topic
+
+ import zmq
+ self.socket.setsockopt(zmq.SUBSCRIBE, self.topic)
+
+ def receive(self):
+ topic, body, seq = self.socket.recv_multipart()
+ # Topic should match the subscriber topic.
+ assert_equal(topic, self.topic)
+ # Sequence should be incremental.
+ assert_equal(struct.unpack('<I', seq)[-1], self.sequence)
+ self.sequence += 1
+ return body
+
class ZMQTest (BitcoinTestFramework):
def set_test_params(self):
@@ -24,26 +45,33 @@ class ZMQTest (BitcoinTestFramework):
except ImportError:
raise SkipTest("python3-zmq module not available.")
- # Check that bitcoin has been built with ZMQ enabled
+ # Check that bitcoin has been built with ZMQ enabled.
config = configparser.ConfigParser()
if not self.options.configfile:
- self.options.configfile = os.path.dirname(__file__) + "/../config.ini"
+ self.options.configfile = os.path.abspath(os.path.join(os.path.dirname(__file__), "../config.ini"))
config.read_file(open(self.options.configfile))
if not config["components"].getboolean("ENABLE_ZMQ"):
raise SkipTest("bitcoind has not been built with zmq enabled.")
- self.zmqContext = zmq.Context()
- self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
- self.zmqSubSocket.set(zmq.RCVTIMEO, 60000)
- self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")
- self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx")
- self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawblock")
- self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtx")
- ip_address = "tcp://127.0.0.1:28332"
- self.zmqSubSocket.connect(ip_address)
- self.extra_args = [['-zmqpubhashblock=%s' % ip_address, '-zmqpubhashtx=%s' % ip_address,
- '-zmqpubrawblock=%s' % ip_address, '-zmqpubrawtx=%s' % ip_address], []]
+ # Initialize ZMQ context and socket.
+ # All messages are received in the same socket which means
+ # that this test fails if the publishing order changes.
+ # Note that the publishing order is not defined in the documentation and
+ # is subject to change.
+ address = "tcp://127.0.0.1:28332"
+ self.zmq_context = zmq.Context()
+ socket = self.zmq_context.socket(zmq.SUB)
+ socket.set(zmq.RCVTIMEO, 60000)
+ socket.connect(address)
+
+ # Subscribe to all available topics.
+ self.hashblock = ZMQSubscriber(socket, b"hashblock")
+ self.hashtx = ZMQSubscriber(socket, b"hashtx")
+ self.rawblock = ZMQSubscriber(socket, b"rawblock")
+ self.rawtx = ZMQSubscriber(socket, b"rawtx")
+
+ self.extra_args = [["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [self.hashblock, self.hashtx, self.rawblock, self.rawtx]], []]
self.add_nodes(self.num_nodes, self.extra_args)
self.start_nodes()
@@ -51,103 +79,48 @@ class ZMQTest (BitcoinTestFramework):
try:
self._zmq_test()
finally:
- # Destroy the zmq context
- self.log.debug("Destroying zmq context")
- self.zmqContext.destroy(linger=None)
+ # Destroy the ZMQ context.
+ self.log.debug("Destroying ZMQ context")
+ self.zmq_context.destroy(linger=None)
def _zmq_test(self):
- genhashes = self.nodes[0].generate(1)
+ num_blocks = 5
+ self.log.info("Generate %(n)d blocks (and %(n)d coinbase txes)" % {"n": num_blocks})
+ genhashes = self.nodes[0].generate(num_blocks)
self.sync_all()
- self.log.info("Wait for tx")
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- assert_equal(topic, b"hashtx")
- txhash = msg[1]
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, 0) # must be sequence 0 on hashtx
-
- # rawtx
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- assert_equal(topic, b"rawtx")
- body = msg[1]
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, 0) # must be sequence 0 on rawtx
-
- # Check that the rawtx hashes to the hashtx
- assert_equal(hash256(body), txhash)
-
- self.log.info("Wait for block")
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- assert_equal(topic, b"hashblock")
- body = msg[1]
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, 0) # must be sequence 0 on hashblock
- blkhash = bytes_to_hex_str(body)
- assert_equal(genhashes[0], blkhash) # blockhash from generate must be equal to the hash received over zmq
-
- # rawblock
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- assert_equal(topic, b"rawblock")
- body = msg[1]
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, 0) #must be sequence 0 on rawblock
-
- # Check the hash of the rawblock's header matches generate
- assert_equal(genhashes[0], bytes_to_hex_str(hash256(body[:80])))
-
- self.log.info("Generate 10 blocks (and 10 coinbase txes)")
- n = 10
- genhashes = self.nodes[1].generate(n)
- self.sync_all()
+ for x in range(num_blocks):
+ # Should receive the coinbase txid.
+ txid = self.hashtx.receive()
+
+ # Should receive the coinbase raw transaction.
+ hex = self.rawtx.receive()
+ tx = CTransaction()
+ tx.deserialize(BytesIO(hex))
+ tx.calc_sha256()
+ assert_equal(tx.hash, bytes_to_hex_str(txid))
- zmqHashes = []
- zmqRawHashed = []
- blockcount = 0
- for x in range(n * 4):
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- body = msg[1]
- if topic == b"hashblock":
- zmqHashes.append(bytes_to_hex_str(body))
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, blockcount + 1)
- blockcount += 1
- if topic == b"rawblock":
- zmqRawHashed.append(bytes_to_hex_str(hash256(body[:80])))
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, blockcount)
-
- for x in range(n):
- assert_equal(genhashes[x], zmqHashes[x]) # blockhash from generate must be equal to the hash received over zmq
- assert_equal(genhashes[x], zmqRawHashed[x])
+ # Should receive the generated block hash.
+ hash = bytes_to_hex_str(self.hashblock.receive())
+ assert_equal(genhashes[x], hash)
+ # The block should only have the coinbase txid.
+ assert_equal([bytes_to_hex_str(txid)], self.nodes[1].getblock(hash)["tx"])
+
+ # Should receive the generated raw block.
+ block = self.rawblock.receive()
+ assert_equal(genhashes[x], bytes_to_hex_str(hash256(block[:80])))
self.log.info("Wait for tx from second node")
- # test tx from a second node
- hashRPC = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
+ payment_txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
self.sync_all()
- # now we should receive a zmq msg because the tx was broadcast
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- assert_equal(topic, b"hashtx")
- body = msg[1]
- hashZMQ = bytes_to_hex_str(body)
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, blockcount + 1)
-
- msg = self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- assert_equal(topic, b"rawtx")
- body = msg[1]
- hashedZMQ = bytes_to_hex_str(hash256(body))
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- assert_equal(msgSequence, blockcount+1)
- assert_equal(hashRPC, hashZMQ) # txid from sendtoaddress must be equal to the hash received over zmq
- assert_equal(hashRPC, hashedZMQ)
+ # Should receive the broadcasted txid.
+ txid = self.hashtx.receive()
+ assert_equal(payment_txid, bytes_to_hex_str(txid))
+
+ # Should receive the broadcasted raw transaction.
+ hex = self.rawtx.receive()
+ assert_equal(payment_txid, bytes_to_hex_str(hash256(hex)))
if __name__ == '__main__':
ZMQTest().main()