aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml14
-rw-r--r--.fuzzbuzz.yml2
-rw-r--r--.gitignore1
-rw-r--r--COPYING4
-rw-r--r--Makefile.am17
-rw-r--r--README.md3
-rw-r--r--build-aux/m4/l_atomic.m43
-rw-r--r--build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj1
-rw-r--r--build_msvc/testconsensus/testconsensus.cpp2
-rwxr-xr-xci/lint/04_install.sh7
-rwxr-xr-xci/lint/05_before_script.sh9
-rwxr-xr-xci/lint/06_script.sh13
-rwxr-xr-xci/lint_run_all.sh11
-rw-r--r--ci/test/00_setup_env_native_asan.sh2
-rw-r--r--ci/test/00_setup_env_native_fuzz.sh2
-rw-r--r--ci/test/00_setup_env_native_qt5.sh2
-rw-r--r--ci/test/00_setup_env_native_valgrind.sh2
-rwxr-xr-xci/test/03_before_install.sh22
-rwxr-xr-xci/test/05_before_script.sh2
-rwxr-xr-xci/test/06_script_a.sh12
-rwxr-xr-xci/test/06_script_b.sh16
-rwxr-xr-xci/test/wrap-qemu.sh2
-rwxr-xr-xci/test_run_all.sh3
-rw-r--r--configure.ac94
-rw-r--r--contrib/debian/copyright2
-rwxr-xr-xcontrib/devtools/circular-dependencies.py9
-rwxr-xr-xcontrib/devtools/gen-manpages.sh7
-rw-r--r--contrib/devtools/pixie.py323
-rwxr-xr-xcontrib/devtools/security-check.py173
-rwxr-xr-xcontrib/devtools/symbol-check.py98
-rwxr-xr-xcontrib/filter-lcov.py2
-rwxr-xr-xcontrib/gitian-build.py21
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml20
-rw-r--r--contrib/gitian-descriptors/gitian-osx-signer.yml20
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml6
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml6
-rw-r--r--contrib/gitian-keys/keys.txt71
-rw-r--r--contrib/guix/README.md77
-rwxr-xr-xcontrib/guix/guix-build.sh179
-rw-r--r--contrib/guix/libexec/build.sh166
-rw-r--r--contrib/guix/manifest.scm50
-rw-r--r--contrib/guix/patches/nsis-SConstruct-sde-support.patch15
-rw-r--r--contrib/init/README.md4
-rw-r--r--contrib/init/bitcoind.service6
-rwxr-xr-xcontrib/install_db4.sh153
-rwxr-xr-xcontrib/macdeploy/detached-sig-apply.sh36
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh35
-rwxr-xr-xcontrib/macdeploy/extract-osx-sdk.sh34
-rw-r--r--contrib/signet/README.md61
-rwxr-xr-xcontrib/signet/miner639
-rw-r--r--contrib/testgen/base58.py2
-rwxr-xr-xcontrib/testgen/gen_key_io_test_vectors.py2
-rwxr-xr-xcontrib/zmq/zmq_sub.py2
-rw-r--r--depends/Makefile50
-rw-r--r--depends/README.md65
-rw-r--r--depends/config.site.in74
-rw-r--r--depends/funcs.mk30
-rw-r--r--depends/hosts/darwin.mk97
-rw-r--r--depends/packages/libnatpmp.mk19
-rw-r--r--depends/packages/packages.mk1
-rw-r--r--depends/packages/qt.mk25
-rw-r--r--depends/patches/fontconfig/gperf_header_regen.patch2
-rw-r--r--depends/patches/native_cctools/ld64_disable_threading.patch2
-rw-r--r--depends/patches/qt/freetype_back_compat.patch2
-rw-r--r--doc/JSON-RPC-interface.md15
-rw-r--r--doc/REST-interface.md4
-rw-r--r--doc/build-osx.md7
-rw-r--r--doc/build-unix.md24
-rw-r--r--doc/dependencies.md4
-rw-r--r--doc/developer-notes.md27
-rw-r--r--doc/guix.md3
-rw-r--r--doc/man/Makefile.am4
-rw-r--r--doc/man/bitcoin-cli.12
-rw-r--r--doc/man/bitcoin-qt.12
-rw-r--r--doc/man/bitcoin-tx.12
-rw-r--r--doc/man/bitcoin-util.15
-rw-r--r--doc/man/bitcoin-wallet.12
-rw-r--r--doc/man/bitcoind.12
-rw-r--r--doc/productivity.md1
-rw-r--r--doc/release-notes-18077.md10
-rw-r--r--doc/release-notes.md5
-rw-r--r--doc/release-notes/release-notes-0.21.0.md1336
-rw-r--r--doc/release-process.md16
-rw-r--r--doc/tor.md156
-rwxr-xr-xshare/genbuild.sh4
-rw-r--r--src/Makefile.am44
-rw-r--r--src/Makefile.bench.include2
-rw-r--r--src/Makefile.qt.include4
-rw-r--r--src/Makefile.qttest.include2
-rw-r--r--src/Makefile.test.include5
-rw-r--r--src/Makefile.test_fuzz.include1
-rw-r--r--src/addrdb.cpp2
-rw-r--r--src/addrdb.h2
-rw-r--r--src/addrman.cpp2
-rw-r--r--src/attributes.h2
-rw-r--r--src/banman.cpp2
-rw-r--r--src/base58.cpp2
-rw-r--r--src/base58.h2
-rw-r--r--src/bench/base58.cpp2
-rw-r--r--src/bench/block_assemble.cpp2
-rw-r--r--src/bench/chacha20.cpp2
-rw-r--r--src/bench/checkqueue.cpp10
-rw-r--r--src/bench/coin_selection.cpp2
-rw-r--r--src/bench/crypto_hash.cpp54
-rw-r--r--src/bench/gcs_filter.cpp2
-rw-r--r--src/bench/hashpadding.cpp2
-rw-r--r--src/bench/lockedpool.cpp2
-rw-r--r--src/bench/mempool_eviction.cpp2
-rw-r--r--src/bench/mempool_stress.cpp2
-rw-r--r--src/bench/poly1305.cpp2
-rw-r--r--src/bench/prevector.cpp2
-rw-r--r--src/bench/rollingbloom.cpp2
-rw-r--r--src/bench/rpc_blockchain.cpp3
-rw-r--r--src/bench/rpc_mempool.cpp2
-rw-r--r--src/bench/util_time.cpp2
-rw-r--r--src/bench/verify_script.cpp2
-rw-r--r--src/bench/wallet_balance.cpp2
-rw-r--r--src/bitcoin-cli.cpp72
-rw-r--r--src/bitcoin-util-res.rc35
-rw-r--r--src/bitcoin-util.cpp221
-rw-r--r--src/bitcoin-wallet.cpp5
-rw-r--r--src/blockencodings.cpp2
-rw-r--r--src/blockfilter.cpp2
-rw-r--r--src/bloom.cpp2
-rw-r--r--src/bloom.h2
-rw-r--r--src/chainparamsbase.cpp2
-rw-r--r--src/chainparamsbase.h2
-rw-r--r--src/checkqueue.h92
-rw-r--r--src/clientversion.cpp2
-rw-r--r--src/clientversion.h2
-rw-r--r--src/coins.cpp4
-rw-r--r--src/coins.h29
-rw-r--r--src/compat.h2
-rw-r--r--src/compat/assumptions.h2
-rw-r--r--src/compat/glibc_compat.cpp8
-rw-r--r--src/compat/glibc_sanity.cpp2
-rw-r--r--src/consensus/params.h2
-rw-r--r--src/consensus/tx_verify.cpp2
-rw-r--r--src/consensus/tx_verify.h2
-rw-r--r--src/consensus/validation.h2
-rw-r--r--src/core_io.h7
-rw-r--r--src/core_read.cpp2
-rw-r--r--src/core_write.cpp33
-rw-r--r--src/crypto/chacha_poly_aead.h4
-rw-r--r--src/crypto/common.h2
-rw-r--r--src/crypto/muhash.cpp338
-rw-r--r--src/crypto/muhash.h130
-rw-r--r--src/crypto/sha256_shani.cpp2
-rw-r--r--src/crypto/sha256_sse4.cpp2
-rw-r--r--src/crypto/siphash.cpp2
-rw-r--r--src/crypto/siphash.h2
-rw-r--r--src/cuckoocache.h2
-rw-r--r--src/dbwrapper.h2
-rw-r--r--src/flatfile.cpp1
-rw-r--r--src/fs.cpp8
-rw-r--r--src/fs.h11
-rw-r--r--src/hash.cpp4
-rw-r--r--src/hash.h2
-rw-r--r--src/httprpc.h2
-rw-r--r--src/index/blockfilterindex.cpp3
-rw-r--r--src/index/blockfilterindex.h8
-rw-r--r--src/index/disktxpos.h2
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp34
-rw-r--r--src/interfaces/node.h4
-rw-r--r--src/key.cpp6
-rw-r--r--src/key_io.cpp58
-rw-r--r--src/key_io.h1
-rw-r--r--src/logging.cpp2
-rw-r--r--src/logging.h4
-rw-r--r--src/mapport.cpp336
-rw-r--r--src/mapport.h30
-rw-r--r--src/merkleblock.cpp4
-rw-r--r--src/merkleblock.h2
-rw-r--r--src/miner.cpp2
-rw-r--r--src/miner.h2
-rw-r--r--src/net.cpp320
-rw-r--r--src/net.h1090
-rw-r--r--src/net_permissions.cpp2
-rw-r--r--src/net_processing.cpp418
-rw-r--r--src/net_processing.h193
-rw-r--r--src/netaddress.cpp81
-rw-r--r--src/netaddress.h26
-rw-r--r--src/netmessagemaker.h2
-rw-r--r--src/node/coinstats.h2
-rw-r--r--src/node/interfaces.cpp11
-rw-r--r--src/node/transaction.cpp2
-rw-r--r--src/node/utxo_snapshot.h2
-rw-r--r--src/noui.cpp2
-rw-r--r--src/noui.h2
-rw-r--r--src/optional.h18
-rw-r--r--src/outputtype.cpp2
-rw-r--r--src/outputtype.h8
-rw-r--r--src/policy/feerate.cpp2
-rw-r--r--src/policy/feerate.h2
-rw-r--r--src/policy/fees.cpp37
-rw-r--r--src/policy/fees.h13
-rw-r--r--src/policy/policy.cpp2
-rw-r--r--src/policy/policy.h2
-rw-r--r--src/policy/rbf.cpp2
-rw-r--r--src/policy/rbf.h2
-rw-r--r--src/primitives/block.h2
-rw-r--r--src/primitives/transaction.h2
-rw-r--r--src/protocol.cpp2
-rw-r--r--src/protocol.h2
-rw-r--r--src/psbt.cpp7
-rw-r--r--src/pubkey.cpp2
-rw-r--r--src/pubkey.h2
-rw-r--r--src/qt/README.md121
-rw-r--r--src/qt/addressbookpage.cpp4
-rw-r--r--src/qt/addressbookpage.h2
-rw-r--r--src/qt/addresstablemodel.cpp14
-rw-r--r--src/qt/addresstablemodel.h2
-rw-r--r--src/qt/askpassphrasedialog.cpp4
-rw-r--r--src/qt/askpassphrasedialog.h2
-rw-r--r--src/qt/bantablemodel.cpp8
-rw-r--r--src/qt/bitcoin.cpp10
-rw-r--r--src/qt/bitcoinaddressvalidator.h2
-rw-r--r--src/qt/bitcoinamountfield.cpp2
-rw-r--r--src/qt/bitcoinamountfield.h2
-rw-r--r--src/qt/bitcoingui.cpp3
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/clientmodel.cpp1
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/coincontroldialog.cpp6
-rw-r--r--src/qt/coincontroldialog.h2
-rw-r--r--src/qt/createwalletdialog.cpp6
-rw-r--r--src/qt/editaddressdialog.cpp4
-rw-r--r--src/qt/editaddressdialog.h2
-rw-r--r--src/qt/forms/createwalletdialog.ui253
-rw-r--r--src/qt/forms/debugwindow.ui99
-rw-r--r--src/qt/forms/optionsdialog.ui10
-rw-r--r--src/qt/forms/overviewpage.ui15
-rw-r--r--src/qt/guiutil.cpp46
-rw-r--r--src/qt/guiutil.h25
-rw-r--r--src/qt/intro.cpp2
-rw-r--r--src/qt/modaloverlay.h2
-rw-r--r--src/qt/notificator.cpp4
-rw-r--r--src/qt/openuridialog.cpp2
-rw-r--r--src/qt/openuridialog.h2
-rw-r--r--src/qt/optionsdialog.cpp13
-rw-r--r--src/qt/optionsdialog.h2
-rw-r--r--src/qt/optionsmodel.cpp24
-rw-r--r--src/qt/optionsmodel.h1
-rw-r--r--src/qt/overviewpage.cpp42
-rw-r--r--src/qt/overviewpage.h2
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/paymentserver.h2
-rw-r--r--src/qt/peertablemodel.cpp33
-rw-r--r--src/qt/peertablemodel.h17
-rw-r--r--src/qt/psbtoperationsdialog.cpp2
-rw-r--r--src/qt/qrimagewidget.cpp2
-rw-r--r--src/qt/qrimagewidget.h2
-rw-r--r--src/qt/qvalidatedlineedit.h2
-rw-r--r--src/qt/receivecoinsdialog.cpp5
-rw-r--r--src/qt/receivecoinsdialog.h2
-rw-r--r--src/qt/receiverequestdialog.cpp4
-rw-r--r--src/qt/receiverequestdialog.h2
-rw-r--r--src/qt/recentrequeststablemodel.cpp12
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rwxr-xr-xsrc/qt/res/animation/makespinner.sh2
-rw-r--r--src/qt/rpcconsole.cpp56
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp5
-rw-r--r--src/qt/sendcoinsdialog.h4
-rw-r--r--src/qt/sendcoinsrecipient.h2
-rw-r--r--src/qt/signverifymessagedialog.cpp4
-rw-r--r--src/qt/signverifymessagedialog.h2
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/splashscreen.h2
-rw-r--r--src/qt/test/addressbooktests.h2
-rw-r--r--src/qt/test/rpcnestedtests.cpp12
-rw-r--r--src/qt/test/rpcnestedtests.h2
-rw-r--r--src/qt/test/test_main.cpp2
-rw-r--r--src/qt/test/util.cpp2
-rw-r--r--src/qt/test/util.h2
-rw-r--r--src/qt/test/wallettests.h2
-rw-r--r--src/qt/trafficgraphwidget.cpp2
-rw-r--r--src/qt/transactiondescdialog.cpp4
-rw-r--r--src/qt/transactionfilterproxy.h2
-rw-r--r--src/qt/transactionoverviewwidget.h41
-rw-r--r--src/qt/transactionrecord.cpp4
-rw-r--r--src/qt/transactionrecord.h2
-rw-r--r--src/qt/transactiontablemodel.cpp11
-rw-r--r--src/qt/transactiontablemodel.h2
-rw-r--r--src/qt/transactionview.cpp2
-rw-r--r--src/qt/transactionview.h2
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/walletcontroller.cpp2
-rw-r--r--src/qt/walletframe.cpp17
-rw-r--r--src/qt/walletframe.h2
-rw-r--r--src/qt/walletmodel.cpp8
-rw-r--r--src/rest.cpp2
-rw-r--r--src/rpc/blockchain.cpp94
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/client.cpp11
-rw-r--r--src/rpc/mining.cpp62
-rw-r--r--src/rpc/misc.cpp45
-rw-r--r--src/rpc/net.cpp123
-rw-r--r--src/rpc/protocol.h2
-rw-r--r--src/rpc/rawtransaction.cpp49
-rw-r--r--src/rpc/request.cpp2
-rw-r--r--src/rpc/request.h2
-rw-r--r--src/rpc/server.cpp31
-rw-r--r--src/rpc/server.h10
-rw-r--r--src/rpc/util.cpp34
-rw-r--r--src/rpc/util.h9
-rw-r--r--src/scheduler.cpp1
-rw-r--r--src/script/bitcoinconsensus.cpp7
-rw-r--r--src/script/descriptor.cpp4
-rw-r--r--src/script/interpreter.cpp4
-rw-r--r--src/script/interpreter.h2
-rw-r--r--src/script/keyorigin.h2
-rw-r--r--src/script/script.cpp2
-rw-r--r--src/script/script_error.h2
-rw-r--r--src/script/sigcache.cpp2
-rw-r--r--src/script/sigcache.h24
-rw-r--r--src/script/sign.cpp2
-rw-r--r--src/script/signingprovider.cpp10
-rw-r--r--src/script/standard.cpp11
-rw-r--r--src/script/standard.h6
-rw-r--r--src/shutdown.cpp2
-rw-r--r--src/shutdown.h2
-rw-r--r--src/streams.h2
-rw-r--r--src/support/lockedpool.cpp2
-rw-r--r--src/support/lockedpool.h2
-rw-r--r--src/sync.cpp3
-rw-r--r--src/sync.h17
-rw-r--r--src/test/amount_tests.cpp2
-rw-r--r--src/test/base58_tests.cpp2
-rw-r--r--src/test/blockencodings_tests.cpp2
-rw-r--r--src/test/blockfilter_tests.cpp2
-rw-r--r--src/test/checkqueue_tests.cpp63
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/crypto_tests.cpp90
-rw-r--r--src/test/denialofservice_tests.cpp26
-rw-r--r--src/test/flatfile_tests.cpp2
-rw-r--r--src/test/fs_tests.cpp17
-rw-r--r--src/test/fuzz/FuzzedDataProvider.h563
-rw-r--r--src/test/fuzz/addrman.cpp138
-rw-r--r--src/test/fuzz/autofile.cpp68
-rw-r--r--src/test/fuzz/banman.cpp84
-rw-r--r--src/test/fuzz/bech32.cpp2
-rw-r--r--src/test/fuzz/bloom_filter.cpp78
-rw-r--r--src/test/fuzz/buffered_file.cpp65
-rw-r--r--src/test/fuzz/coins_view.cpp345
-rw-r--r--src/test/fuzz/connman.cpp206
-rw-r--r--src/test/fuzz/crypto.cpp176
-rw-r--r--src/test/fuzz/crypto_chacha20.cpp47
-rw-r--r--src/test/fuzz/crypto_chacha20_poly1305_aead.cpp77
-rw-r--r--src/test/fuzz/data_stream.cpp25
-rw-r--r--src/test/fuzz/decode_tx.cpp2
-rw-r--r--src/test/fuzz/fuzz.h4
-rw-r--r--src/test/fuzz/kitchen_sink.cpp35
-rw-r--r--src/test/fuzz/load_external_block_file.cpp2
-rw-r--r--src/test/fuzz/merkleblock.cpp48
-rw-r--r--src/test/fuzz/muhash.cpp53
-rw-r--r--src/test/fuzz/net.cpp176
-rw-r--r--src/test/fuzz/net_permissions.cpp13
-rw-r--r--src/test/fuzz/node_eviction.cpp44
-rw-r--r--src/test/fuzz/p2p_transport_deserializer.cpp2
-rw-r--r--src/test/fuzz/parse_hd_keypath.cpp2
-rw-r--r--src/test/fuzz/parse_iso8601.cpp2
-rw-r--r--src/test/fuzz/parse_numbers.cpp2
-rw-r--r--src/test/fuzz/parse_script.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp74
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/pow.cpp5
-rw-r--r--src/test/fuzz/process_message.cpp36
-rw-r--r--src/test/fuzz/process_messages.cpp35
-rw-r--r--src/test/fuzz/rolling_bloom_filter.cpp46
-rw-r--r--src/test/fuzz/script.cpp22
-rw-r--r--src/test/fuzz/script_ops.cpp99
-rw-r--r--src/test/fuzz/scriptnum_ops.cpp192
-rw-r--r--src/test/fuzz/signet.cpp2
-rw-r--r--src/test/fuzz/spanparsing.cpp2
-rw-r--r--src/test/fuzz/strprintf.cpp121
-rw-r--r--src/test/fuzz/system.cpp118
-rw-r--r--src/test/fuzz/tx_in.cpp2
-rw-r--r--src/test/fuzz/tx_out.cpp2
-rw-r--r--src/test/fuzz/util.cpp25
-rw-r--r--src/test/fuzz/util.h248
-rw-r--r--src/test/merkle_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/net_tests.cpp17
-rw-r--r--src/test/netbase_tests.cpp21
-rw-r--r--src/test/pow_tests.cpp2
-rw-r--r--src/test/raii_event_tests.cpp2
-rw-r--r--src/test/sanity_tests.cpp2
-rw-r--r--src/test/scheduler_tests.cpp1
-rw-r--r--src/test/script_standard_tests.cpp40
-rw-r--r--src/test/streams_tests.cpp2
-rw-r--r--src/test/sync_tests.cpp6
-rw-r--r--src/test/system_tests.cpp2
-rw-r--r--src/test/transaction_tests.cpp11
-rw-r--r--src/test/util/logging.cpp2
-rw-r--r--src/test/util/logging.h2
-rw-r--r--src/test/util/mining.cpp2
-rw-r--r--src/test/util/net.h31
-rw-r--r--src/test/util/setup_common.cpp15
-rw-r--r--src/test/util/setup_common.h4
-rw-r--r--src/test/util_tests.cpp6
-rw-r--r--src/test/validation_chainstate_tests.cpp2
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp8
-rw-r--r--src/test/validation_tests.cpp4
-rw-r--r--src/threadsafety.h2
-rw-r--r--src/torcontrol.cpp5
-rw-r--r--src/torcontrol.h2
-rw-r--r--src/txmempool.cpp3
-rw-r--r--src/txmempool.h18
-rw-r--r--src/uint256.cpp2
-rw-r--r--src/uint256.h2
-rw-r--r--src/util/asmap.h2
-rw-r--r--src/util/check.h2
-rw-r--r--src/util/error.cpp2
-rw-r--r--src/util/error.h2
-rw-r--r--src/util/fees.cpp2
-rw-r--r--src/util/fees.h2
-rw-r--r--src/util/golombrice.h2
-rw-r--r--src/util/hasher.cpp19
-rw-r--r--src/util/hasher.h99
-rw-r--r--src/util/memory.h2
-rw-r--r--src/util/message.cpp2
-rw-r--r--src/util/strencodings.h2
-rw-r--r--src/util/system.cpp31
-rw-r--r--src/util/system.h12
-rw-r--r--src/util/trace.h45
-rw-r--r--src/util/translation.h2
-rw-r--r--src/validation.cpp66
-rw-r--r--src/validation.h15
-rw-r--r--src/version.h2
-rw-r--r--src/versionbitsinfo.cpp2
-rw-r--r--src/wallet/bdb.cpp17
-rw-r--r--src/wallet/bdb.h4
-rw-r--r--src/wallet/coinselection.cpp2
-rw-r--r--src/wallet/coinselection.h2
-rw-r--r--src/wallet/crypter.h2
-rw-r--r--src/wallet/feebumper.cpp4
-rw-r--r--src/wallet/fees.cpp4
-rw-r--r--src/wallet/init.cpp5
-rw-r--r--src/wallet/ismine.h22
-rw-r--r--src/wallet/load.cpp2
-rw-r--r--src/wallet/load.h2
-rw-r--r--src/wallet/rpcdump.cpp69
-rw-r--r--src/wallet/rpcwallet.cpp177
-rw-r--r--src/wallet/scriptpubkeyman.h2
-rw-r--r--src/wallet/sqlite.h2
-rw-r--r--src/wallet/test/coinselector_tests.cpp2
-rw-r--r--src/wallet/test/db_tests.cpp2
-rw-r--r--src/wallet/test/init_test_fixture.cpp6
-rw-r--r--src/wallet/test/init_test_fixture.h2
-rw-r--r--src/wallet/test/init_tests.cpp2
-rw-r--r--src/wallet/test/ismine_tests.cpp2
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp6
-rw-r--r--src/wallet/test/walletdb_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp21
-rw-r--r--src/wallet/wallet.h2
-rw-r--r--src/wallet/walletdb.cpp2
-rw-r--r--src/wallet/wallettool.cpp16
-rw-r--r--src/wallet/wallettool.h4
-rw-r--r--src/wallet/walletutil.cpp2
-rw-r--r--src/wallet/walletutil.h2
-rw-r--r--src/walletinitinterface.h2
-rw-r--r--src/warnings.cpp2
-rw-r--r--src/warnings.h2
-rw-r--r--src/zmq/zmqabstractnotifier.cpp2
-rw-r--r--src/zmq/zmqabstractnotifier.h2
-rw-r--r--src/zmq/zmqnotificationinterface.cpp2
-rw-r--r--src/zmq/zmqnotificationinterface.h2
-rw-r--r--src/zmq/zmqpublishnotifier.cpp40
-rw-r--r--src/zmq/zmqpublishnotifier.h2
-rw-r--r--src/zmq/zmqrpc.cpp6
-rw-r--r--test/README.md2
-rw-r--r--test/functional/README.md2
-rwxr-xr-xtest/functional/example_test.py2
-rwxr-xr-xtest/functional/feature_bip68_sequence.py2
-rwxr-xr-xtest/functional/feature_cltv.py9
-rwxr-xr-xtest/functional/feature_config_args.py6
-rwxr-xr-xtest/functional/feature_dbcrash.py2
-rwxr-xr-xtest/functional/feature_dersig.py9
-rwxr-xr-xtest/functional/feature_help.py2
-rwxr-xr-xtest/functional/feature_minchainwork.py2
-rwxr-xr-xtest/functional/feature_notifications.py2
-rwxr-xr-xtest/functional/feature_nulldummy.py2
-rwxr-xr-xtest/functional/feature_proxy.py2
-rwxr-xr-xtest/functional/feature_rbf.py2
-rwxr-xr-xtest/functional/feature_reindex.py2
-rwxr-xr-xtest/functional/feature_shutdown.py2
-rwxr-xr-xtest/functional/feature_versionbits_warning.py2
-rwxr-xr-xtest/functional/interface_zmq.py108
-rwxr-xr-xtest/functional/mempool_accept.py2
-rwxr-xr-xtest/functional/mempool_compatibility.py17
-rwxr-xr-xtest/functional/mempool_package_onemore.py2
-rwxr-xr-xtest/functional/mempool_packages.py2
-rwxr-xr-xtest/functional/mempool_resurrect.py63
-rwxr-xr-xtest/functional/mempool_spend_coinbase.py2
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py2
-rwxr-xr-xtest/functional/p2p_add_connections.py97
-rwxr-xr-xtest/functional/p2p_blockfilters.py2
-rwxr-xr-xtest/functional/p2p_blocksonly.py109
-rwxr-xr-xtest/functional/p2p_compactblocks.py2
-rwxr-xr-xtest/functional/p2p_disconnect_ban.py2
-rwxr-xr-xtest/functional/p2p_eviction.py2
-rwxr-xr-xtest/functional/p2p_feefilter.py2
-rwxr-xr-xtest/functional/p2p_fingerprint.py2
-rwxr-xr-xtest/functional/p2p_invalid_tx.py2
-rwxr-xr-xtest/functional/p2p_nobloomfilter_messages.py2
-rwxr-xr-xtest/functional/p2p_node_network_limited.py2
-rwxr-xr-xtest/functional/p2p_permissions.py50
-rwxr-xr-xtest/functional/p2p_segwit.py26
-rwxr-xr-xtest/functional/p2p_timeouts.py6
-rwxr-xr-xtest/functional/rpc_blockchain.py44
-rwxr-xr-xtest/functional/rpc_createmultisig.py2
-rwxr-xr-xtest/functional/rpc_deprecated.py35
-rwxr-xr-xtest/functional/rpc_getblockfilter.py2
-rwxr-xr-xtest/functional/rpc_getdescriptorinfo.py2
-rwxr-xr-xtest/functional/rpc_getpeerinfo_deprecation.py38
-rwxr-xr-xtest/functional/rpc_help.py66
-rwxr-xr-xtest/functional/rpc_invalid_address_message.py78
-rwxr-xr-xtest/functional/rpc_invalidateblock.py2
-rwxr-xr-xtest/functional/rpc_misc.py2
-rwxr-xr-xtest/functional/rpc_net.py2
-rwxr-xr-xtest/functional/rpc_preciousblock.py2
-rwxr-xr-xtest/functional/rpc_rawtransaction.py2
-rwxr-xr-xtest/functional/rpc_setban.py18
-rwxr-xr-xtest/functional/rpc_txoutproof.py2
-rwxr-xr-xtest/functional/rpc_users.py2
-rw-r--r--test/functional/test_framework/blocktools.py2
-rw-r--r--test/functional/test_framework/key.py2
-rwxr-xr-xtest/functional/test_framework/messages.py5
-rw-r--r--test/functional/test_framework/muhash.py14
-rw-r--r--test/functional/test_framework/netutil.py2
-rwxr-xr-xtest/functional/test_framework/p2p.py99
-rw-r--r--test/functional/test_framework/script.py2
-rwxr-xr-xtest/functional/test_framework/script_util.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py7
-rwxr-xr-xtest/functional/test_framework/test_node.py32
-rw-r--r--test/functional/test_framework/util.py22
-rw-r--r--test/functional/test_framework/wallet.py10
-rwxr-xr-xtest/functional/test_runner.py4
-rwxr-xr-xtest/functional/tool_wallet.py6
-rwxr-xr-xtest/functional/wallet_basic.py4
-rwxr-xr-xtest/functional/wallet_bumpfee.py3
-rwxr-xr-xtest/functional/wallet_create_tx.py2
-rwxr-xr-xtest/functional/wallet_descriptor.py2
-rwxr-xr-xtest/functional/wallet_disable.py2
-rwxr-xr-xtest/functional/wallet_encryption.py4
-rwxr-xr-xtest/functional/wallet_fallbackfee.py2
-rwxr-xr-xtest/functional/wallet_import_rescan.py2
-rwxr-xr-xtest/functional/wallet_importdescriptors.py2
-rwxr-xr-xtest/functional/wallet_importmulti.py2
-rwxr-xr-xtest/functional/wallet_importprunedfunds.py2
-rwxr-xr-xtest/functional/wallet_keypool.py2
-rwxr-xr-xtest/functional/wallet_keypool_topup.py2
-rwxr-xr-xtest/functional/wallet_listdescriptors.py67
-rwxr-xr-xtest/functional/wallet_listsinceblock.py2
-rwxr-xr-xtest/functional/wallet_listtransactions.py2
-rwxr-xr-xtest/functional/wallet_multiwallet.py4
-rwxr-xr-xtest/functional/wallet_reorgsrestore.py2
-rwxr-xr-xtest/functional/wallet_startup.py2
-rwxr-xr-xtest/functional/wallet_txn_clone.py2
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py2
-rwxr-xr-xtest/fuzz/test_runner.py42
-rwxr-xr-xtest/get_previous_releases.py1
-rwxr-xr-xtest/lint/check-doc.py2
-rwxr-xr-xtest/lint/check-rpc-mappings.py162
-rwxr-xr-xtest/lint/commit-script-check.sh2
-rwxr-xr-xtest/lint/git-subtree-check.sh2
-rwxr-xr-xtest/lint/lint-assertions.sh2
-rwxr-xr-xtest/lint/lint-git-commit-check.sh7
-rwxr-xr-xtest/lint/lint-include-guards.sh2
-rwxr-xr-xtest/lint/lint-includes.sh5
-rwxr-xr-xtest/lint/lint-python-utf8-encoding.sh2
-rwxr-xr-xtest/lint/lint-python.sh4
-rwxr-xr-xtest/lint/lint-shebang.sh2
-rwxr-xr-xtest/lint/lint-shell.sh8
-rw-r--r--test/lint/lint-spelling.ignore-words.txt24
-rwxr-xr-xtest/lint/lint-spelling.sh2
-rwxr-xr-xtest/lint/lint-whitespace.sh11
-rw-r--r--test/sanitizer_suppressions/tsan25
-rw-r--r--test/sanitizer_suppressions/ubsan68
582 files changed, 10850 insertions, 5264 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 0507d664f1..801164c368 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -70,16 +70,8 @@ task:
memory: 1G
# For faster CI feedback, immediately schedule the linters
<< : *CREDITS_TEMPLATE
- setup_script:
- - set -o errexit; source ./ci/test/00_setup_env.sh
- before_install_script:
- - set -o errexit; source ./ci/test/03_before_install.sh
- install_script:
- - set -o errexit; source ./ci/lint/04_install.sh
- before_script:
- - set -o errexit; source ./ci/lint/05_before_script.sh
lint_script:
- - set -o errexit; source ./ci/lint/06_script.sh
+ - ./ci/lint_run_all.sh
task:
name: 'ARM [unit tests, no functional tests] [buster]'
@@ -144,7 +136,7 @@ task:
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
task:
- name: '[no depends, sanitizers: fuzzer,address,undefined] [focal]'
+ name: '[no depends, sanitizers: fuzzer,address,undefined,integer] [focal]'
<< : *GLOBAL_TASK_TEMPLATE
container:
image: ubuntu:focal
@@ -178,7 +170,7 @@ task:
task:
name: 'macOS 10.15 native [gui] [no depends]'
macos_brew_addon_script:
- - brew install boost libevent berkeley-db4 qt miniupnpc ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt
+ - brew install boost libevent berkeley-db4 qt miniupnpc libnatpmp ccache zeromq qrencode sqlite libtool automake pkg-config gnu-getopt
<< : *GLOBAL_TASK_TEMPLATE
osx_instance:
# Use latest image, but hardcode version to avoid silent upgrades (and breaks)
diff --git a/.fuzzbuzz.yml b/.fuzzbuzz.yml
index 7615eb3420..be9a1cd4e1 100644
--- a/.fuzzbuzz.yml
+++ b/.fuzzbuzz.yml
@@ -5,7 +5,7 @@ environment:
- CXXFLAGS=-fcoverage-mapping -fno-omit-frame-pointer -fprofile-instr-generate -gline-tables-only -O1
setup:
- sudo apt-get update
- - sudo apt-get install -y autoconf bsdmainutils clang git libboost-all-dev libboost-program-options-dev libc++1 libc++abi1 libc++abi-dev libc++-dev libclang1 libclang-dev libdb5.3++ libevent-dev libllvm-ocaml-dev libomp5 libomp-dev libprotobuf-dev libqt5core5a libqt5dbus5 libqt5gui5 libssl-dev libtool llvm llvm-dev llvm-runtime pkg-config protobuf-compiler qttools5-dev qttools5-dev-tools software-properties-common
+ - sudo apt-get install -y autoconf bsdmainutils clang git libboost-all-dev libc++1 libc++abi1 libc++abi-dev libc++-dev libclang1 libclang-dev libdb5.3++ libevent-dev libllvm-ocaml-dev libomp5 libomp-dev libqt5core5a libqt5dbus5 libqt5gui5 libtool llvm llvm-dev llvm-runtime pkg-config qttools5-dev qttools5-dev-tools software-properties-common
- ./autogen.sh
- CC=clang CXX=clang++ ./configure --enable-fuzz --with-sanitizers=address,fuzzer,undefined --enable-danger-fuzz-link-all
- make
diff --git a/.gitignore b/.gitignore
index 810ef5db6b..010586ee5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ src/bitcoin-cli
src/bitcoin-gui
src/bitcoin-node
src/bitcoin-tx
+src/bitcoin-util
src/bitcoin-wallet
src/test/fuzz/*
!src/test/fuzz/*.*
diff --git a/COPYING b/COPYING
index 461bc73100..c34f575b8c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
The MIT License (MIT)
-Copyright (c) 2009-2020 The Bitcoin Core developers
-Copyright (c) 2009-2020 Bitcoin Developers
+Copyright (c) 2009-2021 The Bitcoin Core developers
+Copyright (c) 2009-2021 Bitcoin Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile.am b/Makefile.am
index 6573f91d97..f6b824faaa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,6 +12,7 @@ if ENABLE_MAN
SUBDIRS += doc/man
endif
.PHONY: deploy FORCE
+.INTERMEDIATE: $(OSX_TEMP_ISO) $(COVERAGE_INFO)
export PYTHONPATH
@@ -24,6 +25,7 @@ BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT)
BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT)
BITCOIN_CLI_BIN=$(top_builddir)/src/$(BITCOIN_CLI_NAME)$(EXEEXT)
BITCOIN_TX_BIN=$(top_builddir)/src/$(BITCOIN_TX_NAME)$(EXEEXT)
+BITCOIN_UTIL_BIN=$(top_builddir)/src/$(BITCOIN_UTIL_NAME)$(EXEEXT)
BITCOIN_WALLET_BIN=$(top_builddir)/src/$(BITCOIN_WALLET_TOOL_NAME)$(EXEEXT)
BITCOIN_NODE_BIN=$(top_builddir)/src/$(BITCOIN_MP_NODE_NAME)$(EXEEXT)
BITCOIN_GUI_BIN=$(top_builddir)/src/$(BITCOIN_MP_GUI_NAME)$(EXEEXT)
@@ -44,6 +46,9 @@ OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns
OSX_PLIST=$(top_builddir)/share/qt/Info.plist #not installed
DIST_CONTRIB = \
+ $(top_srcdir)/test/sanitizer_suppressions/lsan \
+ $(top_srcdir)/test/sanitizer_suppressions/tsan \
+ $(top_srcdir)/test/sanitizer_suppressions/ubsan \
$(top_srcdir)/contrib/linearize/linearize-data.py \
$(top_srcdir)/contrib/linearize/linearize-hashes.py
@@ -52,7 +57,8 @@ DIST_SHARE = \
$(top_srcdir)/share/rpcauth
BIN_CHECKS=$(top_srcdir)/contrib/devtools/symbol-check.py \
- $(top_srcdir)/contrib/devtools/security-check.py
+ $(top_srcdir)/contrib/devtools/security-check.py \
+ $(top_srcdir)/contrib/devtools/pixie.py
WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \
$(top_srcdir)/share/pixmaps/nsis-header.bmp \
@@ -79,6 +85,7 @@ $(BITCOIN_WIN_INSTALLER): all-recursive
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_CLI_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_TX_BIN) $(top_builddir)/release
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_WALLET_BIN) $(top_builddir)/release
+ STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $(BITCOIN_UTIL_BIN) $(top_builddir)/release
@test -f $(MAKENSIS) && echo 'OutFile "$@"' | cat $(top_builddir)/share/setup.nsi - | $(MAKENSIS) -V2 - || \
echo error: could not build $@
@echo built $@
@@ -136,9 +143,8 @@ $(APP_DIST_DIR)/Applications:
$(APP_DIST_EXTRAS): $(APP_DIST_DIR)/$(OSX_APP)/Contents/MacOS/Bitcoin-Qt
-.INTERMEDIATE: $(OSX_TEMP_ISO)
$(OSX_TEMP_ISO): $(APP_DIST_EXTRAS)
- $(XORRISOFS) -D -l -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -o $@ dist
+ $(XORRISOFS) -D -l -V "$(OSX_VOLNAME)" -no-pad -r -dir-mode 0755 -o $@ dist -- $(if $(SOURCE_DATE_EPOCH),-volume_date all_file_dates =$(SOURCE_DATE_EPOCH))
$(OSX_DMG): $(OSX_TEMP_ISO)
$(DMG) dmg "$<" "$@"
@@ -176,6 +182,9 @@ $(BITCOIN_CLI_BIN): FORCE
$(BITCOIN_TX_BIN): FORCE
$(MAKE) -C src $(@F)
+$(BITCOIN_UTIL_BIN): FORCE
+ $(MAKE) -C src $(@F)
+
$(BITCOIN_WALLET_BIN): FORCE
$(MAKE) -C src $(@F)
@@ -332,8 +341,6 @@ EXTRA_DIST += \
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
-.INTERMEDIATE: $(COVERAGE_INFO)
-
DISTCHECK_CONFIGURE_FLAGS = --enable-man
doc/doxygen/.stamp: doc/Doxyfile FORCE
diff --git a/README.md b/README.md
index 312e2d00ec..c73e25c429 100644
--- a/README.md
+++ b/README.md
@@ -56,7 +56,8 @@ There are also [regression and integration tests](/test), written
in Python, that are run automatically on the build server.
These tests can be run (if the [test dependencies](/test) are installed) with: `test/functional/test_runner.py`
-The Travis CI system makes sure that every pull request is built for Windows, Linux, and macOS, and that unit/sanity tests are run automatically.
+The CI (Continuous Integration) systems make sure that every pull request is built for Windows, Linux, and macOS,
+and that unit/sanity tests are run automatically.
### Manual Quality Assurance (QA) Testing
diff --git a/build-aux/m4/l_atomic.m4 b/build-aux/m4/l_atomic.m4
index 75c43f9a92..5201a8cc7c 100644
--- a/build-aux/m4/l_atomic.m4
+++ b/build-aux/m4/l_atomic.m4
@@ -14,6 +14,9 @@ m4_define([_CHECK_ATOMIC_testbody], [[
#include <cstdint>
int main() {
+ std::atomic<bool> lock{true};
+ std::atomic_exchange(&lock, false);
+
std::atomic<int64_t> a{};
int64_t v = 5;
diff --git a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
index 6a3c9f1dc1..490ce8b1ce 100644
--- a/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
+++ b/build_msvc/libbitcoin_qt/libbitcoin_qt.vcxproj
@@ -104,6 +104,7 @@
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiondesc.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiondescdialog.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionfilterproxy.cpp" />
+ <ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionoverviewwidget.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionrecord.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactiontablemodel.cpp" />
<ClCompile Include="$(GeneratedFilesOutDir)\moc\moc_transactionview.cpp" />
diff --git a/build_msvc/testconsensus/testconsensus.cpp b/build_msvc/testconsensus/testconsensus.cpp
index 5fdd97dc78..115c92792d 100644
--- a/build_msvc/testconsensus/testconsensus.cpp
+++ b/build_msvc/testconsensus/testconsensus.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/ci/lint/04_install.sh b/ci/lint/04_install.sh
index 43d33b3f3b..a0b579de1e 100755
--- a/ci/lint/04_install.sh
+++ b/ci/lint/04_install.sh
@@ -1,16 +1,17 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
-${CI_RETRY_EXE} apt update && apt install -y clang-format-9 python3-pip curl git
+${CI_RETRY_EXE} apt-get update
+${CI_RETRY_EXE} apt-get install -y clang-format-9 python3-pip curl git gawk jq
update-alternatives --install /usr/bin/clang-format clang-format $(which clang-format-9 ) 100
update-alternatives --install /usr/bin/clang-format-diff clang-format-diff $(which clang-format-diff-9) 100
-${CI_RETRY_EXE} pip3 install codespell==1.17.1
+${CI_RETRY_EXE} pip3 install codespell==2.0.0
${CI_RETRY_EXE} pip3 install flake8==3.8.3
${CI_RETRY_EXE} pip3 install yq
${CI_RETRY_EXE} pip3 install mypy==0.781
diff --git a/ci/lint/05_before_script.sh b/ci/lint/05_before_script.sh
deleted file mode 100755
index 8e5a177b01..0000000000
--- a/ci/lint/05_before_script.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C
-
-git fetch
diff --git a/ci/lint/06_script.sh b/ci/lint/06_script.sh
index ba582e7bf6..e38cfe8eef 100755
--- a/ci/lint/06_script.sh
+++ b/ci/lint/06_script.sh
@@ -1,18 +1,17 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
+GIT_HEAD=$(git rev-parse HEAD)
if [ -n "$CIRRUS_PR" ]; then
- # CIRRUS_PR will be present in a Cirrus environment. For builds triggered
- # by a pull request this is the name of the branch targeted by the pull request.
- # https://cirrus-ci.org/guide/writing-tasks/#environment-variables
- COMMIT_RANGE="$CIRRUS_BRANCH..HEAD"
+ COMMIT_RANGE="$CIRRUS_BASE_SHA..$GIT_HEAD"
test/lint/commit-script-check.sh $COMMIT_RANGE
fi
+export COMMIT_RANGE
# This only checks that the trees are pure subtrees, it is not doing a full
# check with -r to not have to fetch all the remotes.
@@ -22,7 +21,6 @@ test/lint/git-subtree-check.sh src/univalue
test/lint/git-subtree-check.sh src/leveldb
test/lint/git-subtree-check.sh src/crc32c
test/lint/check-doc.py
-test/lint/check-rpc-mappings.py .
test/lint/lint-all.sh
if [ "$CIRRUS_REPO_FULL_NAME" = "bitcoin/bitcoin" ] && [ -n "$CIRRUS_CRON" ]; then
@@ -30,3 +28,6 @@ if [ "$CIRRUS_REPO_FULL_NAME" = "bitcoin/bitcoin" ] && [ -n "$CIRRUS_CRON" ]; th
${CI_RETRY_EXE} gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $(<contrib/verify-commits/trusted-keys) &&
./contrib/verify-commits/verify-commits.py --clean-merge=2;
fi
+
+echo
+git log --no-merges --oneline $COMMIT_RANGE
diff --git a/ci/lint_run_all.sh b/ci/lint_run_all.sh
new file mode 100755
index 0000000000..7adfe71674
--- /dev/null
+++ b/ci/lint_run_all.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) 2019-2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+export LC_ALL=C.UTF-8
+
+set -o errexit; source ./ci/test/00_setup_env.sh
+set -o errexit; source ./ci/lint/04_install.sh
+set -o errexit; source ./ci/lint/06_script.sh
diff --git a/ci/test/00_setup_env_native_asan.sh b/ci/test/00_setup_env_native_asan.sh
index 191b8049b0..f682486088 100644
--- a/ci/test/00_setup_env_native_asan.sh
+++ b/ci/test/00_setup_env_native_asan.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_asan
-export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
+export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
export DOCKER_NAME_TAG=ubuntu:20.04
export NO_DEPENDS=1
export GOAL="install"
diff --git a/ci/test/00_setup_env_native_fuzz.sh b/ci/test/00_setup_env_native_fuzz.sh
index a32de4a6b5..b7157c608d 100644
--- a/ci/test/00_setup_env_native_fuzz.sh
+++ b/ci/test/00_setup_env_native_fuzz.sh
@@ -14,5 +14,5 @@ export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export RUN_FUZZ_TESTS=true
export GOAL="install"
-export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined CC=clang CXX=clang++ --with-boost-process"
+export BITCOIN_CONFIG="--enable-fuzz --with-sanitizers=fuzzer,address,undefined,integer CC=clang CXX=clang++ --with-boost-process"
export CCACHE_SIZE=200M
diff --git a/ci/test/00_setup_env_native_qt5.sh b/ci/test/00_setup_env_native_qt5.sh
index dc6b2aecb5..567145fe47 100644
--- a/ci/test/00_setup_env_native_qt5.sh
+++ b/ci/test/00_setup_env_native_qt5.sh
@@ -9,7 +9,7 @@ export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_qt5
export DOCKER_NAME_TAG=ubuntu:18.04 # Check that bionic gcc-7 can compile our c++17 and run our functional tests in python3, see doc/dependencies.md
export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libharfbuzz-dev"
-export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
+export DEP_OPTS="NO_QT=1 NO_UPNP=1 NO_NATPMP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
export TEST_RUNNER_EXTRA="--previous-releases --coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export RUN_SECURITY_TESTS="true"
export RUN_UNIT_TESTS_SEQUENTIAL="true"
diff --git a/ci/test/00_setup_env_native_valgrind.sh b/ci/test/00_setup_env_native_valgrind.sh
index bfaea13a25..f0c153158b 100644
--- a/ci/test/00_setup_env_native_valgrind.sh
+++ b/ci/test/00_setup_env_native_valgrind.sh
@@ -7,7 +7,7 @@
export LC_ALL=C.UTF-8
export CONTAINER_NAME=ci_native_valgrind
-export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libsqlite3-dev"
+export PACKAGES="valgrind clang llvm python3-zmq libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libsqlite3-dev"
export USE_VALGRIND=1
export NO_DEPENDS=1
export TEST_RUNNER_EXTRA="--exclude rpc_bind" # Excluded for now, see https://github.com/bitcoin/bitcoin/issues/17765#issuecomment-602068547
diff --git a/ci/test/03_before_install.sh b/ci/test/03_before_install.sh
deleted file mode 100755
index 80806aab75..0000000000
--- a/ci/test/03_before_install.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C.UTF-8
-
-BEGIN_FOLD () {
- echo ""
- CURRENT_FOLD_NAME=$1
- echo "travis_fold:start:${CURRENT_FOLD_NAME}"
-}
-
-END_FOLD () {
- RET=$?
- echo "travis_fold:end:${CURRENT_FOLD_NAME}"
- if [ $RET != 0 ]; then
- echo "${CURRENT_FOLD_NAME} failed with status code ${RET}"
- fi
-}
-
diff --git a/ci/test/05_before_script.sh b/ci/test/05_before_script.sh
index d7dd5d9dec..4644f28a4e 100755
--- a/ci/test/05_before_script.sh
+++ b/ci/test/05_before_script.sh
@@ -47,7 +47,5 @@ if [ -z "$NO_DEPENDS" ]; then
DOCKER_EXEC $SHELL_OPTS make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS
fi
if [ -n "$PREVIOUS_RELEASES_TO_DOWNLOAD" ]; then
- BEGIN_FOLD previous-versions
DOCKER_EXEC test/get_previous_releases.py -b -t "$PREVIOUS_RELEASES_DIR" "${PREVIOUS_RELEASES_TO_DOWNLOAD}"
- END_FOLD
fi
diff --git a/ci/test/06_script_a.sh b/ci/test/06_script_a.sh
index d99068cb10..7986f7665a 100755
--- a/ci/test/06_script_a.sh
+++ b/ci/test/06_script_a.sh
@@ -12,30 +12,22 @@ if [ -z "$NO_WERROR" ]; then
fi
DOCKER_EXEC "ccache --zero-stats --max-size=$CCACHE_SIZE"
-BEGIN_FOLD autogen
if [ -n "$CONFIG_SHELL" ]; then
DOCKER_EXEC "$CONFIG_SHELL" -c "./autogen.sh"
else
DOCKER_EXEC ./autogen.sh
fi
-END_FOLD
DOCKER_EXEC mkdir -p "${BASE_BUILD_DIR}"
export P_CI_DIR="${BASE_BUILD_DIR}"
-BEGIN_FOLD configure
DOCKER_EXEC "${BASE_ROOT_DIR}/configure" --cache-file=config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( (DOCKER_EXEC cat config.log) && false)
-END_FOLD
-BEGIN_FOLD distdir
DOCKER_EXEC make distdir VERSION=$HOST
-END_FOLD
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST"
-BEGIN_FOLD configure
DOCKER_EXEC ./configure --cache-file=../config.cache $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG || ( (DOCKER_EXEC cat config.log) && false)
-END_FOLD
set -o errtrace
trap 'DOCKER_EXEC "cat ${BASE_SCRATCH_DIR}/sanitizer-output/* 2> /dev/null"' ERR
@@ -48,12 +40,8 @@ if [[ ${USE_MEMORY_SANITIZER} == "true" ]]; then
DOCKER_EXEC 'grep -v HAVE_SYS_GETRANDOM src/config/bitcoin-config.h > src/config/bitcoin-config.h.tmp && mv src/config/bitcoin-config.h.tmp src/config/bitcoin-config.h'
fi
-BEGIN_FOLD build
DOCKER_EXEC make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && DOCKER_EXEC make $GOAL V=1 ; false )
-END_FOLD
-BEGIN_FOLD cache_stats
DOCKER_EXEC "ccache --version | head -n 1 && ccache --show-stats"
DOCKER_EXEC du -sh "${DEPENDS_DIR}"/*/
DOCKER_EXEC du -sh "${PREVIOUS_RELEASES_DIR}"
-END_FOLD
diff --git a/ci/test/06_script_b.sh b/ci/test/06_script_b.sh
index 7aea21f257..194b14beab 100755
--- a/ci/test/06_script_b.sh
+++ b/ci/test/06_script_b.sh
@@ -7,55 +7,39 @@
export LC_ALL=C.UTF-8
if [[ $HOST = *-mingw32 ]]; then
- BEGIN_FOLD wrap-wine
# Generate all binaries, so that they can be wrapped
DOCKER_EXEC make $MAKEJOBS -C src/secp256k1 VERBOSE=1
DOCKER_EXEC make $MAKEJOBS -C src/univalue VERBOSE=1
DOCKER_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-wine.sh"
- END_FOLD
fi
if [ -n "$QEMU_USER_CMD" ]; then
- BEGIN_FOLD wrap-qemu
# Generate all binaries, so that they can be wrapped
DOCKER_EXEC make $MAKEJOBS -C src/secp256k1 VERBOSE=1
DOCKER_EXEC make $MAKEJOBS -C src/univalue VERBOSE=1
DOCKER_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-qemu.sh"
- END_FOLD
fi
if [ -n "$USE_VALGRIND" ]; then
- BEGIN_FOLD wrap-valgrind
DOCKER_EXEC "${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh"
- END_FOLD
fi
if [ "$RUN_UNIT_TESTS" = "true" ]; then
- BEGIN_FOLD unit-tests
DOCKER_EXEC ${TEST_RUNNER_ENV} DIR_UNIT_TEST_DATA=${DIR_UNIT_TEST_DATA} LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib make $MAKEJOBS check VERBOSE=1
- END_FOLD
fi
if [ "$RUN_UNIT_TESTS_SEQUENTIAL" = "true" ]; then
- BEGIN_FOLD unit-tests-seq
DOCKER_EXEC ${TEST_RUNNER_ENV} DIR_UNIT_TEST_DATA=${DIR_UNIT_TEST_DATA} LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib "${BASE_BUILD_DIR}/bitcoin-*/src/test/test_bitcoin*" --catch_system_errors=no -l test_suite
- END_FOLD
fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
- BEGIN_FOLD functional-tests
DOCKER_EXEC LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib ${TEST_RUNNER_ENV} test/functional/test_runner.py --ci $MAKEJOBS --tmpdirprefix "${BASE_SCRATCH_DIR}/test_runner/" --ansi --combinedlogslen=4000 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA} --quiet --failfast
- END_FOLD
fi
if [ "$RUN_SECURITY_TESTS" = "true" ]; then
- BEGIN_FOLD security-tests
DOCKER_EXEC make test-security-check
- END_FOLD
fi
if [ "$RUN_FUZZ_TESTS" = "true" ]; then
- BEGIN_FOLD fuzz-tests
DOCKER_EXEC LD_LIBRARY_PATH=$DEPENDS_DIR/$HOST/lib test/fuzz/test_runner.py ${FUZZ_TESTS_CONFIG} $MAKEJOBS -l DEBUG ${DIR_FUZZ_IN}
- END_FOLD
fi
diff --git a/ci/test/wrap-qemu.sh b/ci/test/wrap-qemu.sh
index be7d7fcc1f..2cd7c8cec2 100755
--- a/ci/test/wrap-qemu.sh
+++ b/ci/test/wrap-qemu.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/ci/test_run_all.sh b/ci/test_run_all.sh
index a1d4bd1952..93b07aab1e 100755
--- a/ci/test_run_all.sh
+++ b/ci/test_run_all.sh
@@ -1,13 +1,12 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C.UTF-8
set -o errexit; source ./ci/test/00_setup_env.sh
-set -o errexit; source ./ci/test/03_before_install.sh
set -o errexit; source ./ci/test/04_install.sh
set -o errexit; source ./ci/test/05_before_script.sh
set -o errexit; source ./ci/test/06_script_a.sh
diff --git a/configure.ac b/configure.ac
index ef2f31e582..23a33b8c4f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ define(_CLIENT_VERSION_MINOR, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, false)
-define(_COPYRIGHT_YEAR, 2020)
+define(_COPYRIGHT_YEAR, 2021)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
AC_INIT([Bitcoin Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_BUILD)m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
@@ -23,6 +23,7 @@ BITCOIN_DAEMON_NAME=bitcoind
BITCOIN_GUI_NAME=bitcoin-qt
BITCOIN_CLI_NAME=bitcoin-cli
BITCOIN_TX_NAME=bitcoin-tx
+BITCOIN_UTIL_NAME=bitcoin-util
BITCOIN_WALLET_TOOL_NAME=bitcoin-wallet
dnl Multi Process
BITCOIN_MP_NODE_NAME=bitcoin-node
@@ -106,7 +107,6 @@ AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
AC_PATH_PROG(XGETTEXT,xgettext)
AC_PATH_PROG(HEXDUMP,hexdump)
-AC_PATH_TOOL(READELF, readelf)
AC_PATH_TOOL(CPPFILT, c++filt)
AC_PATH_TOOL(OBJCOPY, objcopy)
AC_PATH_PROG(DOXYGEN, doxygen)
@@ -132,6 +132,12 @@ AC_ARG_WITH([bdb],
[use_bdb=$withval],
[use_bdb=auto])
+AC_ARG_ENABLE([ebpf],
+ [AS_HELP_STRING([--enable-ebpf],
+ [enable eBPF tracing (default is yes if sys/sdt.h is found)])],
+ [use_ebpf=$enableval],
+ [use_ebpf=yes])
+
AC_ARG_WITH([miniupnpc],
[AS_HELP_STRING([--with-miniupnpc],
[enable UPNP (default is yes if libminiupnpc is found)])],
@@ -144,6 +150,18 @@ AC_ARG_ENABLE([upnp-default],
[use_upnp_default=$enableval],
[use_upnp_default=no])
+AC_ARG_WITH([natpmp],
+ [AS_HELP_STRING([--with-natpmp],
+ [enable NAT-PMP (default is yes if libnatpmp is found)])],
+ [use_natpmp=$withval],
+ [use_natpmp=auto])
+
+AC_ARG_ENABLE([natpmp-default],
+ [AS_HELP_STRING([--enable-natpmp-default],
+ [if NAT-PMP is enabled, turn it on at startup (default is no)])],
+ [use_natpmp_default=$enableval],
+ [use_natpmp_default=no])
+
AC_ARG_ENABLE(tests,
AS_HELP_STRING([--disable-tests],[do not compile tests (default is to compile)]),
[use_tests=$enableval],
@@ -424,6 +442,7 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wrange-loop-analysis],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wrange-loop-analysis"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wredundant-decls],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wredundant-decls"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wunused-variable],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-variable"],,[[$CXXFLAG_WERROR]])
+ AX_CHECK_COMPILE_FLAG([-Wunused-member-function],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wunused-member-function"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wdate-time],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wdate-time"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wconditional-uninitialized],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wconditional-uninitialized"],,[[$CXXFLAG_WERROR]])
AX_CHECK_COMPILE_FLAG([-Wsign-compare],[WARN_CXXFLAGS="$WARN_CXXFLAGS -Wsign-compare"],,[[$CXXFLAG_WERROR]])
@@ -559,7 +578,7 @@ CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
AC_ARG_WITH([utils],
[AS_HELP_STRING([--with-utils],
- [build bitcoin-cli bitcoin-tx bitcoin-wallet (default=yes)])],
+ [build bitcoin-cli bitcoin-tx bitcoin-util bitcoin-wallet (default=yes)])],
[build_bitcoin_utils=$withval],
[build_bitcoin_utils=yes])
@@ -581,6 +600,12 @@ AC_ARG_ENABLE([util-wallet],
[build_bitcoin_wallet=$enableval],
[build_bitcoin_wallet=$build_bitcoin_utils])
+AC_ARG_ENABLE([util-util],
+ [AS_HELP_STRING([--enable-util-util],
+ [build bitcoin-util])],
+ [build_bitcoin_util=$enableval],
+ [build_bitcoin_util=$build_bitcoin_utils])
+
AC_ARG_WITH([libs],
[AS_HELP_STRING([--with-libs],
[build libraries (default=yes)])],
@@ -753,6 +778,9 @@ if test x$use_lcov_branch != xno; then
AC_SUBST(LCOV_OPTS, "$LCOV_OPTS --rc lcov_branch_coverage=1")
fi
+dnl Check for __int128
+AC_CHECK_TYPES([__int128])
+
dnl Check for endianness
AC_C_BIGENDIAN
@@ -785,6 +813,11 @@ AX_GCC_FUNC_ATTRIBUTE([dllimport])
if test x$use_glibc_compat != xno; then
AX_CHECK_LINK_FLAG([[-Wl,--wrap=__divmoddi4]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=__divmoddi4"])
AX_CHECK_LINK_FLAG([[-Wl,--wrap=log2f]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--wrap=log2f"])
+ case $host in
+ powerpc64* | ppc64*)
+ AX_CHECK_LINK_FLAG([[-Wl,--no-tls-get-addr-optimize]], [COMPAT_LDFLAGS="$COMPAT_LDFLAGS -Wl,--no-tls-get-addr-optimize"])
+ ;;
+ esac
else
AC_SEARCH_LIBS([clock_gettime],[rt])
fi
@@ -1194,6 +1227,7 @@ if test "x$enable_fuzz" = "xyes"; then
build_bitcoin_utils=no
build_bitcoin_cli=no
build_bitcoin_tx=no
+ build_bitcoin_util=no
build_bitcoin_wallet=no
build_bitcoind=no
build_bitcoin_libs=no
@@ -1203,6 +1237,7 @@ if test "x$enable_fuzz" = "xyes"; then
enable_wallet=no
use_bench=no
use_upnp=no
+ use_natpmp=no
use_zmq=no
AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]])
@@ -1271,6 +1306,16 @@ if test x$enable_wallet != xno; then
fi
fi
+if test x$use_ebpf != xno; then
+ AC_CHECK_HEADER([sys/sdt.h], [have_sdt=yes], [have_sdt=no])
+else
+ have_sdt=no
+fi
+
+if test x$have_sdt = xyes; then
+ AC_DEFINE([ENABLE_TRACING], [1], [Define to 1 to enable eBPF user static defined tracepoints])
+fi
+
dnl Check for libminiupnpc (optional)
if test x$use_upnp != xno; then
AC_CHECK_HEADERS(
@@ -1300,6 +1345,13 @@ if test x$have_miniupnpc != xno; then
fi
fi
+dnl Check for libnatpmp (optional).
+if test "x$use_natpmp" != xno; then
+ AC_CHECK_HEADERS([natpmp.h],
+ [AC_CHECK_LIB([natpmp], [initnatpmp], [NATPMP_LIBS=-lnatpmp], [have_natpmp=no])],
+ [have_natpmp=no])
+fi
+
if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
use_boost=no
else
@@ -1410,7 +1462,7 @@ fi
dnl univalue check
need_bundled_univalue=yes
-if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononononono; then
+if test x$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononononono; then
need_bundled_univalue=no
else
if test x$system_univalue != xno; then
@@ -1493,6 +1545,10 @@ AC_MSG_CHECKING([whether to build bitcoin-wallet])
AM_CONDITIONAL([BUILD_BITCOIN_WALLET], [test x$build_bitcoin_wallet = xyes])
AC_MSG_RESULT($build_bitcoin_wallet)
+AC_MSG_CHECKING([whether to build bitcoin-util])
+AM_CONDITIONAL([BUILD_BITCOIN_UTIL], [test x$build_bitcoin_util = xyes])
+AC_MSG_RESULT($build_bitcoin_util)
+
AC_MSG_CHECKING([whether to build libraries])
AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes])
if test x$build_bitcoin_libs = xyes; then
@@ -1558,6 +1614,31 @@ else
fi
fi
+dnl Enable NAT-PMP support.
+AC_MSG_CHECKING([whether to build with support for NAT-PMP])
+if test "x$have_natpmp" = xno; then
+ if test "x$use_natpmp" = xyes; then
+ AC_MSG_ERROR([NAT-PMP requested but cannot be built. Use --without-natpmp])
+ fi
+ AC_MSG_RESULT([no])
+ use_natpmp=no
+else
+ if test "x$use_natpmp" != xno; then
+ AC_MSG_RESULT([yes])
+ AC_MSG_CHECKING([whether to build with NAT-PMP enabled by default])
+ use_natpmp=yes
+ natpmp_setting=0
+ if test "x$use_natpmp_default" != xno; then
+ use_natpmp_default=yes
+ natpmp_setting=1
+ fi
+ AC_MSG_RESULT($use_natpmp_default)
+ AC_DEFINE_UNQUOTED([USE_NATPMP], [$natpmp_setting], [NAT-PMP support not compiled if undefined, otherwise value (0 or 1) determines default state])
+ else
+ AC_MSG_RESULT([no])
+ fi
+fi
+
dnl these are only used when qt is enabled
BUILD_TEST_QT=""
if test x$bitcoin_enable_qt != xno; then
@@ -1629,6 +1710,7 @@ AM_CONDITIONAL([TARGET_WINDOWS], [test x$TARGET_OS = xwindows])
AM_CONDITIONAL([ENABLE_WALLET],[test x$enable_wallet = xyes])
AM_CONDITIONAL([USE_SQLITE], [test "x$use_sqlite" = "xyes"])
AM_CONDITIONAL([USE_BDB], [test "x$use_bdb" = "xyes"])
+AM_CONDITIONAL([ENABLE_TRACING],[test x$have_sdt = xyes])
AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes])
AM_CONDITIONAL([ENABLE_FUZZ],[test x$enable_fuzz = xyes])
AM_CONDITIONAL([ENABLE_FUZZ_LINK_ALL],[test x$enable_danger_fuzz_link_all = xyes])
@@ -1669,6 +1751,7 @@ AC_SUBST(BITCOIN_DAEMON_NAME)
AC_SUBST(BITCOIN_GUI_NAME)
AC_SUBST(BITCOIN_CLI_NAME)
AC_SUBST(BITCOIN_TX_NAME)
+AC_SUBST(BITCOIN_UTIL_NAME)
AC_SUBST(BITCOIN_WALLET_TOOL_NAME)
AC_SUBST(BITCOIN_MP_NODE_NAME)
AC_SUBST(BITCOIN_MP_GUI_NAME)
@@ -1704,6 +1787,7 @@ AC_SUBST(SQLITE_LIBS)
AC_SUBST(TESTDEFS)
AC_SUBST(MINIUPNPC_CPPFLAGS)
AC_SUBST(MINIUPNPC_LIBS)
+AC_SUBST(NATPMP_LIBS)
AC_SUBST(EVENT_LIBS)
AC_SUBST(EVENT_PTHREADS_LIBS)
AC_SUBST(ZMQ_LIBS)
@@ -1791,7 +1875,9 @@ else
fi
echo " with bench = $use_bench"
echo " with upnp = $use_upnp"
+echo " with natpmp = $use_natpmp"
echo " use asm = $use_asm"
+echo " ebpf tracing = $have_sdt"
echo " sanitizers = $use_sanitizers"
echo " debug enabled = $enable_debug"
echo " gprof enabled = $enable_gprof"
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index 581fe712e9..a18c5bccc5 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
Source: https://github.com/bitcoin/bitcoin
Files: *
-Copyright: 2009-2020, Bitcoin Core Developers
+Copyright: 2009-2021, Bitcoin Core Developers
License: Expat
Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org,
as well as the numerous contributors to the project.
diff --git a/contrib/devtools/circular-dependencies.py b/contrib/devtools/circular-dependencies.py
index bc5f09a3e2..b1d9f2b7db 100755
--- a/contrib/devtools/circular-dependencies.py
+++ b/contrib/devtools/circular-dependencies.py
@@ -1,10 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import sys
import re
+from typing import Dict, List, Set
MAPPING = {
'core_read.cpp': 'core_io.cpp',
@@ -32,7 +33,7 @@ def module_name(path):
return None
files = dict()
-deps = dict()
+deps: Dict[str, Set[str]] = dict()
RE = re.compile("^#include <(.*)>")
@@ -59,12 +60,12 @@ for arg in sorted(files.keys()):
deps[module].add(included_module)
# Loop to find the shortest (remaining) circular dependency
-have_cycle = False
+have_cycle: bool = False
while True:
shortest_cycle = None
for module in sorted(deps.keys()):
# Build the transitive closure of dependencies of module
- closure = dict()
+ closure: Dict[str, List[str]] = dict()
for dep in deps[module]:
closure[dep] = []
while True:
diff --git a/contrib/devtools/gen-manpages.sh b/contrib/devtools/gen-manpages.sh
index 3fdcda4fd4..b7bf76ce77 100755
--- a/contrib/devtools/gen-manpages.sh
+++ b/contrib/devtools/gen-manpages.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -14,13 +14,14 @@ BITCOIND=${BITCOIND:-$BINDIR/bitcoind}
BITCOINCLI=${BITCOINCLI:-$BINDIR/bitcoin-cli}
BITCOINTX=${BITCOINTX:-$BINDIR/bitcoin-tx}
WALLET_TOOL=${WALLET_TOOL:-$BINDIR/bitcoin-wallet}
+BITCOINUTIL=${BITCOINQT:-$BINDIR/bitcoin-util}
BITCOINQT=${BITCOINQT:-$BINDIR/qt/bitcoin-qt}
[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1
# Don't allow man pages to be generated for binaries built from a dirty tree
DIRTY=""
-for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINQT; do
+for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINUTIL $BITCOINQT; do
VERSION_OUTPUT=$($cmd --version)
if [[ $VERSION_OUTPUT == *"dirty"* ]]; then
DIRTY="${DIRTY}${cmd}\n"
@@ -43,7 +44,7 @@ read -r -a BTCVER <<< "$($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ prin
echo "[COPYRIGHT]" > footer.h2m
$BITCOIND --version | sed -n '1!p' >> footer.h2m
-for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINQT; do
+for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $WALLET_TOOL $BITCOINUTIL $BITCOINQT; do
cmdname="${cmd##*/}"
help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd}
sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1
diff --git a/contrib/devtools/pixie.py b/contrib/devtools/pixie.py
new file mode 100644
index 0000000000..8cf06a799a
--- /dev/null
+++ b/contrib/devtools/pixie.py
@@ -0,0 +1,323 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 Wladimir J. van der Laan
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+'''
+Compact, self-contained ELF implementation for bitcoin-core security checks.
+'''
+import struct
+import types
+from typing import Dict, List, Optional, Union, Tuple
+
+# you can find all these values in elf.h
+EI_NIDENT = 16
+
+# Byte indices in e_ident
+EI_CLASS = 4 # ELFCLASSxx
+EI_DATA = 5 # ELFDATAxxxx
+
+ELFCLASS32 = 1 # 32-bit
+ELFCLASS64 = 2 # 64-bit
+
+ELFDATA2LSB = 1 # little endian
+ELFDATA2MSB = 2 # big endian
+
+# relevant values for e_machine
+EM_386 = 3
+EM_PPC64 = 21
+EM_ARM = 40
+EM_AARCH64 = 183
+EM_X86_64 = 62
+EM_RISCV = 243
+
+# relevant values for e_type
+ET_DYN = 3
+
+# relevant values for sh_type
+SHT_PROGBITS = 1
+SHT_STRTAB = 3
+SHT_DYNAMIC = 6
+SHT_DYNSYM = 11
+SHT_GNU_verneed = 0x6ffffffe
+SHT_GNU_versym = 0x6fffffff
+
+# relevant values for p_type
+PT_LOAD = 1
+PT_GNU_STACK = 0x6474e551
+PT_GNU_RELRO = 0x6474e552
+
+# relevant values for p_flags
+PF_X = (1 << 0)
+PF_W = (1 << 1)
+PF_R = (1 << 2)
+
+# relevant values for d_tag
+DT_NEEDED = 1
+DT_FLAGS = 30
+
+# relevant values of `d_un.d_val' in the DT_FLAGS entry
+DF_BIND_NOW = 0x00000008
+
+# relevant d_tags with string payload
+STRING_TAGS = {DT_NEEDED}
+
+# rrlevant values for ST_BIND subfield of st_info (symbol binding)
+STB_LOCAL = 0
+
+class ELFRecord(types.SimpleNamespace):
+ '''Unified parsing for ELF records.'''
+ def __init__(self, data: bytes, offset: int, eh: 'ELFHeader', total_size: Optional[int]) -> None:
+ hdr_struct = self.STRUCT[eh.ei_class][0][eh.ei_data]
+ if total_size is not None and hdr_struct.size > total_size:
+ raise ValueError(f'{self.__class__.__name__} header size too small ({total_size} < {hdr_struct.size})')
+ for field, value in zip(self.STRUCT[eh.ei_class][1], hdr_struct.unpack(data[offset:offset + hdr_struct.size])):
+ setattr(self, field, value)
+
+def BiStruct(chars: str) -> Dict[int, struct.Struct]:
+ '''Compile a struct parser for both endians.'''
+ return {
+ ELFDATA2LSB: struct.Struct('<' + chars),
+ ELFDATA2MSB: struct.Struct('>' + chars),
+ }
+
+class ELFHeader(ELFRecord):
+ FIELDS = ['e_type', 'e_machine', 'e_version', 'e_entry', 'e_phoff', 'e_shoff', 'e_flags', 'e_ehsize', 'e_phentsize', 'e_phnum', 'e_shentsize', 'e_shnum', 'e_shstrndx']
+ STRUCT = {
+ ELFCLASS32: (BiStruct('HHIIIIIHHHHHH'), FIELDS),
+ ELFCLASS64: (BiStruct('HHIQQQIHHHHHH'), FIELDS),
+ }
+
+ def __init__(self, data: bytes, offset: int) -> None:
+ self.e_ident = data[offset:offset + EI_NIDENT]
+ if self.e_ident[0:4] != b'\x7fELF':
+ raise ValueError('invalid ELF magic')
+ self.ei_class = self.e_ident[EI_CLASS]
+ self.ei_data = self.e_ident[EI_DATA]
+
+ super().__init__(data, offset + EI_NIDENT, self, None)
+
+ def __repr__(self) -> str:
+ return f'Header(e_ident={self.e_ident!r}, e_type={self.e_type}, e_machine={self.e_machine}, e_version={self.e_version}, e_entry={self.e_entry}, e_phoff={self.e_phoff}, e_shoff={self.e_shoff}, e_flags={self.e_flags}, e_ehsize={self.e_ehsize}, e_phentsize={self.e_phentsize}, e_phnum={self.e_phnum}, e_shentsize={self.e_shentsize}, e_shnum={self.e_shnum}, e_shstrndx={self.e_shstrndx})'
+
+class Section(ELFRecord):
+ name: Optional[bytes] = None
+ FIELDS = ['sh_name', 'sh_type', 'sh_flags', 'sh_addr', 'sh_offset', 'sh_size', 'sh_link', 'sh_info', 'sh_addralign', 'sh_entsize']
+ STRUCT = {
+ ELFCLASS32: (BiStruct('IIIIIIIIII'), FIELDS),
+ ELFCLASS64: (BiStruct('IIQQQQIIQQ'), FIELDS),
+ }
+
+ def __init__(self, data: bytes, offset: int, eh: ELFHeader) -> None:
+ super().__init__(data, offset, eh, eh.e_shentsize)
+ self._data = data
+
+ def __repr__(self) -> str:
+ return f'Section(sh_name={self.sh_name}({self.name!r}), sh_type=0x{self.sh_type:x}, sh_flags={self.sh_flags}, sh_addr=0x{self.sh_addr:x}, sh_offset=0x{self.sh_offset:x}, sh_size={self.sh_size}, sh_link={self.sh_link}, sh_info={self.sh_info}, sh_addralign={self.sh_addralign}, sh_entsize={self.sh_entsize})'
+
+ def contents(self) -> bytes:
+ '''Return section contents.'''
+ return self._data[self.sh_offset:self.sh_offset + self.sh_size]
+
+class ProgramHeader(ELFRecord):
+ STRUCT = {
+ # different ELF classes have the same fields, but in a different order to optimize space versus alignment
+ ELFCLASS32: (BiStruct('IIIIIIII'), ['p_type', 'p_offset', 'p_vaddr', 'p_paddr', 'p_filesz', 'p_memsz', 'p_flags', 'p_align']),
+ ELFCLASS64: (BiStruct('IIQQQQQQ'), ['p_type', 'p_flags', 'p_offset', 'p_vaddr', 'p_paddr', 'p_filesz', 'p_memsz', 'p_align']),
+ }
+
+ def __init__(self, data: bytes, offset: int, eh: ELFHeader) -> None:
+ super().__init__(data, offset, eh, eh.e_phentsize)
+
+ def __repr__(self) -> str:
+ return f'ProgramHeader(p_type={self.p_type}, p_offset={self.p_offset}, p_vaddr={self.p_vaddr}, p_paddr={self.p_paddr}, p_filesz={self.p_filesz}, p_memsz={self.p_memsz}, p_flags={self.p_flags}, p_align={self.p_align})'
+
+class Symbol(ELFRecord):
+ STRUCT = {
+ # different ELF classes have the same fields, but in a different order to optimize space versus alignment
+ ELFCLASS32: (BiStruct('IIIBBH'), ['st_name', 'st_value', 'st_size', 'st_info', 'st_other', 'st_shndx']),
+ ELFCLASS64: (BiStruct('IBBHQQ'), ['st_name', 'st_info', 'st_other', 'st_shndx', 'st_value', 'st_size']),
+ }
+
+ def __init__(self, data: bytes, offset: int, eh: ELFHeader, symtab: Section, strings: bytes, version: Optional[bytes]) -> None:
+ super().__init__(data, offset, eh, symtab.sh_entsize)
+ self.name = _lookup_string(strings, self.st_name)
+ self.version = version
+
+ def __repr__(self) -> str:
+ return f'Symbol(st_name={self.st_name}({self.name!r}), st_value={self.st_value}, st_size={self.st_size}, st_info={self.st_info}, st_other={self.st_other}, st_shndx={self.st_shndx}, version={self.version!r})'
+
+ @property
+ def is_import(self) -> bool:
+ '''Returns whether the symbol is an imported symbol.'''
+ return self.st_bind != STB_LOCAL and self.st_shndx == 0
+
+ @property
+ def is_export(self) -> bool:
+ '''Returns whether the symbol is an exported symbol.'''
+ return self.st_bind != STB_LOCAL and self.st_shndx != 0
+
+ @property
+ def st_bind(self) -> int:
+ '''Returns STB_*.'''
+ return self.st_info >> 4
+
+class Verneed(ELFRecord):
+ DEF = (BiStruct('HHIII'), ['vn_version', 'vn_cnt', 'vn_file', 'vn_aux', 'vn_next'])
+ STRUCT = { ELFCLASS32: DEF, ELFCLASS64: DEF }
+
+ def __init__(self, data: bytes, offset: int, eh: ELFHeader) -> None:
+ super().__init__(data, offset, eh, None)
+
+ def __repr__(self) -> str:
+ return f'Verneed(vn_version={self.vn_version}, vn_cnt={self.vn_cnt}, vn_file={self.vn_file}, vn_aux={self.vn_aux}, vn_next={self.vn_next})'
+
+class Vernaux(ELFRecord):
+ DEF = (BiStruct('IHHII'), ['vna_hash', 'vna_flags', 'vna_other', 'vna_name', 'vna_next'])
+ STRUCT = { ELFCLASS32: DEF, ELFCLASS64: DEF }
+
+ def __init__(self, data: bytes, offset: int, eh: ELFHeader, strings: bytes) -> None:
+ super().__init__(data, offset, eh, None)
+ self.name = _lookup_string(strings, self.vna_name)
+
+ def __repr__(self) -> str:
+ return f'Veraux(vna_hash={self.vna_hash}, vna_flags={self.vna_flags}, vna_other={self.vna_other}, vna_name={self.vna_name}({self.name!r}), vna_next={self.vna_next})'
+
+class DynTag(ELFRecord):
+ STRUCT = {
+ ELFCLASS32: (BiStruct('II'), ['d_tag', 'd_val']),
+ ELFCLASS64: (BiStruct('QQ'), ['d_tag', 'd_val']),
+ }
+
+ def __init__(self, data: bytes, offset: int, eh: ELFHeader, section: Section) -> None:
+ super().__init__(data, offset, eh, section.sh_entsize)
+
+ def __repr__(self) -> str:
+ return f'DynTag(d_tag={self.d_tag}, d_val={self.d_val})'
+
+def _lookup_string(data: bytes, index: int) -> bytes:
+ '''Look up string by offset in ELF string table.'''
+ endx = data.find(b'\x00', index)
+ assert endx != -1
+ return data[index:endx]
+
+VERSYM_S = BiStruct('H') # .gnu_version section has a single 16-bit integer per symbol in the linked section
+def _parse_symbol_table(section: Section, strings: bytes, eh: ELFHeader, versym: bytes, verneed: Dict[int, bytes]) -> List[Symbol]:
+ '''Parse symbol table, return a list of symbols.'''
+ data = section.contents()
+ symbols = []
+ versym_iter = (verneed.get(v[0]) for v in VERSYM_S[eh.ei_data].iter_unpack(versym))
+ for ofs, version in zip(range(0, len(data), section.sh_entsize), versym_iter):
+ symbols.append(Symbol(data, ofs, eh, section, strings, version))
+ return symbols
+
+def _parse_verneed(section: Section, strings: bytes, eh: ELFHeader) -> Dict[int, bytes]:
+ '''Parse .gnu.version_r section, return a dictionary of {versym: 'GLIBC_...'}.'''
+ data = section.contents()
+ ofs = 0
+ result = {}
+ while True:
+ verneed = Verneed(data, ofs, eh)
+ aofs = verneed.vn_aux
+ while True:
+ vernaux = Vernaux(data, aofs, eh, strings)
+ result[vernaux.vna_other] = vernaux.name
+ if not vernaux.vna_next:
+ break
+ aofs += vernaux.vna_next
+
+ if not verneed.vn_next:
+ break
+ ofs += verneed.vn_next
+
+ return result
+
+def _parse_dyn_tags(section: Section, strings: bytes, eh: ELFHeader) -> List[Tuple[int, Union[bytes, int]]]:
+ '''Parse dynamic tags. Return array of tuples.'''
+ data = section.contents()
+ ofs = 0
+ result = []
+ for ofs in range(0, len(data), section.sh_entsize):
+ tag = DynTag(data, ofs, eh, section)
+ val = _lookup_string(strings, tag.d_val) if tag.d_tag in STRING_TAGS else tag.d_val
+ result.append((tag.d_tag, val))
+
+ return result
+
+class ELFFile:
+ sections: List[Section]
+ program_headers: List[ProgramHeader]
+ dyn_symbols: List[Symbol]
+ dyn_tags: List[Tuple[int, Union[bytes, int]]]
+
+ def __init__(self, data: bytes) -> None:
+ self.data = data
+ self.hdr = ELFHeader(self.data, 0)
+ self._load_sections()
+ self._load_program_headers()
+ self._load_dyn_symbols()
+ self._load_dyn_tags()
+ self._section_to_segment_mapping()
+
+ def _load_sections(self) -> None:
+ self.sections = []
+ for idx in range(self.hdr.e_shnum):
+ offset = self.hdr.e_shoff + idx * self.hdr.e_shentsize
+ self.sections.append(Section(self.data, offset, self.hdr))
+
+ shstr = self.sections[self.hdr.e_shstrndx].contents()
+ for section in self.sections:
+ section.name = _lookup_string(shstr, section.sh_name)
+
+ def _load_program_headers(self) -> None:
+ self.program_headers = []
+ for idx in range(self.hdr.e_phnum):
+ offset = self.hdr.e_phoff + idx * self.hdr.e_phentsize
+ self.program_headers.append(ProgramHeader(self.data, offset, self.hdr))
+
+ def _load_dyn_symbols(self) -> None:
+ # first, load 'verneed' section
+ verneed = None
+ for section in self.sections:
+ if section.sh_type == SHT_GNU_verneed:
+ strtab = self.sections[section.sh_link].contents() # associated string table
+ assert verneed is None # only one section of this kind please
+ verneed = _parse_verneed(section, strtab, self.hdr)
+ assert verneed is not None
+
+ # then, correlate GNU versym sections with dynamic symbol sections
+ versym = {}
+ for section in self.sections:
+ if section.sh_type == SHT_GNU_versym:
+ versym[section.sh_link] = section
+
+ # finally, load dynsym sections
+ self.dyn_symbols = []
+ for idx, section in enumerate(self.sections):
+ if section.sh_type == SHT_DYNSYM: # find dynamic symbol tables
+ strtab_data = self.sections[section.sh_link].contents() # associated string table
+ versym_data = versym[idx].contents() # associated symbol version table
+ self.dyn_symbols += _parse_symbol_table(section, strtab_data, self.hdr, versym_data, verneed)
+
+ def _load_dyn_tags(self) -> None:
+ self.dyn_tags = []
+ for idx, section in enumerate(self.sections):
+ if section.sh_type == SHT_DYNAMIC: # find dynamic tag tables
+ strtab = self.sections[section.sh_link].contents() # associated string table
+ self.dyn_tags += _parse_dyn_tags(section, strtab, self.hdr)
+
+ def _section_to_segment_mapping(self) -> None:
+ for ph in self.program_headers:
+ ph.sections = []
+ for section in self.sections:
+ if ph.p_vaddr <= section.sh_addr < (ph.p_vaddr + ph.p_memsz):
+ ph.sections.append(section)
+
+ def query_dyn_tags(self, tag_in: int) -> List[Union[int, bytes]]:
+ '''Return the values of all dyn tags with the specified tag.'''
+ return [val for (tag, val) in self.dyn_tags if tag == tag_in]
+
+
+def load(filename: str) -> ELFFile:
+ with open(filename, 'rb') as f:
+ data = f.read()
+ return ELFFile(data)
diff --git a/contrib/devtools/security-check.py b/contrib/devtools/security-check.py
index 02615edb54..7b09c42fde 100755
--- a/contrib/devtools/security-check.py
+++ b/contrib/devtools/security-check.py
@@ -6,15 +6,15 @@
Perform basic security checks on a series of executables.
Exit status will be 0 if successful, and the program will be silent.
Otherwise the exit status will be 1 and it will log which executables failed which checks.
-Needs `readelf` (for ELF), `objdump` (for PE) and `otool` (for MACHO).
+Needs `objdump` (for PE) and `otool` (for MACHO).
'''
import subprocess
import sys
import os
-
from typing import List, Optional
-READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
+import pixie
+
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool')
@@ -26,75 +26,20 @@ def check_ELF_PIE(executable) -> bool:
'''
Check for position independent executable (PIE), allowing for address space randomization.
'''
- stdout = run_command([READELF_CMD, '-h', '-W', executable])
-
- ok = False
- for line in stdout.splitlines():
- tokens = line.split()
- if len(line)>=2 and tokens[0] == 'Type:' and tokens[1] == 'DYN':
- ok = True
- return ok
-
-def get_ELF_program_headers(executable):
- '''Return type and flags for ELF program headers'''
- stdout = run_command([READELF_CMD, '-l', '-W', executable])
-
- in_headers = False
- headers = []
- for line in stdout.splitlines():
- if line.startswith('Program Headers:'):
- in_headers = True
- count = 0
- if line == '':
- in_headers = False
- if in_headers:
- if count == 1: # header line
- header = [x.strip() for x in line.split()]
- ofs_typ = header.index('Type')
- ofs_flags = header.index('Flg')
- # assert readelf output is what we expect
- if ofs_typ == -1 or ofs_flags == -1:
- raise ValueError('Cannot parse elfread -lW output')
- elif count > 1:
- splitline = [x.strip() for x in line.split()]
- typ = splitline[ofs_typ]
- if not typ.startswith('[R'): # skip [Requesting ...]
- splitline = [x.strip() for x in line.split()]
- flags = splitline[ofs_flags]
- # check for 'R', ' E'
- if splitline[ofs_flags + 1] == 'E':
- flags += ' E'
- headers.append((typ, flags, []))
- count += 1
-
- if line.startswith(' Section to Segment mapping:'):
- in_mapping = True
- count = 0
- if line == '':
- in_mapping = False
- if in_mapping:
- if count == 1: # header line
- ofs_segment = line.find('Segment')
- ofs_sections = line.find('Sections...')
- if ofs_segment == -1 or ofs_sections == -1:
- raise ValueError('Cannot parse elfread -lW output')
- elif count > 1:
- segment = int(line[ofs_segment:ofs_sections].strip())
- sections = line[ofs_sections:].strip().split()
- headers[segment][2].extend(sections)
- count += 1
- return headers
+ elf = pixie.load(executable)
+ return elf.hdr.e_type == pixie.ET_DYN
def check_ELF_NX(executable) -> bool:
'''
Check that no sections are writable and executable (including the stack)
'''
+ elf = pixie.load(executable)
have_wx = False
have_gnu_stack = False
- for (typ, flags, _) in get_ELF_program_headers(executable):
- if typ == 'GNU_STACK':
+ for ph in elf.program_headers:
+ if ph.p_type == pixie.PT_GNU_STACK:
have_gnu_stack = True
- if 'W' in flags and 'E' in flags: # section is both writable and executable
+ if (ph.p_flags & pixie.PF_W) != 0 and (ph.p_flags & pixie.PF_X) != 0: # section is both writable and executable
have_wx = True
return have_gnu_stack and not have_wx
@@ -104,35 +49,34 @@ def check_ELF_RELRO(executable) -> bool:
GNU_RELRO program header must exist
Dynamic section must have BIND_NOW flag
'''
+ elf = pixie.load(executable)
have_gnu_relro = False
- for (typ, flags, _) in get_ELF_program_headers(executable):
- # Note: not checking flags == 'R': here as linkers set the permission differently
+ for ph in elf.program_headers:
+ # Note: not checking p_flags == PF_R: here as linkers set the permission differently
# This does not affect security: the permission flags of the GNU_RELRO program
# header are ignored, the PT_LOAD header determines the effective permissions.
# However, the dynamic linker need to write to this area so these are RW.
# Glibc itself takes care of mprotecting this area R after relocations are finished.
# See also https://marc.info/?l=binutils&m=1498883354122353
- if typ == 'GNU_RELRO':
+ if ph.p_type == pixie.PT_GNU_RELRO:
have_gnu_relro = True
have_bindnow = False
- stdout = run_command([READELF_CMD, '-d', '-W', executable])
-
- for line in stdout.splitlines():
- tokens = line.split()
- if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2:]):
+ for flags in elf.query_dyn_tags(pixie.DT_FLAGS):
+ assert isinstance(flags, int)
+ if flags & pixie.DF_BIND_NOW:
have_bindnow = True
+
return have_gnu_relro and have_bindnow
def check_ELF_Canary(executable) -> bool:
'''
Check for use of stack canary
'''
- stdout = run_command([READELF_CMD, '--dyn-syms', '-W', executable])
-
+ elf = pixie.load(executable)
ok = False
- for line in stdout.splitlines():
- if '__stack_chk_fail' in line:
+ for symbol in elf.dyn_symbols:
+ if symbol.name == b'__stack_chk_fail':
ok = True
return ok
@@ -142,48 +86,55 @@ def check_ELF_separate_code(executable):
based on their permissions. This checks for missing -Wl,-z,separate-code
and potentially other problems.
'''
+ elf = pixie.load(executable)
+ R = pixie.PF_R
+ W = pixie.PF_W
+ E = pixie.PF_X
EXPECTED_FLAGS = {
# Read + execute
- '.init': 'R E',
- '.plt': 'R E',
- '.plt.got': 'R E',
- '.plt.sec': 'R E',
- '.text': 'R E',
- '.fini': 'R E',
+ b'.init': R | E,
+ b'.plt': R | E,
+ b'.plt.got': R | E,
+ b'.plt.sec': R | E,
+ b'.text': R | E,
+ b'.fini': R | E,
# Read-only data
- '.interp': 'R',
- '.note.gnu.property': 'R',
- '.note.gnu.build-id': 'R',
- '.note.ABI-tag': 'R',
- '.gnu.hash': 'R',
- '.dynsym': 'R',
- '.dynstr': 'R',
- '.gnu.version': 'R',
- '.gnu.version_r': 'R',
- '.rela.dyn': 'R',
- '.rela.plt': 'R',
- '.rodata': 'R',
- '.eh_frame_hdr': 'R',
- '.eh_frame': 'R',
- '.qtmetadata': 'R',
- '.gcc_except_table': 'R',
- '.stapsdt.base': 'R',
+ b'.interp': R,
+ b'.note.gnu.property': R,
+ b'.note.gnu.build-id': R,
+ b'.note.ABI-tag': R,
+ b'.gnu.hash': R,
+ b'.dynsym': R,
+ b'.dynstr': R,
+ b'.gnu.version': R,
+ b'.gnu.version_r': R,
+ b'.rela.dyn': R,
+ b'.rela.plt': R,
+ b'.rodata': R,
+ b'.eh_frame_hdr': R,
+ b'.eh_frame': R,
+ b'.qtmetadata': R,
+ b'.gcc_except_table': R,
+ b'.stapsdt.base': R,
# Writable data
- '.init_array': 'RW',
- '.fini_array': 'RW',
- '.dynamic': 'RW',
- '.got': 'RW',
- '.data': 'RW',
- '.bss': 'RW',
+ b'.init_array': R | W,
+ b'.fini_array': R | W,
+ b'.dynamic': R | W,
+ b'.got': R | W,
+ b'.data': R | W,
+ b'.bss': R | W,
}
+ if elf.hdr.e_machine == pixie.EM_PPC64:
+ # .plt is RW on ppc64 even with separate-code
+ EXPECTED_FLAGS[b'.plt'] = R | W
# For all LOAD program headers get mapping to the list of sections,
# and for each section, remember the flags of the associated program header.
flags_per_section = {}
- for (typ, flags, sections) in get_ELF_program_headers(executable):
- if typ == 'LOAD':
- for section in sections:
- assert(section not in flags_per_section)
- flags_per_section[section] = flags
+ for ph in elf.program_headers:
+ if ph.p_type == pixie.PT_LOAD:
+ for section in ph.sections:
+ assert(section.name not in flags_per_section)
+ flags_per_section[section.name] = ph.p_flags
# Spot-check ELF LOAD program header flags per section
# If these sections exist, check them against the expected R/W/E flags
for (section, flags) in flags_per_section.items():
@@ -236,7 +187,7 @@ def check_PE_NX(executable) -> bool:
def get_MACHO_executable_flags(executable) -> List[str]:
stdout = run_command([OTOOL_CMD, '-vh', executable])
- flags = []
+ flags: List[str] = []
for line in stdout.splitlines():
tokens = line.split()
# filter first two header lines
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index 6949cb7ced..b30ed62521 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -11,10 +11,11 @@ Example usage:
find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
'''
import subprocess
-import re
import sys
import os
-from typing import List, Optional, Tuple
+from typing import List, Optional
+
+import pixie
# Debian 8 (Jessie) EOL: 2020. https://wiki.debian.org/DebianReleases#Production_Releases
#
@@ -50,7 +51,6 @@ IGNORE_EXPORTS = {
'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr',
'environ', '_environ', '__environ',
}
-READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
OTOOL_CMD = os.getenv('OTOOL', '/usr/bin/otool')
@@ -68,6 +68,8 @@ ELF_ALLOWED_LIBRARIES = {
'ld-linux.so.2', # 32-bit dynamic linker
'ld-linux-aarch64.so.1', # 64-bit ARM dynamic linker
'ld-linux-armhf.so.3', # 32-bit ARM dynamic linker
+'ld64.so.1', # POWER64 ABIv1 dynamic linker
+'ld64.so.2', # POWER64 ABIv2 dynamic linker
'ld-linux-riscv64-lp64d.so.1', # 64-bit RISC-V dynamic linker
# bitcoin-qt only
'libxcb.so.1', # part of X11
@@ -76,11 +78,12 @@ ELF_ALLOWED_LIBRARIES = {
'libdl.so.2' # programming interface to dynamic linker
}
ARCH_MIN_GLIBC_VER = {
-'80386': (2,1),
-'X86-64': (2,2,5),
-'ARM': (2,4),
-'AArch64':(2,17),
-'RISC-V': (2,27)
+pixie.EM_386: (2,1),
+pixie.EM_X86_64: (2,2,5),
+pixie.EM_ARM: (2,4),
+pixie.EM_AARCH64:(2,17),
+pixie.EM_PPC64: (2,17),
+pixie.EM_RISCV: (2,27)
}
MACHO_ALLOWED_LIBRARIES = {
@@ -140,29 +143,6 @@ class CPPFilt(object):
self.proc.stdout.close()
self.proc.wait()
-def read_symbols(executable, imports=True) -> List[Tuple[str, str, str]]:
- '''
- Parse an ELF executable and return a list of (symbol,version, arch) tuples
- for dynamic, imported symbols.
- '''
- p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', '-h', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Could not read symbols for {}: {}'.format(executable, stderr.strip()))
- syms = []
- for line in stdout.splitlines():
- line = line.split()
- if 'Machine:' in line:
- arch = line[-1]
- if len(line)>7 and re.match('[0-9]+:$', line[0]):
- (sym, _, version) = line[7].partition('@')
- is_import = line[6] == 'UND'
- if version.startswith('@'):
- version = version[1:]
- if is_import == imports:
- syms.append((sym, version, arch))
- return syms
-
def check_version(max_versions, version, arch) -> bool:
if '_' in version:
(lib, _, ver) = version.rpartition('_')
@@ -174,46 +154,42 @@ def check_version(max_versions, version, arch) -> bool:
return False
return ver <= max_versions[lib] or lib == 'GLIBC' and ver <= ARCH_MIN_GLIBC_VER[arch]
-def elf_read_libraries(filename) -> List[str]:
- p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
- (stdout, stderr) = p.communicate()
- if p.returncode:
- raise IOError('Error opening file')
- libraries = []
- for line in stdout.splitlines():
- tokens = line.split()
- if len(tokens)>2 and tokens[1] == '(NEEDED)':
- match = re.match(r'^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
- if match:
- libraries.append(match.group(1))
- else:
- raise ValueError('Unparseable (NEEDED) specification')
- return libraries
-
def check_imported_symbols(filename) -> bool:
+ elf = pixie.load(filename)
cppfilt = CPPFilt()
- ok = True
- for sym, version, arch in read_symbols(filename, True):
- if version and not check_version(MAX_VERSIONS, version, arch):
+ ok: bool = True
+
+ for symbol in elf.dyn_symbols:
+ if not symbol.is_import:
+ continue
+ sym = symbol.name.decode()
+ version = symbol.version.decode() if symbol.version is not None else None
+ if version and not check_version(MAX_VERSIONS, version, elf.hdr.e_machine):
print('{}: symbol {} from unsupported version {}'.format(filename, cppfilt(sym), version))
ok = False
return ok
def check_exported_symbols(filename) -> bool:
+ elf = pixie.load(filename)
cppfilt = CPPFilt()
- ok = True
- for sym,version,arch in read_symbols(filename, False):
- if arch == 'RISC-V' or sym in IGNORE_EXPORTS:
+ ok: bool = True
+ for symbol in elf.dyn_symbols:
+ if not symbol.is_export:
+ continue
+ sym = symbol.name.decode()
+ if elf.hdr.e_machine == pixie.EM_RISCV or sym in IGNORE_EXPORTS:
continue
print('{}: export of symbol {} not allowed'.format(filename, cppfilt(sym)))
ok = False
return ok
def check_ELF_libraries(filename) -> bool:
- ok = True
- for library_name in elf_read_libraries(filename):
- if library_name not in ELF_ALLOWED_LIBRARIES:
- print('{}: NEEDED library {} is not allowed'.format(filename, library_name))
+ ok: bool = True
+ elf = pixie.load(filename)
+ for library_name in elf.query_dyn_tags(pixie.DT_NEEDED):
+ assert(isinstance(library_name, bytes))
+ if library_name.decode() not in ELF_ALLOWED_LIBRARIES:
+ print('{}: NEEDED library {} is not allowed'.format(filename, library_name.decode()))
ok = False
return ok
@@ -231,7 +207,7 @@ def macho_read_libraries(filename) -> List[str]:
return libraries
def check_MACHO_libraries(filename) -> bool:
- ok = True
+ ok: bool = True
for dylib in macho_read_libraries(filename):
if dylib not in MACHO_ALLOWED_LIBRARIES:
print('{} is not in ALLOWED_LIBRARIES!'.format(dylib))
@@ -251,7 +227,7 @@ def pe_read_libraries(filename) -> List[str]:
return libraries
def check_PE_libraries(filename) -> bool:
- ok = True
+ ok: bool = True
for dylib in pe_read_libraries(filename):
if dylib not in PE_ALLOWED_LIBRARIES:
print('{} is not in ALLOWED_LIBRARIES!'.format(dylib))
@@ -284,7 +260,7 @@ def identify_executable(executable) -> Optional[str]:
return None
if __name__ == '__main__':
- retval = 0
+ retval: int = 0
for filename in sys.argv[1:]:
try:
etype = identify_executable(filename)
@@ -293,7 +269,7 @@ if __name__ == '__main__':
retval = 1
continue
- failed = []
+ failed: List[str] = []
for (name, func) in CHECKS[etype]:
if not func(filename):
failed.append(name)
diff --git a/contrib/filter-lcov.py b/contrib/filter-lcov.py
index e005cb96da..db780ad53b 100755
--- a/contrib/filter-lcov.py
+++ b/contrib/filter-lcov.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py
index d498c9e2c8..06b15574a7 100755
--- a/contrib/gitian-build.py
+++ b/contrib/gitian-build.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,15 +13,16 @@ def setup():
programs = ['ruby', 'git', 'make', 'wget', 'curl']
if args.kvm:
programs += ['apt-cacher-ng', 'python-vm-builder', 'qemu-kvm', 'qemu-utils']
- elif args.docker and not os.path.isfile('/lib/systemd/system/docker.service'):
- dockers = ['docker.io', 'docker-ce']
- for i in dockers:
- return_code = subprocess.call(['sudo', 'apt-get', 'install', '-qq', i])
- if return_code == 0:
- break
- if return_code != 0:
- print('Cannot find any way to install Docker.', file=sys.stderr)
- sys.exit(1)
+ elif args.docker:
+ if not os.path.isfile('/lib/systemd/system/docker.service'):
+ dockers = ['docker.io', 'docker-ce']
+ for i in dockers:
+ return_code = subprocess.call(['sudo', 'apt-get', 'install', '-qq', i])
+ if return_code == 0:
+ break
+ if return_code != 0:
+ print('Cannot find any way to install Docker.', file=sys.stderr)
+ sys.exit(1)
else:
programs += ['apt-cacher-ng', 'lxc', 'debootstrap']
subprocess.check_call(['sudo', 'apt-get', 'install', '-qq'] + programs)
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index 0e2c5be0fa..a0ff87b531 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -27,6 +27,12 @@ packages:
# - aarch64-linux-gnu
- "binutils-aarch64-linux-gnu"
- "g++-8-aarch64-linux-gnu"
+# - powerpc64-linux-gnu
+- "binutils-powerpc64-linux-gnu"
+- "g++-8-powerpc64-linux-gnu"
+# - powerpc64le-linux-gnu
+- "binutils-powerpc64le-linux-gnu"
+- "g++-8-powerpc64le-linux-gnu"
# - riscv64-linux-gnu
- "binutils-riscv64-linux-gnu"
- "g++-8-riscv64-linux-gnu"
@@ -38,7 +44,7 @@ script: |
set -e -o pipefail
WRAP_DIR=$HOME/wrapped
- HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu"
+ HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu powerpc64-linux-gnu powerpc64le-linux-gnu riscv64-linux-gnu"
CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests"
FAKETIME_HOST_PROGS="gcc g++"
FAKETIME_PROGS="date ar ranlib nm"
@@ -64,7 +70,7 @@ script: |
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
- echo "\$REAL \$@" >> $WRAP_DIR/${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
}
@@ -78,7 +84,13 @@ script: |
echo "REAL=\`which -a ${i}-${prog}-8 | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
- echo "\$REAL \"\$@\"" >> $WRAP_DIR/${i}-${prog}
+ if [ "${i:0:11}" = "powerpc64le" ]; then
+ echo "exec \"\$REAL\" -mcpu=power8 -mtune=power9 \"\$@\"" >> $WRAP_DIR/${i}-${prog}
+ elif [ "${i:0:9}" = "powerpc64" ]; then
+ echo "exec \"\$REAL\" -mcpu=970 -mtune=power9 \"\$@\"" >> $WRAP_DIR/${i}-${prog}
+ else
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${i}-${prog}
+ fi
chmod +x ${WRAP_DIR}/${i}-${prog}
fi
done
@@ -118,7 +130,7 @@ script: |
# Extract the git archive into a dir for each host and build
for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
- if [ "${i}" = "riscv64-linux-gnu" ]; then
+ if [ "${i}" = "riscv64-linux-gnu" ] || [ "${i}" = "powerpc64-linux-gnu" ] || [ "${i}" = "powerpc64le-linux-gnu" ]; then
# Workaround for https://bugs.launchpad.net/ubuntu/+source/gcc-8-cross-ports/+bug/1853740
# TODO: remove this when no longer needed
HOST_LDFLAGS="${HOST_LDFLAGS_BASE} -Wl,-z,noexecstack"
diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml
index 2330ff7736..6fcb21f729 100644
--- a/contrib/gitian-descriptors/gitian-osx-signer.yml
+++ b/contrib/gitian-descriptors/gitian-osx-signer.yml
@@ -8,9 +8,13 @@ architectures:
packages:
- "faketime"
- "xorriso"
+- "python3-pip"
remotes:
- "url": "https://github.com/bitcoin-core/bitcoin-detached-sigs.git"
"dir": "signature"
+- "url": "https://github.com/achow101/signapple.git"
+ "dir": "signapple"
+ "commit": "c7e73aa27a7615ac9506559173f787e2906b25eb"
files:
- "bitcoin-osx-unsigned.tar.gz"
script: |
@@ -27,15 +31,23 @@ script: |
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog}
- echo "\$REAL \$@" >> $WRAP_DIR/${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
- UNSIGNED=bitcoin-osx-unsigned.tar.gz
+ # Install signapple
+ cd signapple
+ python3 -m pip install -U pip setuptools
+ python3 -m pip install .
+ export PATH="$HOME/.local/bin":$PATH
+ cd ..
+
+ UNSIGNED_TARBALL=bitcoin-osx-unsigned.tar.gz
+ UNSIGNED_APP=dist/Bitcoin-Qt.app
SIGNED=bitcoin-osx-signed.dmg
- tar -xf ${UNSIGNED}
+ tar -xf ${UNSIGNED_TARBALL}
OSX_VOLNAME="$(cat osx_volname)"
- ./detached-sig-apply.sh ${UNSIGNED} signature/osx
+ ./detached-sig-apply.sh ${UNSIGNED_APP} signature/osx/dist
${WRAP_DIR}/xorrisofs -D -l -V "${OSX_VOLNAME}" -no-pad -r -dir-mode 0755 -o uncompressed.dmg signed-app
${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED}
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 9a7dd13c9c..2a47e90e6e 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -63,7 +63,7 @@ script: |
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
- echo "\$REAL \$@" >> $WRAP_DIR/${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
}
@@ -75,7 +75,7 @@ script: |
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
- echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
done
done
@@ -138,8 +138,6 @@ script: |
cp contrib/macdeploy/detached-sig-apply.sh unsigned-app-${i}
cp contrib/macdeploy/detached-sig-create.sh unsigned-app-${i}
cp ${BASEPREFIX}/${i}/native/bin/dmg unsigned-app-${i}
- cp ${BASEPREFIX}/${i}/native/bin/${i}-codesign_allocate unsigned-app-${i}/codesign_allocate
- cp ${BASEPREFIX}/${i}/native/bin/${i}-pagestuff unsigned-app-${i}/pagestuff
mv dist unsigned-app-${i}
pushd unsigned-app-${i}
find . | sort | tar --mtime="$REFERENCE_DATETIME" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index fc79745e69..1edd8b2e81 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -55,7 +55,7 @@ script: |
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
- echo "\$REAL \$@" >> $WRAP_DIR/${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
}
@@ -67,7 +67,7 @@ script: |
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
- echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
done
done
@@ -81,7 +81,7 @@ script: |
echo "REAL=\`which -a ${i}-${prog}-posix | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo "export LD_PRELOAD='/usr/\$LIB/faketime/libfaketime.so.1'" >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
- echo "\$REAL \"\$@\"" >> $WRAP_DIR/${i}-${prog}
+ echo "exec \"\$REAL\" \"\$@\"" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
done
done
diff --git a/contrib/gitian-keys/keys.txt b/contrib/gitian-keys/keys.txt
index 0a2c1302c8..db28cd07a0 100644
--- a/contrib/gitian-keys/keys.txt
+++ b/contrib/gitian-keys/keys.txt
@@ -1,36 +1,51 @@
9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C Aaron Clauson (sipsorcery)
-617C90010B3BD370B0AC7D424BB42E31C79111B8 Akira Takizawa
-E944AE667CF960B1004BC32FCA662BE18B877A60 Andreas Schildbach
-152812300785C96444D3334D17565732E08E5E41 Andrew Chow
-912FD3228387123DC97E0E57D5566241A0295FA9 BtcDrak
+617C90010B3BD370B0AC7D424BB42E31C79111B8 Akira Takizawa (akx20000)
+E944AE667CF960B1004BC32FCA662BE18B877A60 Andreas Schildbach (aschildbach)
+152812300785C96444D3334D17565732E08E5E41 Andrew Chow (achow101)
+590B7292695AFFA5B672CBB2E13FC145CD3F4304 Antoine Poinsot (darosior)
+0AD83877C1F0CD1EE9BD660AD7CC770B81FD22A8 Ben Carman (benthecarman)
+912FD3228387123DC97E0E57D5566241A0295FA9 BtcDrak (btcdrak)
C519EBCF3B926298946783EFF6430754120EC2F4 Christian Decker (cdecker)
-F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur
-C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields
-BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random
-6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark
+18AE2F798E0D239755DA4FD24B79F986CBDF8736 Chun Kuan Le (ken2812221)
+101598DC823C1B5F9A6624ABA5E0907A0380E6C3 CoinForensics (CoinForensics)
+F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur (centaur)
+C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields (cfields)
+BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random (devrandom)
+6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark (droark)
+1C6621605EC50319C463D56C7F81D87985D61612 Emanuele Cisbani (cisba)
9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos)
-D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece
-01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen
+D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece (fivepiece)
+6F993B250557E7B016ADE5713BDCDA2D87A881D9 Fuzzbawls (Fuzzbawls)
+01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen (gavinandresen)
D1DBF2C4B96F2DEBF4C16654410108112E7EA81F Hennadii Stepanov (hebasto)
-D3CC177286005BB8FF673294C5242A1AB3936517 jl2012
-82921A4B88FD454B7EB8CE3C796C4109063D4EAF Jon Atack
-32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli
-4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon
+A2FD494D0021AA9B4FA58F759102B7AE654A4A5A Ilyas Ridhuan (IlyasRidhuan)
+D3F22A3A4C366C2DCB66D3722DA9C5A7FA81EA35 Jarol Rodriguez (jarolrod)
+7480909378D544EA6B6DCEB7535B12980BB8A4D3 Jeffri H Frontz (jhfrontz)
+D3CC177286005BB8FF673294C5242A1AB3936517 jl2012 (jl2012)
+82921A4B88FD454B7EB8CE3C796C4109063D4EAF Jon Atack (jonatack)
+32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC Jonas Schnelli (jonasschnelli)
+4B4E840451149DD7FB0D633477DFAB5C3108B9A8 Jorge Timon (jtimon)
C42AFF7C61B3E44A1454CD3557AF762DB3353322 Karl-Johan Alm (kallewoof)
-E463A93F5F3117EEDE6C7316BD02942421F4889F Luke Dashjr
-B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B Marco Falke
+30DE693AE0DE9E37B3E7EB6BBFF0F67810C1EED1 Lisa Neigut (niftynei)
+E463A93F5F3117EEDE6C7316BD02942421F4889F Luke Dashjr (luke-jr)
+B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B Marco Falke (marco)
07DF3E57A548CCFB7530709189BBB8663E2E65CE Matt Corallo (BlueMatt)
-CA03882CB1FC067B5D3ACFE4D300116E1C875A3D MeshCollider
-E777299FC265DD04793070EB944D35F9AC3DB76A Michael Ford
-9692B91BBF0E8D34DFD33B1882C5C009628ECF0C Michagogo
-77E72E69DA7EE0A148C06B21B34821D4944DE5F7 Nils Schneider
-D62A803E27E7F43486035ADBBCD04D8E9CCCAC2A Paul Rabahy
-37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04 Peter Todd
-D762373D24904A3E42F33B08B9A408E71DAAC974 Pieter Wuille (Location: Leuven, Belgium)
-133EAC179436F14A5CF1B794860FEB804E669320 Pieter Wuille
+CA03882CB1FC067B5D3ACFE4D300116E1C875A3D MeshCollider (meshcollider)
+E777299FC265DD04793070EB944D35F9AC3DB76A Michael Ford (fanquake)
+AD5764F4ADCE1B99BDFD179E12335A271D4D62EC Michael Tidwell (miketwenty1)
+9692B91BBF0E8D34DFD33B1882C5C009628ECF0C Michagogo (michagogo)
+C57E4B42223FDE851D4F69DD28DF2724F241D8EE midnightmagic (midnightmagic)
+F4FC70F07310028424EFC20A8E4256593F177720 Oliver Gugger (guggero, Oliver Gugger)
+D62A803E27E7F43486035ADBBCD04D8E9CCCAC2A Paul Rabahy (prab)
+37EC7D7B0A217CDB4B4E007E7FAB114267E4FA04 Peter Todd (petertodd)
+D762373D24904A3E42F33B08B9A408E71DAAC974 Pieter Wuille [Location: Leuven, Belgium] (sipa)
+133EAC179436F14A5CF1B794860FEB804E669320 Pieter Wuille (sipa)
+6A8F9C266528E25AEB1D7731C2371D91CB716EA7 Sebastian Falbesoner (theStack)
A8FC55F3B04BA3146F3492E79303B33A305224CB Sebastian Kung (TheCharlatan)
-ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost
+ED9BDF7AD6A55E232E84524257FF9BDBCC301009 Sjors Provoost (sjors)
+867345026B6763E8B07EE73AB6737117397F5C4F Stephan Oeste (Emzy)
9EDAFF80E080659604F4A76B2EBB056FD847F8A7 Stephan Oeste (Emzy)
-AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami
-79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko
-71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan
+6DEEF79B050C4072509B743F8C275BC595448867 Tomas Kanocz (KanoczTomas)
+AEC1884398647C47413C1C3FB1179EB7347DC10D Warren Togami (wtogami)
+79D00BAC68B56D422F945A8F8E3A8F3247DBCBBF Willy Ko (willyko)
+71A3B16735405025D447E8F274810B012346C9A6 Wladimir J. van der Laan (laanwj)
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index dffcf99607..5870deee39 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -40,25 +40,27 @@ Otherwise, follow the [Guix installation guide][guix/bin-install].
Guix allows us to achieve better binary security by using our CPU time to build
everything from scratch. However, it doesn't sacrifice user choice in pursuit of
-this: users can decide whether or not to bootstrap and to use substitutes.
+this: users can decide whether or not to bootstrap and to use substitutes
+(pre-built packages).
After installation, you may want to consider [adding substitute
-servers](#speeding-up-builds-with-substitute-servers) to speed up your build if
-that fits your security model (say, if you're just testing that this works).
-This is skippable if you're using the [Dockerfile][fanquake/guix-docker].
+servers](#speeding-up-builds-with-substitute-servers) from which to download
+pre-built packages to speed up your build if that fits your security model (say,
+if you're just testing that this works). Substitute servers are set up by
+default if you're using the [Dockerfile][fanquake/guix-docker].
-If you prefer not to use any substitutes, make sure to set
-`ADDITIONAL_GUIX_ENVIRONMENT_FLAGS` like the following snippet. The first build
-will take a while, but the resulting packages will be cached for future builds.
+If you prefer not to use any substitutes, make sure to supply `--no-substitutes`
+like in the following snippet. The first build will take a while, but the
+resulting packages will be cached for future builds.
```sh
-export ADDITIONAL_GUIX_ENVIRONMENT_FLAGS='--no-substitutes'
+export ADDITIONAL_GUIX_COMMON_FLAGS='--no-substitutes'
```
Likewise, to perform a bootstrapped build (takes even longer):
```sh
-export ADDITIONAL_GUIX_ENVIRONMENT_FLAGS='--bootstrap --no-substitutes'
+export ADDITIONAL_GUIX_COMMON_FLAGS='--no-substitutes' ADDITIONAL_GUIX_ENVIRONMENT_FLAGS='--bootstrap'
```
### Using a version of Guix with `guix time-machine` capabilities
@@ -82,17 +84,6 @@ export PATH="${HOME}/.config/guix/current/bin${PATH:+:}$PATH"
## Usage
-### As a Development Environment
-
-For a Bitcoin Core depends development environment, simply invoke
-
-```sh
-guix environment --manifest=contrib/guix/manifest.scm
-```
-
-And you'll land back in your shell with all the build dependencies required for
-a `depends` build injected into your environment.
-
### As a Tool for Deterministic Builds
From the top of a clean Bitcoin Core repository:
@@ -113,10 +104,9 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
* _**HOSTS**_
Override the space-separated list of platform triples for which to perform a
- bootstrappable build. _(defaults to "x86\_64-linux-gnu
- arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu")_
-
- > Windows and OS X platform triplet support are WIP.
+ bootstrappable build. _(defaults to "x86\_64-linux-gnu arm-linux-gnueabihf
+ aarch64-linux-gnu riscv64-linux-gnu x86_64-w64-mingw32
+ x86_64-apple-darwin18")_
* _**SOURCES_PATH**_
@@ -147,13 +137,29 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
string) is interpreted the same way as not setting `V` at all, and that `V=0`
has the same effect as `V=1`.
-* _**ADDITIONAL_GUIX_ENVIRONMENT_FLAGS**_
+* _**SUBSTITUTE_URLS**_
- Additional flags to be passed to `guix environment`. For a fully-bootstrapped
+ A whitespace-delimited list of URLs from which to download pre-built packages.
+ A URL is only used if its signing key is authorized (refer to the [substitute
+ servers section](#speeding-up-builds-with-substitute-servers) for more
+ details).
+
+* _**ADDITIONAL_GUIX_COMMON_FLAGS**_
+
+ Additional flags to be passed to all `guix` commands. For a fully-bootstrapped
build, set this to `--bootstrap --no-substitutes` (refer to the [security
model section](#choosing-your-security-model) for more details). Note that a
fully-bootstrapped build will take quite a long time on the first run.
+* _**ADDITIONAL_GUIX_TIMEMACHINE_FLAGS**_
+
+ Additional flags to be passed to `guix time-machine`.
+
+* _**ADDITIONAL_GUIX_ENVIRONMENT_FLAGS**_
+
+ Additional flags to be passed to the invocation of `guix environment` inside
+ `guix time-machine`.
+
## Tips and Tricks
### Speeding up builds with substitute servers
@@ -161,14 +167,15 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
_This whole section is automatically done in the convenience
[Dockerfiles][fanquake/guix-docker]_
-For those who are used to life in the fast _(and trustful)_ lane, you can use
-[substitute servers][guix/substitutes] to enable binary downloads of packages.
+For those who are used to life in the fast _(and trustful)_ lane, you can
+specify [substitute servers][guix/substitutes] from which to download pre-built
+packages.
> For those who only want to use substitutes from the official Guix build farm
> and have authorized the build farm's signing key during Guix's installation,
> you don't need to do anything.
-#### Authorize the signing keys
+#### Step 1: Authorize the signing keys
For the official Guix build farm at https://ci.guix.gnu.org, run as root:
@@ -182,7 +189,7 @@ For dongcarl's substitute server at https://guix.carldong.io, run as root:
wget -qO- 'https://guix.carldong.io/signing-key.pub' | guix archive --authorize
```
-#### Use the substitute servers
+#### Step 2: Specify the substitute servers
The official Guix build farm at https://ci.guix.gnu.org is automatically used
unless the `--no-substitutes` flag is supplied.
@@ -196,7 +203,7 @@ To use dongcarl's substitute server for Bitcoin Core builds after having
[authorized his signing key](#authorize-the-signing-keys):
```
-export ADDITIONAL_GUIX_ENVIRONMENT_FLAGS='--substitute-urls="https://guix.carldong.io https://ci.guix.gnu.org"'
+export SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org'
```
## FAQ
@@ -212,9 +219,9 @@ As mentioned at the bottom of [this manual page][guix/bin-install]:
### When will Guix be packaged in debian?
-Vagrant Cascadian has been making good progress on this
-[here][debian/guix-package]. We have all the pieces needed to put up an APT
-repository and will likely put one up soon.
+Thanks to Vagrant Cascadian's diligent work, Guix is now [in debian
+experimental][debian/guix-experimental]! Hopefully it will make its way into a
+release soon.
[b17e]: http://bootstrappable.org/
[r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/
@@ -226,5 +233,5 @@ repository and will likely put one up soon.
[guix/substitute-server-auth]: https://www.gnu.org/software/guix/manual/en/html_node/Substitute-Server-Authorization.html
[guix/time-machine]: https://guix.gnu.org/manual/en/html_node/Invoking-guix-time_002dmachine.html
-[debian/guix-package]: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850644
+[debian/guix-experimental]: https://packages.debian.org/experimental/guix
[fanquake/guix-docker]: https://github.com/fanquake/core-review/tree/master/guix
diff --git a/contrib/guix/guix-build.sh b/contrib/guix/guix-build.sh
index 11d2c8b867..da6bd13f6a 100755
--- a/contrib/guix/guix-build.sh
+++ b/contrib/guix/guix-build.sh
@@ -2,6 +2,136 @@
export LC_ALL=C
set -e -o pipefail
+###################
+## Sanity Checks ##
+###################
+
+################
+# Check 1: Make sure that we can invoke required tools
+################
+for cmd in git make guix cat mkdir; do
+ if ! command -v "$cmd" > /dev/null 2>&1; then
+ echo "ERR: This script requires that '$cmd' is installed and available in your \$PATH"
+ exit 1
+ fi
+done
+
+################
+# Check 2: Make sure GUIX_BUILD_OPTIONS is empty
+################
+#
+# GUIX_BUILD_OPTIONS is an environment variable recognized by guix commands that
+# can perform builds. This seems like what we want instead of
+# ADDITIONAL_GUIX_COMMON_FLAGS, but the value of GUIX_BUILD_OPTIONS is actually
+# _appended_ to normal command-line options. Meaning that they will take
+# precedence over the command-specific ADDITIONAL_GUIX_<CMD>_FLAGS.
+#
+# This seems like a poor user experience. Thus we check for GUIX_BUILD_OPTIONS's
+# existence here and direct users of this script to use our (more flexible)
+# custom environment variables.
+if [ -n "$GUIX_BUILD_OPTIONS" ]; then
+cat << EOF
+Error: Environment variable GUIX_BUILD_OPTIONS is not empty:
+ '$GUIX_BUILD_OPTIONS'
+
+Unfortunately this script is incompatible with GUIX_BUILD_OPTIONS, please unset
+GUIX_BUILD_OPTIONS and use ADDITIONAL_GUIX_COMMON_FLAGS to set build options
+across guix commands or ADDITIONAL_GUIX_<CMD>_FLAGS to set build options for a
+specific guix command.
+
+See contrib/guix/README.md for more details.
+EOF
+exit 1
+fi
+
+################
+# Check 3: Make sure that we're not in a dirty worktree
+################
+if ! git diff-index --quiet HEAD -- && [ -z "$FORCE_DIRTY_WORKTREE" ]; then
+cat << EOF
+ERR: The current git worktree is dirty, which may lead to broken builds.
+
+ Aborting...
+
+Hint: To make your git worktree clean, You may want to:
+ 1. Commit your changes,
+ 2. Stash your changes, or
+ 3. Set the 'FORCE_DIRTY_WORKTREE' environment variable if you insist on
+ using a dirty worktree
+EOF
+exit 1
+else
+ GIT_COMMIT=$(git rev-parse --short=12 HEAD)
+fi
+
+################
+# Check 4: Make sure that build directories do not exist
+################
+
+# Default to building for all supported HOSTs (overridable by environment)
+export HOSTS="${HOSTS:-x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu
+ x86_64-w64-mingw32
+ x86_64-apple-darwin18}"
+
+DISTSRC_BASE="${DISTSRC_BASE:-${PWD}}"
+
+# Usage: distsrc_for_host HOST
+#
+# HOST: The current platform triple we're building for
+#
+distsrc_for_host() {
+ echo "${DISTSRC_BASE}/distsrc-${GIT_COMMIT}-${1}"
+}
+
+# Accumulate a list of build directories that already exist...
+hosts_distsrc_exists=""
+for host in $HOSTS; do
+ if [ -e "$(distsrc_for_host "$host")" ]; then
+ hosts_distsrc_exists+=" ${host}"
+ fi
+done
+
+if [ -n "$hosts_distsrc_exists" ]; then
+# ...so that we can print them out nicely in an error message
+cat << EOF
+ERR: Build directories for this commit already exist for the following platform
+ triples you're attempting to build, probably because of previous builds.
+ Please remove, or otherwise deal with them prior to starting another build.
+
+ Aborting...
+
+EOF
+for host in $hosts_distsrc_exists; do
+ echo " ${host} '$(distsrc_for_host "$host")'"
+done
+exit 1
+else
+
+ mkdir -p "$DISTSRC_BASE"
+fi
+
+################
+# Check 5: When building for darwin, make sure that the macOS SDK exists
+################
+
+for host in $HOSTS; do
+ case "$host" in
+ *darwin*)
+ OSX_SDK="$(make -C "${PWD}/depends" --no-print-directory HOST="$host" print-OSX_SDK | sed 's@^[^=]\+=[[:space:]]\+@@g')"
+ if [ -e "$OSX_SDK" ]; then
+ echo "Found macOS SDK at '${OSX_SDK}', using..."
+ else
+ echo "macOS SDK does not exist at '${OSX_SDK}', please place the extracted, untarred SDK there to perform darwin builds, exiting..."
+ exit 1
+ fi
+ ;;
+ esac
+done
+
+#########
+# Setup #
+#########
+
# Determine the maximum number of jobs to run simultaneously (overridable by
# environment)
MAX_JOBS="${MAX_JOBS:-$(nproc)}"
@@ -16,11 +146,23 @@ SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log --format=%at -1)}"
# Execute "$@" in a pinned, possibly older version of Guix, for reproducibility
# across time.
time-machine() {
+ # shellcheck disable=SC2086
guix time-machine --url=https://github.com/dongcarl/guix.git \
--commit=b066c25026f21fb57677aa34692a5034338e7ee3 \
+ --max-jobs="$MAX_JOBS" \
+ ${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
+ ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_TIMEMACHINE_FLAGS} \
-- "$@"
}
+# Make sure an output directory exists for our builds
+OUTDIR="${OUTDIR:-${PWD}/output}"
+[ -e "$OUTDIR" ] || mkdir -p "$OUTDIR"
+
+#########
+# Build #
+#########
+
# Function to be called when building for host ${1} and the user interrupts the
# build
int_trap() {
@@ -38,9 +180,9 @@ and untracked files and directories will be wiped, allowing you to start anew.
EOF
}
-# Deterministically build Bitcoin Core for HOSTs (overridable by environment)
+# Deterministically build Bitcoin Core
# shellcheck disable=SC2153
-for host in ${HOSTS=x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu x86_64-w64-mingw32}; do
+for host in $HOSTS; do
# Display proper warning when the user interrupts the build
trap 'int_trap ${host}' INT
@@ -50,6 +192,19 @@ for host in ${HOSTS=x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv
# for the particular $HOST we're building for
export HOST="$host"
+ # shellcheck disable=SC2030
+cat << EOF
+INFO: Building commit ${GIT_COMMIT:?not set} for platform triple ${HOST:?not set}:
+ ...using reference timestamp: ${SOURCE_DATE_EPOCH:?not set}
+ ...running at most ${MAX_JOBS:?not set} jobs
+ ...from worktree directory: '${PWD}'
+ ...bind-mounted in container to: '/bitcoin'
+ ...in build directory: '$(distsrc_for_host "$HOST")'
+ ...bind-mounted in container to: '$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")'
+ ...outputting in: '${OUTDIR:?not set}'
+ ...bind-mounted in container to: '/outdir'
+EOF
+
# Run the build script 'contrib/guix/libexec/build.sh' in the build
# container specified by 'contrib/guix/manifest.scm'.
#
@@ -99,20 +254,36 @@ for host in ${HOSTS=x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv
# make the downloaded depends sources available to it. The sources
# should have been downloaded prior to this invocation.
#
- # shellcheck disable=SC2086
+ # ${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"}
+ #
+ # fetch substitute from SUBSTITUTE_URLS if they are
+ # authorized
+ #
+ # Depending on the user's security model, it may be desirable to use
+ # substitutes (pre-built packages) from servers that the user trusts.
+ # Please read the README.md in the same directory as this file for
+ # more information.
+ #
+ # shellcheck disable=SC2086,SC2031
time-machine environment --manifest="${PWD}/contrib/guix/manifest.scm" \
--container \
--pure \
--no-cwd \
--share="$PWD"=/bitcoin \
+ --share="$DISTSRC_BASE"=/distsrc-base \
+ --share="$OUTDIR"=/outdir \
--expose="$(git rev-parse --git-common-dir)" \
${SOURCES_PATH:+--share="$SOURCES_PATH"} \
- ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
+ --max-jobs="$MAX_JOBS" \
+ ${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
+ ${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
-- env HOST="$host" \
MAX_JOBS="$MAX_JOBS" \
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:?unable to determine value}" \
${V:+V=1} \
${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"} \
+ DISTSRC="$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")" \
+ OUTDIR=/outdir \
bash -c "cd /bitcoin && bash contrib/guix/libexec/build.sh"
)
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index d658c4f6a6..39d3cb9b50 100644
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -11,9 +11,15 @@ if [ -n "$V" ]; then
export VERBOSE="$V"
fi
-# Check that environment variables assumed to be set by the environment are set
-echo "Building for platform triple ${HOST:?not set} with reference timestamp ${SOURCE_DATE_EPOCH:?not set}..."
-echo "At most ${MAX_JOBS:?not set} jobs will run at once..."
+# Check that required environment variables are set
+cat << EOF
+Required environment variables as seen inside the container:
+ HOST: ${HOST:?not set}
+ SOURCE_DATE_EPOCH: ${SOURCE_DATE_EPOCH:?not set}
+ MAX_JOBS: ${MAX_JOBS:?not set}
+ DISTSRC: ${DISTSRC:?not set}
+ OUTDIR: ${OUTDIR:?not set}
+EOF
#####################
# Environment Setup #
@@ -23,19 +29,6 @@ echo "At most ${MAX_JOBS:?not set} jobs will run at once..."
# $HOSTs after successfully building.
BASEPREFIX="${PWD}/depends"
-# Setup an output directory for our build
-OUTDIR="${OUTDIR:-${PWD}/output}"
-[ -e "$OUTDIR" ] || mkdir -p "$OUTDIR"
-
-# Setup the directory where our Bitcoin Core build for HOST will occur
-DISTSRC="${DISTSRC:-${PWD}/distsrc-${HOST}}"
-if [ -e "$DISTSRC" ]; then
- echo "DISTSRC directory '${DISTSRC}' exists, probably because of previous builds... Aborting..."
- exit 1
-else
- mkdir -p "$DISTSRC"
-fi
-
# Given a package name and an output name, return the path of that output in our
# current guix environment
store_path() {
@@ -45,7 +38,28 @@ store_path() {
--expression='s|"[[:space:]]*$||'
}
-# Set environment variables to point Guix's cross-toolchain to the right
+
+# Set environment variables to point the NATIVE toolchain to the right
+# includes/libs
+NATIVE_GCC="$(store_path gcc-toolchain)"
+export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64"
+export CPATH="${NATIVE_GCC}/include"
+case "$HOST" in
+ *darwin*)
+ # When targeting darwin, some native tools built by depends require
+ # native packages not incorporated in depends
+ #
+ # libcap required by native_cdrkit/wodim
+ # zlib, bzip2 required by native_cdrkit/genisoimage
+ for native_pkg in libcap zlib bzip2; do
+ native_pkg_store_path=$(store_path "$native_pkg")
+ export LIBRARY_PATH="${native_pkg_store_path}/lib:${LIBRARY_PATH}"
+ export CPATH="${native_pkg_store_path}/include:${CPATH}"
+ done
+ ;;
+esac
+
+# Set environment variables to point the CROSS toolchain to the right
# includes/libs for $HOST
case "$HOST" in
*mingw*)
@@ -55,14 +69,18 @@ case "$HOST" in
CROSS_GCC_LIBS=( "${CROSS_GCC}/lib/gcc/${HOST}"/* ) # This expands to an array of directories...
CROSS_GCC_LIB="${CROSS_GCC_LIBS[0]}" # ...we just want the first one (there should only be one)
- NATIVE_GCC="$(store_path gcc-glibc-2.27-toolchain)"
- export LIBRARY_PATH="${NATIVE_GCC}/lib:${NATIVE_GCC}/lib64"
- export CPATH="${NATIVE_GCC}/include"
-
+ # The search path ordering is generally:
+ # 1. gcc-related search paths
+ # 2. libc-related search paths
+ # 2. kernel-header-related search paths (not applicable to mingw-w64 hosts)
export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include"
export CROSS_CPLUS_INCLUDE_PATH="${CROSS_GCC}/include/c++:${CROSS_GCC}/include/c++/${HOST}:${CROSS_GCC}/include/c++/backward:${CROSS_C_INCLUDE_PATH}"
export CROSS_LIBRARY_PATH="${CROSS_GCC}/lib:${CROSS_GCC}/${HOST}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib"
;;
+ *darwin*)
+ # The CROSS toolchain for darwin uses the SDK and ignores environment variables.
+ # See depends/hosts/darwin.mk for more details.
+ ;;
*linux*)
CROSS_GLIBC="$(store_path "glibc-cross-${HOST}")"
CROSS_GLIBC_STATIC="$(store_path "glibc-cross-${HOST}" static)"
@@ -71,9 +89,7 @@ case "$HOST" in
CROSS_GCC_LIBS=( "${CROSS_GCC}/lib/gcc/${HOST}"/* ) # This expands to an array of directories...
CROSS_GCC_LIB="${CROSS_GCC_LIBS[0]}" # ...we just want the first one (there should only be one)
- # NOTE: CROSS_C_INCLUDE_PATH is missing ${CROSS_GCC_LIB}/include-fixed, because
- # the limits.h in it is missing a '#include_next <limits.h>'
- export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GLIBC}/include:${CROSS_KERNEL}/include"
+ export CROSS_C_INCLUDE_PATH="${CROSS_GCC_LIB}/include:${CROSS_GCC_LIB}/include-fixed:${CROSS_GLIBC}/include:${CROSS_KERNEL}/include"
export CROSS_CPLUS_INCLUDE_PATH="${CROSS_GCC}/include/c++:${CROSS_GCC}/include/c++/${HOST}:${CROSS_GCC}/include/c++/backward:${CROSS_C_INCLUDE_PATH}"
export CROSS_LIBRARY_PATH="${CROSS_GCC}/lib:${CROSS_GCC}/${HOST}/lib:${CROSS_GCC_LIB}:${CROSS_GLIBC}/lib:${CROSS_GLIBC_STATIC}/lib"
;;
@@ -84,14 +100,25 @@ esac
# Sanity check CROSS_*_PATH directories
IFS=':' read -ra PATHS <<< "${CROSS_C_INCLUDE_PATH}:${CROSS_CPLUS_INCLUDE_PATH}:${CROSS_LIBRARY_PATH}"
for p in "${PATHS[@]}"; do
- if [ ! -d "$p" ]; then
+ if [ -n "$p" ] && [ ! -d "$p" ]; then
echo "'$p' doesn't exist or isn't a directory... Aborting..."
exit 1
fi
done
# Disable Guix ld auto-rpath behavior
-export GUIX_LD_WRAPPER_DISABLE_RPATH=yes
+case "$HOST" in
+ *darwin*)
+ # The auto-rpath behavior is necessary for darwin builds as some native
+ # tools built by depends refer to and depend on Guix-built native
+ # libraries
+ #
+ # After the native packages in depends are built, the ld wrapper should
+ # no longer affect our build, as clang would instead reach for
+ # x86_64-apple-darwin18-ld from cctools
+ ;;
+ *) export GUIX_LD_WRAPPER_DISABLE_RPATH=yes ;;
+esac
# Make /usr/bin if it doesn't exist
[ -e /usr/bin ] || mkdir -p /usr/bin
@@ -121,6 +148,16 @@ export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name"
export TZ="UTC"
+case "$HOST" in
+ *darwin*)
+ # cctools AR, unlike GNU binutils AR, does not have a deterministic mode
+ # or a configure flag to enable determinism by default, it only
+ # understands if this env-var is set or not. See:
+ #
+ # https://github.com/tpoechtrager/cctools-port/blob/55562e4073dea0fbfd0b20e0bf69ffe6390c7f97/cctools/ar/archive.c#L334
+ export ZERO_AR_DATE=yes
+ ;;
+esac
####################
# Depends Building #
@@ -142,7 +179,8 @@ make -C depends --jobs="$MAX_JOBS" HOST="$HOST" \
x86_64_linux_RANLIB=x86_64-linux-gnu-ranlib \
x86_64_linux_NM=x86_64-linux-gnu-nm \
x86_64_linux_STRIP=x86_64-linux-gnu-strip \
- qt_config_opts_i686_linux='-platform linux-g++ -xplatform bitcoin-linux-g++'
+ qt_config_opts_i686_linux='-platform linux-g++ -xplatform bitcoin-linux-g++' \
+ FORCE_USE_SYSTEM_CLANG=1
###########################
@@ -176,6 +214,7 @@ HOST_CFLAGS="-O2 -g"
case "$HOST" in
*linux*) HOST_CFLAGS+=" -ffile-prefix-map=${PWD}=." ;;
*mingw*) HOST_CFLAGS+=" -fno-ident" ;;
+ *darwin*) unset HOST_CFLAGS ;;
esac
# CXXFLAGS
@@ -189,6 +228,7 @@ esac
# Make $HOST-specific native binaries from depends available in $PATH
export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
+mkdir -p "$DISTSRC"
(
cd "$DISTSRC"
@@ -205,8 +245,8 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
--disable-maintainer-mode \
--disable-dependency-tracking \
${CONFIGFLAGS} \
- CFLAGS="${HOST_CFLAGS}" \
- CXXFLAGS="${HOST_CXXFLAGS}" \
+ ${HOST_CFLAGS:+CFLAGS="${HOST_CFLAGS}"} \
+ ${HOST_CXXFLAGS:+CXXFLAGS="${HOST_CXXFLAGS}"} \
${HOST_LDFLAGS:+LDFLAGS="${HOST_LDFLAGS}"}
sed -i.old 's/-lstdc++ //g' config.status libtool src/univalue/config.status src/univalue/libtool
@@ -216,14 +256,9 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
# Perform basic ELF security checks on a series of executables.
make -C src --jobs=1 check-security ${V:+V=1}
-
- case "$HOST" in
- *linux*|*mingw*)
- # Check that executables only contain allowed gcc, glibc and libstdc++
- # version symbols for Linux distro back-compatibility.
- make -C src --jobs=1 check-symbols ${V:+V=1}
- ;;
- esac
+ # Check that executables only contain allowed gcc, glibc and libstdc++
+ # version symbols for Linux distro back-compatibility.
+ make -C src --jobs=1 check-symbols ${V:+V=1}
# Make the os-specific installers
case "$HOST" in
@@ -238,8 +273,39 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
INSTALLPATH="${PWD}/installed/${DISTNAME}"
mkdir -p "${INSTALLPATH}"
# Install built Bitcoin Core to $INSTALLPATH
- make install DESTDIR="${INSTALLPATH}" ${V:+V=1}
+ case "$HOST" in
+ *darwin*)
+ make install-strip DESTDIR="${INSTALLPATH}" ${V:+V=1}
+ ;;
+ *)
+ make install DESTDIR="${INSTALLPATH}" ${V:+V=1}
+ ;;
+ esac
+ case "$HOST" in
+ *darwin*)
+ make osx_volname ${V:+V=1}
+ make deploydir ${V:+V=1}
+ mkdir -p "unsigned-app-${HOST}"
+ cp --target-directory="unsigned-app-${HOST}" \
+ osx_volname \
+ contrib/macdeploy/detached-sig-{apply,create}.sh \
+ "${BASEPREFIX}/${HOST}"/native/bin/dmg
+ for util in codesign_allocate pagestuff; do
+ cp --no-target-directory {"${BASEPREFIX}/${HOST}/native/bin/${HOST}-","unsigned-app-${HOST}/"}"$util"
+ done
+ mv --target-directory="unsigned-app-${HOST}" dist
+ (
+ cd "unsigned-app-${HOST}"
+ find . -print0 \
+ | sort --zero-terminated \
+ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
+ | gzip -9n > "${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz" \
+ || ( rm -f "${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz" && exit 1 )
+ )
+ make deploy ${V:+V=1} OSX_DMG="${OUTDIR}/${DISTNAME}-osx-unsigned.dmg"
+ ;;
+ esac
(
cd installed
@@ -254,13 +320,18 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
find . -name "lib*.a" -delete
# Prune pkg-config files
- rm -r "${DISTNAME}/lib/pkgconfig"
+ rm -rf "${DISTNAME}/lib/pkgconfig"
- # Split binaries and libraries from their debug symbols
- {
- find "${DISTNAME}/bin" -type f -executable -print0
- find "${DISTNAME}/lib" -type f -print0
- } | xargs -0 -n1 -P"$MAX_JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg
+ case "$HOST" in
+ *darwin*) ;;
+ *)
+ # Split binaries and libraries from their debug symbols
+ {
+ find "${DISTNAME}/bin" -type f -executable -print0
+ find "${DISTNAME}/lib" -type f -print0
+ } | xargs -0 -n1 -P"$MAX_JOBS" -I{} "${DISTSRC}/contrib/devtools/split-debug.sh" {} {} {}.dbg
+ ;;
+ esac
case "$HOST" in
*mingw*)
@@ -300,6 +371,13 @@ export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-debug.tar.gz" && exit 1 )
;;
+ *darwin*)
+ find "${DISTNAME}" -print0 \
+ | sort --zero-terminated \
+ | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
+ | gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST//x86_64-apple-darwin18/osx64}.tar.gz" \
+ || ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-apple-darwin18/osx64}.tar.gz" && exit 1 )
+ ;;
esac
)
)
diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm
index 5e011ea184..3b89659263 100644
--- a/contrib/guix/manifest.scm
+++ b/contrib/guix/manifest.scm
@@ -3,28 +3,44 @@
(gnu packages autotools)
(gnu packages base)
(gnu packages bash)
+ (gnu packages cdrom)
(gnu packages check)
+ (gnu packages cmake)
(gnu packages commencement)
(gnu packages compression)
(gnu packages cross-base)
(gnu packages file)
(gnu packages gawk)
(gnu packages gcc)
+ (gnu packages gnome)
+ (gnu packages image)
+ (gnu packages imagemagick)
(gnu packages installers)
(gnu packages linux)
+ (gnu packages llvm)
(gnu packages mingw)
(gnu packages perl)
(gnu packages pkg-config)
(gnu packages python)
(gnu packages shells)
(gnu packages version-control)
+ (guix build-system font)
(guix build-system gnu)
(guix build-system trivial)
+ (guix download)
(guix gexp)
+ ((guix licenses) #:prefix license:)
(guix packages)
(guix profiles)
(guix utils))
+(define-syntax-rule (search-our-patches file-name ...)
+ "Return the list of absolute file names corresponding to each
+FILE-NAME found in ./patches relative to the current file."
+ (parameterize
+ ((%patch-path (list (string-append (dirname (current-filename)) "/patches"))))
+ (list (search-patch file-name) ...)))
+
(define (make-ssp-fixed-gcc xgcc)
"Given a XGCC package, return a modified package that uses the SSP function
from glibc instead of from libssp.so. Our `symbol-check' script will complain if
@@ -150,11 +166,33 @@ chain for " target " development."))
(home-page (package-home-page pthreads-xgcc))
(license (package-license pthreads-xgcc)))))
+(define (make-nsis-with-sde-support base-nsis)
+ (package-with-extra-patches base-nsis
+ (search-our-patches "nsis-SConstruct-sde-support.patch")))
+
+(define-public font-tuffy
+ (package
+ (name "font-tuffy")
+ (version "20120614")
+ (source
+ (origin
+ (method url-fetch)
+ (uri (string-append "http://tulrich.com/fonts/tuffy-" version ".tar.gz"))
+ (file-name (string-append name "-" version ".tar.gz"))
+ (sha256
+ (base32
+ "02vf72bgrp30vrbfhxjw82s115z27dwfgnmmzfb0n9wfhxxfpyf6"))))
+ (build-system font-build-system)
+ (home-page "http://tulrich.com/fonts/")
+ (synopsis "The Tuffy Truetype Font Family")
+ (description
+ "Thatcher Ulrich's first outline font design. He started with the goal of producing a neutral, readable sans-serif text font. There are lots of \"expressive\" fonts out there, but he wanted to start with something very plain and clean, something he might want to actually use. ")
+ (license license:public-domain)))
(packages->manifest
(append
(list ;; The Basics
- bash-minimal
+ bash
which
coreutils
util-linux
@@ -184,15 +222,19 @@ chain for " target " development."))
python-3.7
;; Git
git
- ;; Native gcc 9 toolchain targeting glibc 2.27
- (make-gcc-toolchain gcc-9 glibc-2.27))
+ ;; Native gcc 7 toolchain
+ gcc-toolchain-7)
(let ((target (getenv "HOST")))
(cond ((string-suffix? "-mingw32" target)
;; Windows
- (list zip (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32") nsis-x86_64))
+ (list zip
+ (make-mingw-pthreads-cross-toolchain "x86_64-w64-mingw32")
+ (make-nsis-with-sde-support nsis-x86_64)))
((string-contains target "riscv64-linux-")
(list (make-bitcoin-cross-toolchain "riscv64-linux-gnu"
#:base-gcc-for-libc gcc-7)))
((string-contains target "-linux-")
(list (make-bitcoin-cross-toolchain target)))
+ ((string-contains target "darwin")
+ (list clang-8 libcap binutils imagemagick libtiff librsvg font-tuffy cmake-3.15.5 xorriso))
(else '())))))
diff --git a/contrib/guix/patches/nsis-SConstruct-sde-support.patch b/contrib/guix/patches/nsis-SConstruct-sde-support.patch
new file mode 100644
index 0000000000..5edf1b7c8e
--- /dev/null
+++ b/contrib/guix/patches/nsis-SConstruct-sde-support.patch
@@ -0,0 +1,15 @@
+diff --git a/SConstruct b/SConstruct
+index e8252c9..41786f2 100755
+--- a/SConstruct
++++ b/SConstruct
+@@ -95,8 +95,8 @@ default_doctype = 'html'
+ if defenv.WhereIs('hhc', os.environ['PATH']):
+ default_doctype = 'chm'
+
+-from time import strftime, gmtime
+-cvs_version = strftime('%d-%b-%Y.cvs', gmtime())
++import time
++cvs_version = time.strftime('%d-%b-%Y.cvs', time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
+
+ opts = Variables()
+
diff --git a/contrib/init/README.md b/contrib/init/README.md
index 306a37f75a..affc7c2e75 100644
--- a/contrib/init/README.md
+++ b/contrib/init/README.md
@@ -1,6 +1,6 @@
Sample configuration files for:
```
-SystemD: bitcoind.service
+systemd: bitcoind.service
Upstart: bitcoind.conf
OpenRC: bitcoind.openrc
bitcoind.openrcconf
@@ -9,4 +9,4 @@ macOS: org.bitcoin.bitcoind.plist
```
have been made available to assist packagers in creating node packages here.
-See doc/init.md for more information.
+See [doc/init.md](../../doc/init.md) for more information.
diff --git a/contrib/init/bitcoind.service b/contrib/init/bitcoind.service
index 8b308644b1..5999928aa4 100644
--- a/contrib/init/bitcoind.service
+++ b/contrib/init/bitcoind.service
@@ -11,7 +11,11 @@
[Unit]
Description=Bitcoin daemon
-After=network.target
+Documentation=https://github.com/bitcoin/bitcoin/blob/master/doc/init.md
+
+# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
+After=network-online.target
+Wants=network-online.target
[Service]
ExecStart=/usr/bin/bitcoind -daemon \
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
index e9130a21de..4037936404 100755
--- a/contrib/install_db4.sh
+++ b/contrib/install_db4.sh
@@ -68,10 +68,155 @@ tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX"
cd "${BDB_PREFIX}/${BDB_VERSION}/"
# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592)
-CLANG_CXX11_PATCH_URL='https://gist.githubusercontent.com/LnL7/5153b251fd525fe15de69b67e63a6075/raw/7778e9364679093a32dec2908656738e16b6bdcb/clang.patch'
-CLANG_CXX11_PATCH_HASH='7a9a47b03fd5fb93a16ef42235fa9512db9b0829cfc3bdf90edd3ec1f44d637c'
-http_get "${CLANG_CXX11_PATCH_URL}" clang.patch "${CLANG_CXX11_PATCH_HASH}"
-patch -p2 < clang.patch
+patch --ignore-whitespace -p1 << 'EOF'
+commit 3311d68f11d1697565401eee6efc85c34f022ea7
+Author: fanquake <fanquake@gmail.com>
+Date: Mon Aug 17 20:03:56 2020 +0800
+
+ Fix C++11 compatibility
+
+diff --git a/dbinc/atomic.h b/dbinc/atomic.h
+index 0034dcc..7c11d4a 100644
+--- a/dbinc/atomic.h
++++ b/dbinc/atomic.h
+@@ -70,7 +70,7 @@ typedef struct {
+ * These have no memory barriers; the caller must include them when necessary.
+ */
+ #define atomic_read(p) ((p)->value)
+-#define atomic_init(p, val) ((p)->value = (val))
++#define atomic_init_db(p, val) ((p)->value = (val))
+
+ #ifdef HAVE_ATOMIC_SUPPORT
+
+@@ -144,7 +144,7 @@ typedef LONG volatile *interlocked_val;
+ #define atomic_inc(env, p) __atomic_inc(p)
+ #define atomic_dec(env, p) __atomic_dec(p)
+ #define atomic_compare_exchange(env, p, o, n) \
+- __atomic_compare_exchange((p), (o), (n))
++ __atomic_compare_exchange_db((p), (o), (n))
+ static inline int __atomic_inc(db_atomic_t *p)
+ {
+ int temp;
+@@ -176,7 +176,7 @@ static inline int __atomic_dec(db_atomic_t *p)
+ * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
+ * which configure could be changed to use.
+ */
+-static inline int __atomic_compare_exchange(
++static inline int __atomic_compare_exchange_db(
+ db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
+ {
+ atomic_value_t was;
+@@ -206,7 +206,7 @@ static inline int __atomic_compare_exchange(
+ #define atomic_dec(env, p) (--(p)->value)
+ #define atomic_compare_exchange(env, p, oldval, newval) \
+ (DB_ASSERT(env, atomic_read(p) == (oldval)), \
+- atomic_init(p, (newval)), 1)
++ atomic_init_db(p, (newval)), 1)
+ #else
+ #define atomic_inc(env, p) __atomic_inc(env, p)
+ #define atomic_dec(env, p) __atomic_dec(env, p)
+diff --git a/mp/mp_fget.c b/mp/mp_fget.c
+index 5fdee5a..0b75f57 100644
+--- a/mp/mp_fget.c
++++ b/mp/mp_fget.c
+@@ -617,7 +617,7 @@ alloc: /* Allocate a new buffer header and data space. */
+
+ /* Initialize enough so we can call __memp_bhfree. */
+ alloc_bhp->flags = 0;
+- atomic_init(&alloc_bhp->ref, 1);
++ atomic_init_db(&alloc_bhp->ref, 1);
+ #ifdef DIAGNOSTIC
+ if ((uintptr_t)alloc_bhp->buf & (sizeof(size_t) - 1)) {
+ __db_errx(env,
+@@ -911,7 +911,7 @@ alloc: /* Allocate a new buffer header and data space. */
+ MVCC_MPROTECT(bhp->buf, mfp->stat.st_pagesize,
+ PROT_READ);
+
+- atomic_init(&alloc_bhp->ref, 1);
++ atomic_init_db(&alloc_bhp->ref, 1);
+ MUTEX_LOCK(env, alloc_bhp->mtx_buf);
+ alloc_bhp->priority = bhp->priority;
+ alloc_bhp->pgno = bhp->pgno;
+diff --git a/mp/mp_mvcc.c b/mp/mp_mvcc.c
+index 34467d2..f05aa0c 100644
+--- a/mp/mp_mvcc.c
++++ b/mp/mp_mvcc.c
+@@ -276,7 +276,7 @@ __memp_bh_freeze(dbmp, infop, hp, bhp, need_frozenp)
+ #else
+ memcpy(frozen_bhp, bhp, SSZA(BH, buf));
+ #endif
+- atomic_init(&frozen_bhp->ref, 0);
++ atomic_init_db(&frozen_bhp->ref, 0);
+ if (mutex != MUTEX_INVALID)
+ frozen_bhp->mtx_buf = mutex;
+ else if ((ret = __mutex_alloc(env, MTX_MPOOL_BH,
+@@ -428,7 +428,7 @@ __memp_bh_thaw(dbmp, infop, hp, frozen_bhp, alloc_bhp)
+ #endif
+ alloc_bhp->mtx_buf = mutex;
+ MUTEX_LOCK(env, alloc_bhp->mtx_buf);
+- atomic_init(&alloc_bhp->ref, 1);
++ atomic_init_db(&alloc_bhp->ref, 1);
+ F_CLR(alloc_bhp, BH_FROZEN);
+ }
+
+diff --git a/mp/mp_region.c b/mp/mp_region.c
+index e6cece9..ddbe906 100644
+--- a/mp/mp_region.c
++++ b/mp/mp_region.c
+@@ -224,7 +224,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
+ MTX_MPOOL_FILE_BUCKET, 0, &htab[i].mtx_hash)) != 0)
+ return (ret);
+ SH_TAILQ_INIT(&htab[i].hash_bucket);
+- atomic_init(&htab[i].hash_page_dirty, 0);
++ atomic_init_db(&htab[i].hash_page_dirty, 0);
+ }
+
+ /*
+@@ -269,7 +269,7 @@ __memp_init(env, dbmp, reginfo_off, htab_buckets, max_nreg)
+ hp->mtx_hash = (mtx_base == MUTEX_INVALID) ? MUTEX_INVALID :
+ mtx_base + i;
+ SH_TAILQ_INIT(&hp->hash_bucket);
+- atomic_init(&hp->hash_page_dirty, 0);
++ atomic_init_db(&hp->hash_page_dirty, 0);
+ #ifdef HAVE_STATISTICS
+ hp->hash_io_wait = 0;
+ hp->hash_frozen = hp->hash_thawed = hp->hash_frozen_freed = 0;
+diff --git a/mutex/mut_method.c b/mutex/mut_method.c
+index 2588763..5c6d516 100644
+--- a/mutex/mut_method.c
++++ b/mutex/mut_method.c
+@@ -426,7 +426,7 @@ atomic_compare_exchange(env, v, oldval, newval)
+ MUTEX_LOCK(env, mtx);
+ ret = atomic_read(v) == oldval;
+ if (ret)
+- atomic_init(v, newval);
++ atomic_init_db(v, newval);
+ MUTEX_UNLOCK(env, mtx);
+
+ return (ret);
+diff --git a/mutex/mut_tas.c b/mutex/mut_tas.c
+index f3922e0..e40fcdf 100644
+--- a/mutex/mut_tas.c
++++ b/mutex/mut_tas.c
+@@ -46,7 +46,7 @@ __db_tas_mutex_init(env, mutex, flags)
+
+ #ifdef HAVE_SHARED_LATCHES
+ if (F_ISSET(mutexp, DB_MUTEX_SHARED))
+- atomic_init(&mutexp->sharecount, 0);
++ atomic_init_db(&mutexp->sharecount, 0);
+ else
+ #endif
+ if (MUTEX_INIT(&mutexp->tas)) {
+@@ -486,7 +486,7 @@ __db_tas_mutex_unlock(env, mutex)
+ F_CLR(mutexp, DB_MUTEX_LOCKED);
+ /* Flush flag update before zeroing count */
+ MEMBAR_EXIT();
+- atomic_init(&mutexp->sharecount, 0);
++ atomic_init_db(&mutexp->sharecount, 0);
+ } else {
+ DB_ASSERT(env, sharecount > 0);
+ MEMBAR_EXIT();
+EOF
# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
# Replace them with modern versions.
diff --git a/contrib/macdeploy/detached-sig-apply.sh b/contrib/macdeploy/detached-sig-apply.sh
index 5c5a85d3fe..d481413cc3 100755
--- a/contrib/macdeploy/detached-sig-apply.sh
+++ b/contrib/macdeploy/detached-sig-apply.sh
@@ -8,10 +8,9 @@ set -e
UNSIGNED="$1"
SIGNATURE="$2"
-ARCH=x86_64
ROOTDIR=dist
-TEMPDIR=signed.temp
OUTDIR=signed-app
+SIGNAPPLE=signapple
if [ -z "$UNSIGNED" ]; then
echo "usage: $0 <unsigned app> <signature>"
@@ -23,35 +22,6 @@ if [ -z "$SIGNATURE" ]; then
exit 1
fi
-rm -rf ${TEMPDIR} && mkdir -p ${TEMPDIR}
-tar -C ${TEMPDIR} -xf ${UNSIGNED}
-cp -rf "${SIGNATURE}"/* ${TEMPDIR}
-
-if [ -z "${PAGESTUFF}" ]; then
- PAGESTUFF=${TEMPDIR}/pagestuff
-fi
-
-if [ -z "${CODESIGN_ALLOCATE}" ]; then
- CODESIGN_ALLOCATE=${TEMPDIR}/codesign_allocate
-fi
-
-find ${TEMPDIR} -name "*.sign" | while read i; do
- SIZE=$(stat -c %s "${i}")
- TARGET_FILE="$(echo "${i}" | sed 's/\.sign$//')"
-
- echo "Allocating space for the signature of size ${SIZE} in ${TARGET_FILE}"
- ${CODESIGN_ALLOCATE} -i "${TARGET_FILE}" -a ${ARCH} ${SIZE} -o "${i}.tmp"
-
- OFFSET=$(${PAGESTUFF} "${i}.tmp" -p | tail -2 | grep offset | sed 's/[^0-9]*//g')
- if [ -z ${QUIET} ]; then
- echo "Attaching signature at offset ${OFFSET}"
- fi
-
- dd if="$i" of="${i}.tmp" bs=1 seek=${OFFSET} count=${SIZE} 2>/dev/null
- mv "${i}.tmp" "${TARGET_FILE}"
- rm "${i}"
- echo "Success."
-done
-mv ${TEMPDIR}/${ROOTDIR} ${OUTDIR}
-rm -rf ${TEMPDIR}
+${SIGNAPPLE} apply ${UNSIGNED} ${SIGNATURE}
+mv ${ROOTDIR} ${OUTDIR}
echo "Signed: ${OUTDIR}"
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index 31a97f0a24..4f246cbb3f 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -8,44 +8,21 @@ set -e
ROOTDIR=dist
BUNDLE="${ROOTDIR}/Bitcoin-Qt.app"
-CODESIGN=codesign
+SIGNAPPLE=signapple
TEMPDIR=sign.temp
-TEMPLIST=${TEMPDIR}/signatures.txt
OUT=signature-osx.tar.gz
-OUTROOT=osx
+OUTROOT=osx/dist
if [ -z "$1" ]; then
- echo "usage: $0 <codesign args>"
- echo "example: $0 -s MyIdentity"
+ echo "usage: $0 <signapple args>"
+ echo "example: $0 <path to key>"
exit 1
fi
-rm -rf ${TEMPDIR} ${TEMPLIST}
+rm -rf ${TEMPDIR}
mkdir -p ${TEMPDIR}
-${CODESIGN} -f --file-list ${TEMPLIST} "$@" "${BUNDLE}"
-
-grep -v CodeResources < "${TEMPLIST}" | while read i; do
- TARGETFILE="${BUNDLE}/$(echo "${i}" | sed "s|.*${BUNDLE}/||")"
- SIZE=$(pagestuff "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g')
- OFFSET=$(pagestuff "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g')
- SIGNFILE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign"
- DIRNAME="$(dirname "${SIGNFILE}")"
- mkdir -p "${DIRNAME}"
- echo "Adding detached signature for: ${TARGETFILE}. Size: ${SIZE}. Offset: ${OFFSET}"
- dd if="$i" of="${SIGNFILE}" bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null
-done
-
-grep CodeResources < "${TEMPLIST}" | while read i; do
- TARGETFILE="${BUNDLE}/$(echo "${i}" | sed "s|.*${BUNDLE}/||")"
- RESOURCE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}"
- DIRNAME="$(dirname "${RESOURCE}")"
- mkdir -p "${DIRNAME}"
- echo "Adding resource for: \"${TARGETFILE}\""
- cp "${i}" "${RESOURCE}"
-done
-
-rm ${TEMPLIST}
+${SIGNAPPLE} sign -f --detach "${TEMPDIR}/${OUTROOT}" "$@" "${BUNDLE}"
tar -C "${TEMPDIR}" -czf "${OUT}" .
rm -rf "${TEMPDIR}"
diff --git a/contrib/macdeploy/extract-osx-sdk.sh b/contrib/macdeploy/extract-osx-sdk.sh
deleted file mode 100755
index 3c7bdf4217..0000000000
--- a/contrib/macdeploy/extract-osx-sdk.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2016-2020 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-export LC_ALL=C
-set -e
-
-INPUTFILE="Xcode_7.3.1.dmg"
-HFSFILENAME="5.hfs"
-SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk"
-
-7z x "${INPUTFILE}" "${HFSFILENAME}"
-SDKNAME="$(basename "${SDKDIR}")"
-SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}")
-fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} |
- while read type inode filename; do
- inode="${inode::-1}"
- if [ "${filename:0:14}" = "usr/share/man/" ]; then
- continue
- fi
- filename="${SDKNAME}/$filename"
- echo "Extracting $filename ..."
- mkdir -p "$(dirname "$filename")"
- if [ "$type" = "l/l" ]; then
- ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename"
- else
- icat "${HFSFILENAME}" $inode >"$filename"
- fi
-done
-echo "Building ${SDKNAME}.tar.gz ..."
-MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')"
-find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz"
-echo 'All done!'
diff --git a/contrib/signet/README.md b/contrib/signet/README.md
index c4aa5ae2f7..71dc2f9638 100644
--- a/contrib/signet/README.md
+++ b/contrib/signet/README.md
@@ -17,3 +17,64 @@ Syntax: `getcoins.py [-h|--help] [-c|--cmd=<bitcoin-cli path>] [-f|--faucet=<fau
If using the default network, invoking the script with no arguments should be sufficient under normal
circumstances, but if multiple people are behind the same IP address, the faucet will by default only
accept one claim per day. See `--password` above.
+
+miner
+=====
+
+To mine the first block in your custom chain, you can run:
+
+ cd src/
+ CLI="./bitcoin-cli -conf=mysignet.conf"
+ MINER="..contrib/signet/miner"
+ GRIND="./bitcoin-util grind"
+ ADDR=$($CLI -signet getnewaddress)
+ $MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --set-block-time=-1
+
+This will mine a block with the current timestamp. If you want to backdate the chain, you can give a different timestamp to --set-block-time.
+
+You will then need to pick a difficulty target. Since signet chains are primarily protected by a signature rather than proof of work, there is no need to spend as much energy as possible mining, however you may wish to choose to spend more time than the absolute minimum. The calibrate subcommand can be used to pick a target, eg:
+
+ $MINER calibrate --grind-cmd="$GRIND"
+ nbits=1e00f403 for 25s average mining time
+
+It defaults to estimating an nbits value resulting in 25s average time to find a block, but the --seconds parameter can be used to pick a different target, or the --nbits parameter can be used to estimate how long it will take for a given difficulty.
+
+Using the --ongoing parameter will then cause the signet miner to create blocks indefinitely. It will pick the time between blocks so that difficulty is adjusted to match the provided --nbits value.
+
+ $MINER --cli="$CLI" generate --grind-cmd="$GRIND" --address="$ADDR" --nbits=1e00f403 --ongoing
+
+Other options
+-------------
+
+The --debug and --quiet options are available to control how noisy the signet miner's output is. Note that the --debug, --quiet and --cli parameters must all appear before the subcommand (generate, calibrate, etc) if used.
+
+Instead of specifying --ongoing, you can specify --max-blocks=N to mine N blocks and stop.
+
+Instead of using a single address, a ranged descriptor may be provided instead (via the --descriptor parameter), with the reward for the block at height H being sent to the H'th address generated from the descriptor.
+
+Instead of calculating a specific nbits value, --min-nbits can be specified instead, in which case the mininmum signet difficulty will be targeted.
+
+By default, the signet miner mines blocks at fixed intervals with minimal variation. If you want blocks to appear more randomly, as they do in mainnet, specify the --poisson option.
+
+Using the --multiminer parameter allows mining to be distributed amongst multiple miners. For example, if you have 3 miners and want to share blocks between them, specify --multiminer=1/3 on one, --multiminer=2/3 on another, and --multiminer=3/3 on the last one. If you want one to do 10% of blocks and two others to do 45% each, --multiminer=1-10/100 on the first, and --multiminer=11-55 and --multiminer=56-100 on the others. Note that which miner mines which block is determined by the previous block hash, so occasional runs of one miner doing many blocks in a row is to be expected.
+
+When --multiminer is used, if a miner is down and does not mine a block within five minutes of when it is due, the other miners will automatically act as redundant backups ensuring the chain does not halt. The --backup-delay parameter can be used to change how long a given miner waits, allowing one to be the primary backup (after five minutes) and another to be the secondary backup (after six minutes, eg).
+
+The --standby-delay parameter can be used to make a backup miner that only mines if a block doesn't arrive on time. This can be combined with --multiminer if desired. Setting --standby-delay also prevents the first block from being mined immediately.
+
+Advanced usage
+--------------
+
+The process generate follows internally is to get a block template, convert that into a PSBT, sign the PSBT, move the signature from the signed PSBT into the block template's coinbase, grind proof of work for the block, and then submit the block to the network.
+
+These steps can instead be done explicitly:
+
+ $CLI -signet getblocktemplate '{"rules": ["signet","segwit"]}' |
+ $MINER --cli="$CLI" genpsbt --address="$ADDR" |
+ $CLI -signet -stdin walletprocesspsbt |
+ jq -r .psbt |
+ $MINER --cli="$CLI" solvepsbt --grind-cmd="$GRIND" |
+ $CLI -signet -stdin submitblock
+
+This is intended to allow you to replace part of the pipeline for further experimentation, if desired.
+
diff --git a/contrib/signet/miner b/contrib/signet/miner
new file mode 100755
index 0000000000..a3fba49d0e
--- /dev/null
+++ b/contrib/signet/miner
@@ -0,0 +1,639 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import argparse
+import base64
+import json
+import logging
+import math
+import os.path
+import re
+import struct
+import sys
+import time
+import subprocess
+
+from binascii import unhexlify
+from io import BytesIO
+
+PATH_BASE_CONTRIB_SIGNET = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
+PATH_BASE_TEST_FUNCTIONAL = os.path.abspath(os.path.join(PATH_BASE_CONTRIB_SIGNET, "..", "..", "test", "functional"))
+sys.path.insert(0, PATH_BASE_TEST_FUNCTIONAL)
+
+from test_framework.blocktools import WITNESS_COMMITMENT_HEADER, script_BIP34_coinbase_height # noqa: E402
+from test_framework.messages import CBlock, CBlockHeader, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, ToHex, deser_string, hash256, ser_compact_size, ser_string, ser_uint256, uint256_from_str # noqa: E402
+from test_framework.script import CScriptOp # noqa: E402
+
+logging.basicConfig(
+ format='%(asctime)s %(levelname)s %(message)s',
+ level=logging.INFO,
+ datefmt='%Y-%m-%d %H:%M:%S')
+
+SIGNET_HEADER = b"\xec\xc7\xda\xa2"
+PSBT_SIGNET_BLOCK = b"\xfc\x06signetb" # proprietary PSBT global field holding the block being signed
+RE_MULTIMINER = re.compile("^(\d+)(-(\d+))?/(\d+)$")
+
+# #### some helpers that could go into test_framework
+
+# like FromHex, but without the hex part
+def FromBinary(cls, stream):
+ """deserialize a binary stream (or bytes object) into an object"""
+ # handle bytes object by turning it into a stream
+ was_bytes = isinstance(stream, bytes)
+ if was_bytes:
+ stream = BytesIO(stream)
+ obj = cls()
+ obj.deserialize(stream)
+ if was_bytes:
+ assert len(stream.read()) == 0
+ return obj
+
+class PSBTMap:
+ """Class for serializing and deserializing PSBT maps"""
+
+ def __init__(self, map=None):
+ self.map = map if map is not None else {}
+
+ def deserialize(self, f):
+ m = {}
+ while True:
+ k = deser_string(f)
+ if len(k) == 0:
+ break
+ v = deser_string(f)
+ if len(k) == 1:
+ k = k[0]
+ assert k not in m
+ m[k] = v
+ self.map = m
+
+ def serialize(self):
+ m = b""
+ for k,v in self.map.items():
+ if isinstance(k, int) and 0 <= k and k <= 255:
+ k = bytes([k])
+ m += ser_compact_size(len(k)) + k
+ m += ser_compact_size(len(v)) + v
+ m += b"\x00"
+ return m
+
+class PSBT:
+ """Class for serializing and deserializing PSBTs"""
+
+ def __init__(self):
+ self.g = PSBTMap()
+ self.i = []
+ self.o = []
+ self.tx = None
+
+ def deserialize(self, f):
+ assert f.read(5) == b"psbt\xff"
+ self.g = FromBinary(PSBTMap, f)
+ assert 0 in self.g.map
+ self.tx = FromBinary(CTransaction, self.g.map[0])
+ self.i = [FromBinary(PSBTMap, f) for _ in self.tx.vin]
+ self.o = [FromBinary(PSBTMap, f) for _ in self.tx.vout]
+ return self
+
+ def serialize(self):
+ assert isinstance(self.g, PSBTMap)
+ assert isinstance(self.i, list) and all(isinstance(x, PSBTMap) for x in self.i)
+ assert isinstance(self.o, list) and all(isinstance(x, PSBTMap) for x in self.o)
+ assert 0 in self.g.map
+ tx = FromBinary(CTransaction, self.g.map[0])
+ assert len(tx.vin) == len(self.i)
+ assert len(tx.vout) == len(self.o)
+
+ psbt = [x.serialize() for x in [self.g] + self.i + self.o]
+ return b"psbt\xff" + b"".join(psbt)
+
+ def to_base64(self):
+ return base64.b64encode(self.serialize()).decode("utf8")
+
+ @classmethod
+ def from_base64(cls, b64psbt):
+ return FromBinary(cls, base64.b64decode(b64psbt))
+
+# #####
+
+def create_coinbase(height, value, spk):
+ cb = CTransaction()
+ cb.vin = [CTxIn(COutPoint(0, 0xffffffff), script_BIP34_coinbase_height(height), 0xffffffff)]
+ cb.vout = [CTxOut(value, spk)]
+ return cb
+
+def get_witness_script(witness_root, witness_nonce):
+ commitment = uint256_from_str(hash256(ser_uint256(witness_root) + ser_uint256(witness_nonce)))
+ return b"\x6a" + CScriptOp.encode_op_pushdata(WITNESS_COMMITMENT_HEADER + ser_uint256(commitment))
+
+def signet_txs(block, challenge):
+ # assumes signet solution has not been added yet so does not need
+ # to be removed
+
+ txs = block.vtx[:]
+ txs[0] = CTransaction(txs[0])
+ txs[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER)
+ hashes = []
+ for tx in txs:
+ tx.rehash()
+ hashes.append(ser_uint256(tx.sha256))
+ mroot = block.get_merkle_root(hashes)
+
+ sd = b""
+ sd += struct.pack("<i", block.nVersion)
+ sd += ser_uint256(block.hashPrevBlock)
+ sd += ser_uint256(mroot)
+ sd += struct.pack("<I", block.nTime)
+
+ to_spend = CTransaction()
+ to_spend.nVersion = 0
+ to_spend.nLockTime = 0
+ to_spend.vin = [CTxIn(COutPoint(0, 0xFFFFFFFF), b"\x00" + CScriptOp.encode_op_pushdata(sd), 0)]
+ to_spend.vout = [CTxOut(0, challenge)]
+ to_spend.rehash()
+
+ spend = CTransaction()
+ spend.nVersion = 0
+ spend.nLockTime = 0
+ spend.vin = [CTxIn(COutPoint(to_spend.sha256, 0), b"", 0)]
+ spend.vout = [CTxOut(0, b"\x6a")]
+
+ return spend, to_spend
+
+def do_createpsbt(block, signme, spendme):
+ psbt = PSBT()
+ psbt.g = PSBTMap( {0: signme.serialize(),
+ PSBT_SIGNET_BLOCK: block.serialize()
+ } )
+ psbt.i = [ PSBTMap( {0: spendme.serialize(),
+ 3: bytes([1,0,0,0])})
+ ]
+ psbt.o = [ PSBTMap() ]
+ return psbt.to_base64()
+
+def do_decode_psbt(b64psbt):
+ psbt = PSBT.from_base64(b64psbt)
+
+ assert len(psbt.tx.vin) == 1
+ assert len(psbt.tx.vout) == 1
+ assert PSBT_SIGNET_BLOCK in psbt.g.map
+
+ scriptSig = psbt.i[0].map.get(7, b"")
+ scriptWitness = psbt.i[0].map.get(8, b"\x00")
+
+ return FromBinary(CBlock, psbt.g.map[PSBT_SIGNET_BLOCK]), ser_string(scriptSig) + scriptWitness
+
+def finish_block(block, signet_solution, grind_cmd):
+ block.vtx[0].vout[-1].scriptPubKey += CScriptOp.encode_op_pushdata(SIGNET_HEADER + signet_solution)
+ block.vtx[0].rehash()
+ block.hashMerkleRoot = block.calc_merkle_root()
+ if grind_cmd is None:
+ block.solve()
+ else:
+ headhex = CBlockHeader.serialize(block).hex()
+ cmd = grind_cmd.split(" ") + [headhex]
+ newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
+ newhead = FromHex(CBlockHeader(), newheadhex.decode('utf8'))
+ block.nNonce = newhead.nNonce
+ block.rehash()
+ return block
+
+def generate_psbt(tmpl, reward_spk, *, blocktime=None):
+ signet_spk = tmpl["signet_challenge"]
+ signet_spk_bin = unhexlify(signet_spk)
+
+ cbtx = create_coinbase(height=tmpl["height"], value=tmpl["coinbasevalue"], spk=reward_spk)
+ cbtx.vin[0].nSequence = 2**32-2
+ cbtx.rehash()
+
+ block = CBlock()
+ block.nVersion = tmpl["version"]
+ block.hashPrevBlock = int(tmpl["previousblockhash"], 16)
+ block.nTime = tmpl["curtime"] if blocktime is None else blocktime
+ if block.nTime < tmpl["mintime"]:
+ block.nTime = tmpl["mintime"]
+ block.nBits = int(tmpl["bits"], 16)
+ block.nNonce = 0
+ block.vtx = [cbtx] + [FromHex(CTransaction(), t["data"]) for t in tmpl["transactions"]]
+
+ witnonce = 0
+ witroot = block.calc_witness_merkle_root()
+ cbwit = CTxInWitness()
+ cbwit.scriptWitness.stack = [ser_uint256(witnonce)]
+ block.vtx[0].wit.vtxinwit = [cbwit]
+ block.vtx[0].vout.append(CTxOut(0, get_witness_script(witroot, witnonce)))
+
+ signme, spendme = signet_txs(block, signet_spk_bin)
+
+ return do_createpsbt(block, signme, spendme)
+
+def get_reward_address(args, height):
+ if args.address is not None:
+ return args.address
+
+ if '*' not in args.descriptor:
+ addr = json.loads(args.bcli("deriveaddresses", args.descriptor))[0]
+ args.address = addr
+ return addr
+
+ remove = [k for k in args.derived_addresses.keys() if k+20 <= height]
+ for k in remove:
+ del args.derived_addresses[k]
+
+ addr = args.derived_addresses.get(height, None)
+ if addr is None:
+ addrs = json.loads(args.bcli("deriveaddresses", args.descriptor, "[%d,%d]" % (height, height+20)))
+ addr = addrs[0]
+ for k, a in enumerate(addrs):
+ args.derived_addresses[height+k] = a
+
+ return addr
+
+def get_reward_addr_spk(args, height):
+ assert args.address is not None or args.descriptor is not None
+
+ if hasattr(args, "reward_spk"):
+ return args.address, args.reward_spk
+
+ reward_addr = get_reward_address(args, height)
+ reward_spk = unhexlify(json.loads(args.bcli("getaddressinfo", reward_addr))["scriptPubKey"])
+ if args.address is not None:
+ # will always be the same, so cache
+ args.reward_spk = reward_spk
+
+ return reward_addr, reward_spk
+
+def do_genpsbt(args):
+ tmpl = json.load(sys.stdin)
+ _, reward_spk = get_reward_addr_spk(args, tmpl["height"])
+ psbt = generate_psbt(tmpl, reward_spk)
+ print(psbt)
+
+def do_solvepsbt(args):
+ block, signet_solution = do_decode_psbt(sys.stdin.read())
+ block = finish_block(block, signet_solution, args.grind_cmd)
+ print(ToHex(block))
+
+def nbits_to_target(nbits):
+ shift = (nbits >> 24) & 0xff
+ return (nbits & 0x00ffffff) * 2**(8*(shift - 3))
+
+def target_to_nbits(target):
+ tstr = "{0:x}".format(target)
+ if len(tstr) < 6:
+ tstr = ("000000"+tstr)[-6:]
+ if len(tstr) % 2 != 0:
+ tstr = "0" + tstr
+ if int(tstr[0],16) >= 0x8:
+ # avoid "negative"
+ tstr = "00" + tstr
+ fix = int(tstr[:6], 16)
+ sz = len(tstr)//2
+ if tstr[6:] != "0"*(sz*2-6):
+ fix += 1
+
+ return int("%02x%06x" % (sz,fix), 16)
+
+def seconds_to_hms(s):
+ if s == 0:
+ return "0s"
+ neg = (s < 0)
+ if neg:
+ s = -s
+ out = ""
+ if s % 60 > 0:
+ out = "%ds" % (s % 60)
+ s //= 60
+ if s % 60 > 0:
+ out = "%dm%s" % (s % 60, out)
+ s //= 60
+ if s > 0:
+ out = "%dh%s" % (s, out)
+ if neg:
+ out = "-" + out
+ return out
+
+def next_block_delta(last_nbits, last_hash, ultimate_target, do_poisson):
+ # strategy:
+ # 1) work out how far off our desired target we are
+ # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period
+ # 3) use that to work out the desired average interval in this retarget period
+ # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by
+ # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes
+
+ INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug
+
+ current_target = nbits_to_target(last_nbits)
+ retarget_factor = ultimate_target / current_target
+ retarget_factor = max(0.25, min(retarget_factor, 4.0))
+
+ avg_interval = INTERVAL * retarget_factor
+
+ if do_poisson:
+ det_rand = int(last_hash[-8:], 16) * 2**-32
+ this_interval_variance = -math.log1p(-det_rand)
+ else:
+ this_interval_variance = 1
+
+ this_interval = avg_interval * this_interval_variance
+ this_interval = max(1, min(this_interval, 3600))
+
+ return this_interval
+
+def next_block_is_mine(last_hash, my_blocks):
+ det_rand = int(last_hash[-16:-8], 16)
+ return my_blocks[0] <= (det_rand % my_blocks[2]) < my_blocks[1]
+
+def do_generate(args):
+ if args.max_blocks is not None:
+ if args.ongoing:
+ logging.error("Cannot specify both --ongoing and --max-blocks")
+ return 1
+ if args.max_blocks < 1:
+ logging.error("N must be a positive integer")
+ return 1
+ max_blocks = args.max_blocks
+ elif args.ongoing:
+ max_blocks = None
+ else:
+ max_blocks = 1
+
+ if args.set_block_time is not None and max_blocks != 1:
+ logging.error("Cannot specify --ongoing or --max-blocks > 1 when using --set-block-time")
+ return 1
+ if args.set_block_time is not None and args.set_block_time < 0:
+ args.set_block_time = time.time()
+ logging.info("Treating negative block time as current time (%d)" % (args.set_block_time))
+
+ if args.min_nbits:
+ if args.nbits is not None:
+ logging.error("Cannot specify --nbits and --min-nbits")
+ return 1
+ args.nbits = "1e0377ae"
+ logging.info("Using nbits=%s" % (args.nbits))
+
+ if args.set_block_time is None:
+ if args.nbits is None or len(args.nbits) != 8:
+ logging.error("Must specify --nbits (use calibrate command to determine value)")
+ return 1
+
+ if args.multiminer is None:
+ my_blocks = (0,1,1)
+ else:
+ if not args.ongoing:
+ logging.error("Cannot specify --multiminer without --ongoing")
+ return 1
+ m = RE_MULTIMINER.match(args.multiminer)
+ if m is None:
+ logging.error("--multiminer argument must be k/m or j-k/m")
+ return 1
+ start,_,stop,total = m.groups()
+ if stop is None:
+ stop = start
+ start, stop, total = map(int, (start, stop, total))
+ if stop < start or start <= 0 or total < stop or total == 0:
+ logging.error("Inconsistent values for --multiminer")
+ return 1
+ my_blocks = (start-1, stop, total)
+
+ ultimate_target = nbits_to_target(int(args.nbits,16))
+
+ mined_blocks = 0
+ bestheader = {"hash": None}
+ lastheader = None
+ while max_blocks is None or mined_blocks < max_blocks:
+
+ # current status?
+ bci = json.loads(args.bcli("getblockchaininfo"))
+
+ if bestheader["hash"] != bci["bestblockhash"]:
+ bestheader = json.loads(args.bcli("getblockheader", bci["bestblockhash"]))
+
+ if lastheader is None:
+ lastheader = bestheader["hash"]
+ elif bestheader["hash"] != lastheader:
+ next_delta = next_block_delta(int(bestheader["bits"], 16), bestheader["hash"], ultimate_target, args.poisson)
+ next_delta += bestheader["time"] - time.time()
+ next_is_mine = next_block_is_mine(bestheader["hash"], my_blocks)
+ logging.info("Received new block at height %d; next in %s (%s)", bestheader["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup"))
+ lastheader = bestheader["hash"]
+
+ # when is the next block due to be mined?
+ now = time.time()
+ if args.set_block_time is not None:
+ logging.debug("Setting start time to %d", args.set_block_time)
+ mine_time = args.set_block_time
+ action_time = now
+ is_mine = True
+ elif bestheader["height"] == 0:
+ logging.error("When mining first block in a new signet, must specify --set-block-time")
+ return 1
+ else:
+
+ time_delta = next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"], ultimate_target, args.poisson)
+ mine_time = bestheader["time"] + time_delta
+
+ is_mine = next_block_is_mine(bci["bestblockhash"], my_blocks)
+
+ action_time = mine_time
+ if not is_mine:
+ action_time += args.backup_delay
+
+ if args.standby_delay > 0:
+ action_time += args.standby_delay
+ elif mined_blocks == 0:
+ # for non-standby, always mine immediately on startup,
+ # even if the next block shouldn't be ours
+ action_time = now
+
+ # don't want fractional times so round down
+ mine_time = int(mine_time)
+ action_time = int(action_time)
+
+ # can't mine a block 2h in the future; 1h55m for some safety
+ action_time = max(action_time, mine_time - 6900)
+
+ # ready to go? otherwise sleep and check for new block
+ if now < action_time:
+ sleep_for = min(action_time - now, 60)
+ if mine_time < now:
+ # someone else might have mined the block,
+ # so check frequently, so we don't end up late
+ # mining the next block if it's ours
+ sleep_for = min(20, sleep_for)
+ minestr = "mine" if is_mine else "backup"
+ logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(mine_time - now), minestr))
+ time.sleep(sleep_for)
+ continue
+
+ # gbt
+ tmpl = json.loads(args.bcli("getblocktemplate", '{"rules":["signet","segwit"]}'))
+ if tmpl["previousblockhash"] != bci["bestblockhash"]:
+ logging.warning("GBT based off unexpected block (%s not %s), retrying", tmpl["previousblockhash"], bci["bestblockhash"])
+ time.sleep(1)
+ continue
+
+ logging.debug("GBT template: %s", tmpl)
+
+ if tmpl["mintime"] > mine_time:
+ logging.info("Updating block time from %d to %d", mine_time, tmpl["mintime"])
+ mine_time = tmpl["mintime"]
+ if mine_time > now:
+ logging.error("GBT mintime is in the future: %d is %d seconds later than %d", mine_time, (mine_time-now), now)
+ return 1
+
+ # address for reward
+ reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"])
+
+ # mine block
+ logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(mine_time-bestheader["time"]), mine_time, is_mine)
+ mined_blocks += 1
+ psbt = generate_psbt(tmpl, reward_spk, blocktime=mine_time)
+ psbt_signed = json.loads(args.bcli("-stdin", "walletprocesspsbt", input=psbt.encode('utf8')))
+ if not psbt_signed.get("complete",False):
+ logging.debug("Generated PSBT: %s" % (psbt,))
+ sys.stderr.write("PSBT signing failed")
+ return 1
+ block, signet_solution = do_decode_psbt(psbt_signed["psbt"])
+ block = finish_block(block, signet_solution, args.grind_cmd)
+
+ # submit block
+ r = args.bcli("-stdin", "submitblock", input=ToHex(block).encode('utf8'))
+
+ # report
+ bstr = "block" if is_mine else "backup block"
+
+ next_delta = next_block_delta(block.nBits, block.hash, ultimate_target, args.poisson)
+ next_delta += block.nTime - time.time()
+ next_is_mine = next_block_is_mine(block.hash, my_blocks)
+
+ logging.debug("Block hash %s payout to %s", block.hash, reward_addr)
+ logging.info("Mined %s at height %d; next in %s (%s)", bstr, tmpl["height"], seconds_to_hms(next_delta), ("mine" if next_is_mine else "backup"))
+ if r != "":
+ logging.warning("submitblock returned %s for height %d hash %s", r, tmpl["height"], block.hash)
+ lastheader = block.hash
+
+def do_calibrate(args):
+ if args.nbits is not None and args.seconds is not None:
+ sys.stderr.write("Can only specify one of --nbits or --seconds\n")
+ return 1
+ if args.nbits is not None and len(args.nbits) != 8:
+ sys.stderr.write("Must specify 8 hex digits for --nbits")
+ return 1
+
+ TRIALS = 600 # gets variance down pretty low
+ TRIAL_BITS = 0x1e3ea75f # takes about 5m to do 600 trials
+ #TRIAL_BITS = 0x1e7ea75f # XXX
+
+ header = CBlockHeader()
+ header.nBits = TRIAL_BITS
+ targ = nbits_to_target(header.nBits)
+
+ start = time.time()
+ count = 0
+ #CHECKS=[]
+ for i in range(TRIALS):
+ header.nTime = i
+ header.nNonce = 0
+ headhex = header.serialize().hex()
+ cmd = args.grind_cmd.split(" ") + [headhex]
+ newheadhex = subprocess.run(cmd, stdout=subprocess.PIPE, input=b"", check=True).stdout.strip()
+ #newhead = FromHex(CBlockHeader(), newheadhex.decode('utf8'))
+ #count += newhead.nNonce
+ #if (i+1) % 100 == 0:
+ # CHECKS.append((i+1, count, time.time()-start))
+
+ #print("checks =", [c*1.0 / (b*targ*2**-256) for _,b,c in CHECKS])
+
+ avg = (time.time() - start) * 1.0 / TRIALS
+ #exp_count = 2**256 / targ * TRIALS
+ #print("avg =", avg, "count =", count, "exp_count =", exp_count)
+
+ if args.nbits is not None:
+ want_targ = nbits_to_target(int(args.nbits,16))
+ want_time = avg*targ/want_targ
+ else:
+ want_time = args.seconds if args.seconds is not None else 25
+ want_targ = int(targ*(avg/want_time))
+
+ print("nbits=%08x for %ds average mining time" % (target_to_nbits(want_targ), want_time))
+ return 0
+
+def bitcoin_cli(basecmd, args, **kwargs):
+ cmd = basecmd + ["-signet"] + args
+ logging.debug("Calling bitcoin-cli: %r", cmd)
+ out = subprocess.run(cmd, stdout=subprocess.PIPE, **kwargs, check=True).stdout
+ if isinstance(out, bytes):
+ out = out.decode('utf8')
+ return out.strip()
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--cli", default="bitcoin-cli", type=str, help="bitcoin-cli command")
+ parser.add_argument("--debug", action="store_true", help="Print debugging info")
+ parser.add_argument("--quiet", action="store_true", help="Only print warnings/errors")
+
+ cmds = parser.add_subparsers(help="sub-commands")
+ genpsbt = cmds.add_parser("genpsbt", help="Generate a block PSBT for signing")
+ genpsbt.set_defaults(fn=do_genpsbt)
+
+ solvepsbt = cmds.add_parser("solvepsbt", help="Solve a signed block PSBT")
+ solvepsbt.set_defaults(fn=do_solvepsbt)
+
+ generate = cmds.add_parser("generate", help="Mine blocks")
+ generate.set_defaults(fn=do_generate)
+ generate.add_argument("--ongoing", action="store_true", help="Keep mining blocks")
+ generate.add_argument("--max-blocks", default=None, type=int, help="Max blocks to mine (default=1)")
+ generate.add_argument("--set-block-time", default=None, type=int, help="Set block time (unix timestamp)")
+ generate.add_argument("--nbits", default=None, type=str, help="Target nBits (specify difficulty)")
+ generate.add_argument("--min-nbits", action="store_true", help="Target minimum nBits (use min difficulty)")
+ generate.add_argument("--poisson", action="store_true", help="Simulate randomised block times")
+ #generate.add_argument("--signcmd", default=None, type=str, help="Alternative signing command")
+ generate.add_argument("--multiminer", default=None, type=str, help="Specify which set of blocks to mine (eg: 1-40/100 for the first 40%%, 2/3 for the second 3rd)")
+ generate.add_argument("--backup-delay", default=300, type=int, help="Seconds to delay before mining blocks reserved for other miners (default=300)")
+ generate.add_argument("--standby-delay", default=0, type=int, help="Seconds to delay before mining blocks (default=0)")
+
+ calibrate = cmds.add_parser("calibrate", help="Calibrate difficulty")
+ calibrate.set_defaults(fn=do_calibrate)
+ calibrate.add_argument("--nbits", type=str, default=None)
+ calibrate.add_argument("--seconds", type=int, default=None)
+
+ for sp in [genpsbt, generate]:
+ sp.add_argument("--address", default=None, type=str, help="Address for block reward payment")
+ sp.add_argument("--descriptor", default=None, type=str, help="Descriptor for block reward payment")
+
+ for sp in [solvepsbt, generate, calibrate]:
+ sp.add_argument("--grind-cmd", default=None, type=str, help="Command to grind a block header for proof-of-work")
+
+ args = parser.parse_args(sys.argv[1:])
+
+ args.bcli = lambda *a, input=b"", **kwargs: bitcoin_cli(args.cli.split(" "), list(a), input=input, **kwargs)
+
+ if hasattr(args, "address") and hasattr(args, "descriptor"):
+ if args.address is None and args.descriptor is None:
+ sys.stderr.write("Must specify --address or --descriptor\n")
+ return 1
+ elif args.address is not None and args.descriptor is not None:
+ sys.stderr.write("Only specify one of --address or --descriptor\n")
+ return 1
+ args.derived_addresses = {}
+
+ if args.debug:
+ logging.getLogger().setLevel(logging.DEBUG)
+ elif args.quiet:
+ logging.getLogger().setLevel(logging.WARNING)
+ else:
+ logging.getLogger().setLevel(logging.INFO)
+
+ if hasattr(args, "fn"):
+ return args.fn(args)
+ else:
+ logging.error("Must specify command")
+ return 1
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/contrib/testgen/base58.py b/contrib/testgen/base58.py
index c7ebac50d4..87341ccf96 100644
--- a/contrib/testgen/base58.py
+++ b/contrib/testgen/base58.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2018 The Bitcoin Core developers
+# Copyright (c) 2012-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
diff --git a/contrib/testgen/gen_key_io_test_vectors.py b/contrib/testgen/gen_key_io_test_vectors.py
index 49320d92e6..8a3918da6b 100755
--- a/contrib/testgen/gen_key_io_test_vectors.py
+++ b/contrib/testgen/gen_key_io_test_vectors.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2012-2018 The Bitcoin Core developers
+# Copyright (c) 2012-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py
index 8b8503331d..9cb887e2dc 100755
--- a/contrib/zmq/zmq_sub.py
+++ b/contrib/zmq/zmq_sub.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/depends/Makefile b/depends/Makefile
index 1ad21f6821..596a46d4a2 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -37,6 +37,7 @@ NO_QR ?=
NO_WALLET ?=
NO_ZMQ ?=
NO_UPNP ?=
+NO_NATPMP ?=
MULTIPROCESS ?=
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
@@ -126,6 +127,8 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null)
$(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null)
ifneq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
+# Make sure that cache is invalidated when switching between system and
+# depends-managed, pinned clang
build_id_string+=system_clang
$(host_arch)_$(host_os)_id_string+=system_clang
endif
@@ -139,10 +142,12 @@ sqlite_packages_$(NO_SQLITE) = $(sqlite_packages)
wallet_packages_$(NO_WALLET) = $(bdb_packages_) $(sqlite_packages_)
upnp_packages_$(NO_UPNP) = $(upnp_packages)
+natpmp_packages_$(NO_NATPMP) = $(natpmp_packages)
+
zmq_packages_$(NO_ZMQ) = $(zmq_packages)
multiprocess_packages_$(MULTIPROCESS) = $(multiprocess_packages)
-packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_)
+packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) $(natpmp_packages_)
native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages)
ifneq ($(zmq_packages_),)
@@ -163,12 +168,6 @@ $(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain)
include funcs.mk
-binutils_path=$($($(host_arch)_$(host_os)_native_binutils)_prefixbin)
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-toolchain_path=$($($(host_arch)_$(host_os)_native_toolchain)_prefixbin)
-else
-toolchain_path=
-endif
final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in)
final_build_id+=$(shell echo -n "$(final_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))
$(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages)
@@ -179,15 +178,39 @@ $(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages)
$(AT)cd $(@D); $(foreach package,$^, tar xf $($(package)_cached); )
$(AT)touch $@
+# $PATH is not preserved between ./configure and make by convention. Its
+# modification and overriding at ./configure time is (as I understand it)
+# supposed to be captured by the AC_{PROG_{,OBJ}CXX,PATH_{PROG,TOOL}} macros,
+# which will expand the program names to their full absolute paths. The notable
+# exception is command line overriding: ./configure CC=clang, which skips the
+# program name expansion step, and works because the user implicitly indicates
+# with CC=clang that clang will be available in $PATH at all times, and is most
+# likely part of the user's system.
+#
+# Therefore, when we "seed the autoconf cache"/"override well-known program
+# vars" by setting AR=<blah> in our config.site, either one of two things needs
+# to be true for the build system to work correctly:
+#
+# 1. If we refer to the program by name (e.g. AR=riscv64-gnu-linux-ar), the
+# tool needs to be available in $PATH at all times.
+#
+# 2. If the tool is _**not**_ expected to be available in $PATH at all times
+# (such as is the case for our native_cctools binutils tools), it needs to
+# be referred to by its absolute path, such as would be output by the
+# AC_PATH_{PROG,TOOL} macros.
+#
+# Minor note: it is also okay to refer to tools by their absolute path even if
+# we expect them to be available in $PATH at all times, more specificity does
+# not hurt.
$(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_build_id)
$(AT)@mkdir -p $(@D)
$(AT)sed -e 's|@HOST@|$(host)|' \
- -e 's|@CC@|$(toolchain_path)$(host_CC)|' \
- -e 's|@CXX@|$(toolchain_path)$(host_CXX)|' \
- -e 's|@AR@|$(binutils_path)$(host_AR)|' \
- -e 's|@RANLIB@|$(binutils_path)$(host_RANLIB)|' \
- -e 's|@NM@|$(binutils_path)$(host_NM)|' \
- -e 's|@STRIP@|$(binutils_path)$(host_STRIP)|' \
+ -e 's|@CC@|$(host_CC)|' \
+ -e 's|@CXX@|$(host_CXX)|' \
+ -e 's|@AR@|$(host_AR)|' \
+ -e 's|@RANLIB@|$(host_RANLIB)|' \
+ -e 's|@NM@|$(host_NM)|' \
+ -e 's|@STRIP@|$(host_STRIP)|' \
-e 's|@build_os@|$(build_os)|' \
-e 's|@host_os@|$(host_os)|' \
-e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \
@@ -200,6 +223,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@no_zmq@|$(NO_ZMQ)|' \
-e 's|@no_wallet@|$(NO_WALLET)|' \
-e 's|@no_upnp@|$(NO_UPNP)|' \
+ -e 's|@no_natpmp@|$(NO_NATPMP)|' \
-e 's|@multiprocess@|$(MULTIPROCESS)|' \
-e 's|@debug@|$(DEBUG)|' \
$< > $@
diff --git a/depends/README.md b/depends/README.md
index bf8f829848..9e9878c595 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -44,7 +44,7 @@ The paths are automatically configured and no other options are needed unless ta
#### For macOS cross compilation
- sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools libtinfo5
+ sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools libtinfo5 xorriso
#### For Win64 cross compilation
@@ -80,48 +80,31 @@ For linux S390X cross compilation:
sudo apt-get install g++-s390x-linux-gnu binutils-s390x-linux-gnu
### Dependency Options
+
The following can be set when running make: `make FOO=bar`
-<dl>
-<dt>SOURCES_PATH</dt>
-<dd>downloaded sources will be placed here</dd>
-<dt>BASE_CACHE</dt>
-<dd>built packages will be placed here</dd>
-<dt>SDK_PATH</dt>
-<dd>Path where sdk's can be found (used by macOS)</dd>
-<dt>FALLBACK_DOWNLOAD_PATH</dt>
-<dd>If a source file can't be fetched, try here before giving up</dd>
-<dt>NO_QT</dt>
-<dd>Don't download/build/cache qt and its dependencies</dd>
-<dt>NO_QR</dt>
-<dd>Don't download/build/cache packages needed for enabling qrencode</dd>
-<dt>NO_ZMQ</dt>
-<dd>Don't download/build/cache packages needed for enabling zeromq</dd>
-<dt>NO_WALLET</dt>
-<dd>Don't download/build/cache libs needed to enable the wallet</dd>
-<dt>NO_BDB</dt>
-<dd>Don't download/build/cache BerkeleyDB</dd>
-<dt>NO_SQLITE</dt>
-<dd>Don't download/build/cache SQLite</dd>
-<dt>NO_UPNP</dt>
-<dd>Don't download/build/cache packages needed for enabling upnp</dd>
-<dt>ALLOW_HOST_PACKAGES</dt>
-<dd>Packages that are missed in dependencies (due to `NO_*` option or
-build script logic) are searched for among the host system packages using
-`pkg-config`. It allows building with packages of other (newer) versions</dd>
-<dt>MULTIPROCESS</dt>
-<dd>build libmultiprocess (experimental, requires cmake)</dd>
-<dt>DEBUG</dt>
-<dd>disable some optimizations and enable more runtime checking</dd>
-<dt>HOST_ID_SALT</dt>
-<dd>Optional salt to use when generating host package ids</dd>
-<dt>BUILD_ID_SALT</dt>
-<dd>Optional salt to use when generating build package ids</dd>
-<dt>FORCE_USE_SYSTEM_CLANG</dt>
-<dd>(EXPERTS ONLY) When cross-compiling for macOS, use Clang found in the
-system's <code>$PATH</code> rather than the default prebuilt release of Clang
-from llvm.org. Clang 8 or later is required.</dd>
-</dl>
+- `SOURCES_PATH`: Downloaded sources will be placed here
+- `BASE_CACHE`: Built packages will be placed here
+- `SDK_PATH`: Path where SDKs can be found (used by macOS)
+- `FALLBACK_DOWNLOAD_PATH`: If a source file can't be fetched, try here before giving up
+- `NO_QT`: Don't download/build/cache Qt and its dependencies
+- `NO_QR`: Don't download/build/cache packages needed for enabling qrencode
+- `NO_ZMQ`: Don't download/build/cache packages needed for enabling ZeroMQ
+- `NO_WALLET`: Don't download/build/cache libs needed to enable the wallet
+- `NO_BDB`: Don't download/build/cache BerkeleyDB
+- `NO_SQLITE`: Don't download/build/cache SQLite
+- `NO_UPNP`: Don't download/build/cache packages needed for enabling UPnP
+- `NO_NATPMP`: Don't download/build/cache packages needed for enabling NAT-PMP</dd>
+- `ALLOW_HOST_PACKAGES`: Packages that are missed in dependencies (due to `NO_*` option or
+ build script logic) are searched for among the host system packages using
+ `pkg-config`. It allows building with packages of other (newer) versions
+- `MULTIPROCESS`: Build libmultiprocess (experimental, requires CMake)
+- `DEBUG`: Disable some optimizations and enable more runtime checking
+- `HOST_ID_SALT`: Optional salt to use when generating host package ids
+- `BUILD_ID_SALT`: Optional salt to use when generating build package ids
+- `FORCE_USE_SYSTEM_CLANG`: (EXPERTS ONLY) When cross-compiling for macOS, use Clang found in the
+ system's `$PATH` rather than the default prebuilt release of Clang
+ from llvm.org. Clang 8 or later is required.
If some packages are not built, for example `make NO_WALLET=1`, the appropriate
options will be passed to bitcoin's configure. In this case, `--disable-wallet`.
diff --git a/depends/config.site.in b/depends/config.site.in
index f4531830c8..391767357a 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -8,70 +8,74 @@ true # Dummy command because shellcheck treats all directives before first
# See: https://github.com/koalaman/shellcheck/wiki/Directive
# shellcheck disable=SC2154
-depends_prefix="$(cd "$(dirname ${ac_site_file})/.." && pwd)"
+depends_prefix="$(cd "$(dirname "$ac_site_file")/.." && pwd)"
cross_compiling=maybe
-host_alias=@HOST@
-ac_tool_prefix=${host_alias}-
+host_alias="@HOST@"
+ac_tool_prefix="${host_alias}-"
-if test -z $with_boost; then
- with_boost=$depends_prefix
+if test -z "$with_boost"; then
+ with_boost="$depends_prefix"
fi
-if test -z $with_qt_plugindir; then
- with_qt_plugindir=$depends_prefix/plugins
+if test -z "$with_qt_plugindir"; then
+ with_qt_plugindir="${depends_prefix}/plugins"
fi
-if test -z $with_qt_translationdir; then
- with_qt_translationdir=$depends_prefix/translations
+if test -z "$with_qt_translationdir"; then
+ with_qt_translationdir="${depends_prefix}/translations"
fi
-if test -z $with_qt_bindir && test -z "@no_qt@"; then
- with_qt_bindir=$depends_prefix/native/bin
+if test -z "$with_qt_bindir" && test -z "@no_qt@"; then
+ with_qt_bindir="${depends_prefix}/native/bin"
fi
-if test -z $with_mpgen && test -n "@multiprocess@"; then
- with_mpgen=$depends_prefix/native
+if test -z "$with_mpgen" && test -n "@multiprocess@"; then
+ with_mpgen="${depends_prefix}/native"
fi
-if test -z $with_qrencode && test -n "@no_qr@"; then
+if test -z "$with_qrencode" && test -n "@no_qr@"; then
with_qrencode=no
fi
-if test -z $enable_wallet && test -n "@no_wallet@"; then
+if test -z "$enable_wallet" && test -n "@no_wallet@"; then
enable_wallet=no
fi
-if test -z $enable_multiprocess && test -n "@multiprocess@"; then
+if test -z "$enable_multiprocess" && test -n "@multiprocess@"; then
enable_multiprocess=yes
fi
-if test -z $with_miniupnpc && test -n "@no_upnp@"; then
+if test -z "$with_miniupnpc" && test -n "@no_upnp@"; then
with_miniupnpc=no
fi
-if test -z $with_gui && test -n "@no_qt@"; then
+if test -z "$with_natpmp" && test -n "@no_natpmp@"; then
+ with_natpmp=no
+fi
+
+if test -z "$with_gui" && test -n "@no_qt@"; then
with_gui=no
fi
-if test -z $enable_zmq && test -n "@no_zmq@"; then
+if test -z "$enable_zmq" && test -n "@no_zmq@"; then
enable_zmq=no
fi
-if test x@host_os@ = xdarwin; then
+if test "x@host_os@" = xdarwin; then
BREW=no
PORT=no
fi
-PATH=$depends_prefix/native/bin:$PATH
+PATH="${depends_prefix}/native/bin:${PATH}"
PKG_CONFIG="$(which pkg-config) --static"
# These two need to remain exported because pkg-config does not see them
# otherwise. That means they must be unexported at the end of configure.ac to
# avoid ruining the cache. Sigh.
-export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig
+export PKG_CONFIG_PATH="${depends_prefix}/share/pkgconfig:${depends_prefix}/lib/pkgconfig"
if test -z "@allow_host_packages@"; then
- export PKG_CONFIG_LIBDIR=$depends_prefix/lib/pkgconfig
+ export PKG_CONFIG_LIBDIR="${depends_prefix}/lib/pkgconfig"
fi
-CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS"
-LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
+CPPFLAGS="-I${depends_prefix}/include/ ${CPPFLAGS}"
+LDFLAGS="-L${depends_prefix}/lib ${LDFLAGS}"
if test -n "@CC@" -a -z "${CC}"; then
CC="@CC@"
@@ -82,18 +86,18 @@ fi
PYTHONPATH="${depends_prefix}/native/lib/python3/dist-packages${PYTHONPATH:+${PATH_SEPARATOR}}${PYTHONPATH}"
if test -n "@AR@"; then
- AR=@AR@
- ac_cv_path_ac_pt_AR=${AR}
+ AR="@AR@"
+ ac_cv_path_ac_pt_AR="${AR}"
fi
if test -n "@RANLIB@"; then
- RANLIB=@RANLIB@
- ac_cv_path_ac_pt_RANLIB=${RANLIB}
+ RANLIB="@RANLIB@"
+ ac_cv_path_ac_pt_RANLIB="${RANLIB}"
fi
if test -n "@NM@"; then
- NM=@NM@
- ac_cv_path_ac_pt_NM=${NM}
+ NM="@NM@"
+ ac_cv_path_ac_pt_NM="${NM}"
fi
if test -n "@debug@"; then
@@ -101,14 +105,14 @@ if test -n "@debug@"; then
fi
if test -n "@CFLAGS@"; then
- CFLAGS="@CFLAGS@ $CFLAGS"
+ CFLAGS="@CFLAGS@ ${CFLAGS}"
fi
if test -n "@CXXFLAGS@"; then
- CXXFLAGS="@CXXFLAGS@ $CXXFLAGS"
+ CXXFLAGS="@CXXFLAGS@ ${CXXFLAGS}"
fi
if test -n "@CPPFLAGS@"; then
- CPPFLAGS="@CPPFLAGS@ $CPPFLAGS"
+ CPPFLAGS="@CPPFLAGS@ ${CPPFLAGS}"
fi
if test -n "@LDFLAGS@"; then
- LDFLAGS="@LDFLAGS@ $LDFLAGS"
+ LDFLAGS="@LDFLAGS@ ${LDFLAGS}"
fi
diff --git a/depends/funcs.mk b/depends/funcs.mk
index 5697bd6f15..c0159f0e38 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -1,17 +1,23 @@
define int_vars
#Set defaults for vars which may be overridden per-package
-$(1)_cc=$($($(1)_type)_CC)
-$(1)_cxx=$($($(1)_type)_CXX)
-$(1)_objc=$($($(1)_type)_OBJC)
-$(1)_objcxx=$($($(1)_type)_OBJCXX)
-$(1)_ar=$($($(1)_type)_AR)
-$(1)_ranlib=$($($(1)_type)_RANLIB)
-$(1)_libtool=$($($(1)_type)_LIBTOOL)
-$(1)_nm=$($($(1)_type)_NM)
-$(1)_cflags=$($($(1)_type)_CFLAGS) $($($(1)_type)_$(release_type)_CFLAGS)
-$(1)_cxxflags=$($($(1)_type)_CXXFLAGS) $($($(1)_type)_$(release_type)_CXXFLAGS)
-$(1)_ldflags=$($($(1)_type)_LDFLAGS) $($($(1)_type)_$(release_type)_LDFLAGS) -L$($($(1)_type)_prefix)/lib
-$(1)_cppflags=$($($(1)_type)_CPPFLAGS) $($($(1)_type)_$(release_type)_CPPFLAGS) -I$($($(1)_type)_prefix)/include
+$(1)_cc=$$($$($(1)_type)_CC)
+$(1)_cxx=$$($$($(1)_type)_CXX)
+$(1)_objc=$$($$($(1)_type)_OBJC)
+$(1)_objcxx=$$($$($(1)_type)_OBJCXX)
+$(1)_ar=$$($$($(1)_type)_AR)
+$(1)_ranlib=$$($$($(1)_type)_RANLIB)
+$(1)_libtool=$$($$($(1)_type)_LIBTOOL)
+$(1)_nm=$$($$($(1)_type)_NM)
+$(1)_cflags=$$($$($(1)_type)_CFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_CFLAGS)
+$(1)_cxxflags=$$($$($(1)_type)_CXXFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_CXXFLAGS)
+$(1)_ldflags=$$($$($(1)_type)_LDFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_LDFLAGS) \
+ -L$$($($(1)_type)_prefix)/lib
+$(1)_cppflags=$$($$($(1)_type)_CPPFLAGS) \
+ $$($$($(1)_type)_$$(release_type)_CPPFLAGS) \
+ -I$$($$($(1)_type)_prefix)/include
$(1)_recipe_hash:=
endef
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk
index e9faeba336..646e97837a 100644
--- a/depends/hosts/darwin.mk
+++ b/depends/hosts/darwin.mk
@@ -6,6 +6,49 @@ LD64_VERSION=530
OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-libcxx-headers
+darwin_native_binutils=native_cctools
+
+ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
+# FORCE_USE_SYSTEM_CLANG is empty, so we use our depends-managed, pinned clang
+# from llvm.org
+
+# The native_cctools package is what provides clang when FORCE_USE_SYSTEM_CLANG
+# is empty
+darwin_native_toolchain=native_cctools
+
+clang_prog=$(build_prefix)/bin/clang
+clangxx_prog=$(clang_prog)++
+
+clang_resource_dir=$(build_prefix)/lib/clang/$(native_cctools_clang_version)
+else
+# FORCE_USE_SYSTEM_CLANG is non-empty, so we use the clang from the user's
+# system
+
+darwin_native_toolchain=
+
+# We can't just use $(shell command -v clang) because GNU Make handles builtins
+# in a special way and doesn't know that `command` is a POSIX-standard builtin
+# prior to 1af314465e5dfe3e8baa839a32a72e83c04f26ef, first released in v4.2.90.
+# At the time of writing, GNU Make v4.2.1 is still being used in supported
+# distro releases.
+#
+# Source: https://lists.gnu.org/archive/html/bug-make/2017-11/msg00017.html
+clang_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang")
+clangxx_prog=$(shell $(SHELL) $(.SHELLFLAGS) "command -v clang++")
+
+clang_resource_dir=$(shell clang -print-resource-dir)
+endif
+
+cctools_TOOLS=AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL
+
+# Make-only lowercase function
+lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
+
+# For well-known tools provided by cctools, make sure that their well-known
+# variable is set to the full path of the tool, just like how AC_PATH_{TOO,PROG}
+# would.
+$(foreach TOOL,$(cctools_TOOLS),$(eval darwin_$(TOOL) = $$(build_prefix)/bin/$$(host)-$(call lc,$(TOOL))))
+
# Flag explanations:
#
# -mlinker-version
@@ -18,7 +61,7 @@ OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-
# Explicitly point to our binaries (e.g. cctools) so that they are
# ensured to be found and preferred over other possibilities.
#
-# -nostdinc++ -isystem $(OSX_SDK)/usr/include/c++/v1
+# -stdlib=libc++ -nostdinc++ -Xclang -cxx-isystem$(OSX_SDK)/usr/include/c++/v1
#
# Forces clang to use the libc++ headers from our SDK and completely
# forget about the libc++ headers from the standard directories
@@ -28,8 +71,49 @@ OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-
# https://reviews.llvm.org/D64089, we should use that instead. Read the
# differential summary there for more details.
#
-darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -B$(build_prefix)/bin
-darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -stdlib=libc++ -mlinker-version=$(LD64_VERSION) -B$(build_prefix)/bin -nostdinc++ -isystem $(OSX_SDK)/usr/include/c++/v1
+# -Xclang -*system<path_a> \
+# -Xclang -*system<path_b> \
+# -Xclang -*system<path_c> ...
+#
+# Adds path_a, path_b, and path_c to the bottom of clang's list of
+# include search paths. This is used to explicitly specify the list of
+# system include search paths and its ordering, rather than rely on
+# clang's autodetection routine. This routine has been shown to:
+# 1. Fail to pickup libc++ headers in $SYSROOT/usr/include/c++/v1
+# when clang was built manually (see: https://github.com/bitcoin/bitcoin/pull/17919#issuecomment-656785034)
+# 2. Fail to pickup C headers in $SYSROOT/usr/include when
+# C_INCLUDE_DIRS was specified at configure time (see: https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9)
+#
+# Talking directly to cc1 with -Xclang here grants us access to specify
+# more granular categories for these system include search paths, and we
+# can use the correct categories that these search paths would have been
+# placed in if the autodetection routine had worked correctly. (see:
+# https://gist.github.com/dongcarl/5cdc6990b7599e8a5bf6d2a9c70e82f9#the-treatment)
+#
+# Furthermore, it places these search paths after any "non-Xclang"
+# specified search paths. This prevents any additional clang options or
+# environment variables from coming after or in between these system
+# include search paths, as that would be wrong in general but would also
+# break #include_next's.
+#
+darwin_CC=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
+ -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
+ -u LIBRARY_PATH \
+ $(clang_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
+ -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
+ --sysroot=$(OSX_SDK) \
+ -Xclang -internal-externc-isystem$(clang_resource_dir)/include \
+ -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include
+darwin_CXX=env -u C_INCLUDE_PATH -u CPLUS_INCLUDE_PATH \
+ -u OBJC_INCLUDE_PATH -u OBJCPLUS_INCLUDE_PATH -u CPATH \
+ -u LIBRARY_PATH \
+ $(clangxx_prog) --target=$(host) -mmacosx-version-min=$(OSX_MIN_VERSION) \
+ -B$(build_prefix)/bin -mlinker-version=$(LD64_VERSION) \
+ --sysroot=$(OSX_SDK) \
+ -stdlib=libc++ -nostdinc++ \
+ -Xclang -cxx-isystem$(OSX_SDK)/usr/include/c++/v1 \
+ -Xclang -internal-externc-isystem$(clang_resource_dir)/include \
+ -Xclang -internal-externc-isystem$(OSX_SDK)/usr/include
darwin_CFLAGS=-pipe
darwin_CXXFLAGS=$(darwin_CFLAGS)
@@ -40,11 +124,4 @@ darwin_release_CXXFLAGS=$(darwin_release_CFLAGS)
darwin_debug_CFLAGS=-O1
darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS)
-darwin_native_binutils=native_cctools
-ifeq ($(strip $(FORCE_USE_SYSTEM_CLANG)),)
-darwin_native_toolchain=native_cctools
-else
-darwin_native_toolchain=
-endif
-
darwin_cmake_system=Darwin
diff --git a/depends/packages/libnatpmp.mk b/depends/packages/libnatpmp.mk
new file mode 100644
index 0000000000..a24f201859
--- /dev/null
+++ b/depends/packages/libnatpmp.mk
@@ -0,0 +1,19 @@
+package=libnatpmp
+$(package)_version=20150609
+$(package)_download_path=https://miniupnp.tuxfamily.org/files/
+$(package)_file_name=$(package)-$($(package)_version).tar.gz
+$(package)_sha256_hash=e1aa9c4c4219bc06943d6b2130f664daee213fb262fcb94dd355815b8f4536b0
+
+define $(package)_set_vars
+ $(package)_build_opts=CC="$($(package)_cc)"
+endef
+
+define $(package)_build_cmds
+ $(MAKE) libnatpmp.a $($(package)_build_opts)
+endef
+
+define $(package)_stage_cmds
+ mkdir -p $($(package)_staging_prefix_dir)/include $($(package)_staging_prefix_dir)/lib &&\
+ install *.h $($(package)_staging_prefix_dir)/include &&\
+ install libnatpmp.a $($(package)_staging_prefix_dir)/lib
+endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index d4fd23a47b..0f35ca0d2d 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -16,6 +16,7 @@ sqlite_packages=sqlite
zmq_packages=zeromq
upnp_packages=miniupnpc
+natpmp_packages=libnatpmp
multiprocess_packages = libmultiprocess capnp
multiprocess_native_packages = native_libmultiprocess native_capnp
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index bf34835e1a..7d122ea5f9 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -6,7 +6,6 @@ $(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=9b9dec1f67df1f94bce2955c5604de992d529dde72050239154c56352da0907d
$(package)_dependencies=zlib
$(package)_linux_dependencies=freetype fontconfig libxcb
-$(package)_build_subdir=qtbase
$(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_patches=fix_qt_pkgconfig.patch mac-qmake.conf fix_configure_mac.patch fix_no_printer.patch
$(package)_patches+= fix_rcc_determinism.patch fix_riscv64_arch.patch xkb-default.patch no-xlib.patch
@@ -218,7 +217,7 @@ endef
#
# 7. In clang.conf, swap out clang & clang++, for our compiler + flags. See #17466.
#
-# 8. Adjust a regex in toolchain.prf, to accomodate Guix's usage of
+# 8. Adjust a regex in toolchain.prf, to accommodate Guix's usage of
# CROSS_LIBRARY_PATH. See #15277.
define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/freetype_back_compat.patch && \
@@ -257,25 +256,27 @@ define $(package)_config_cmds
export PKG_CONFIG_SYSROOT_DIR=/ && \
export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
+ cd qtbase && \
./configure $($(package)_config_opts) && \
echo "host_build: QT_CONFIG ~= s/system-zlib/zlib" >> mkspecs/qconfig.pri && \
echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \
- $(MAKE) sub-src-clean && \
- cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \
- cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. && \
- cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile && \
- cd ../lupdate/ && ../../../../qtbase/bin/qmake lupdate.pro -o Makefile && cd ../../../..
+ cd .. && \
+ $(MAKE) -C qtbase sub-src-clean && \
+ qtbase/bin/qmake -o qttranslations/Makefile qttranslations/qttranslations.pro && \
+ qtbase/bin/qmake -o qttranslations/translations/Makefile qttranslations/translations/translations.pro && \
+ qtbase/bin/qmake -o qttools/src/linguist/lrelease/Makefile qttools/src/linguist/lrelease/lrelease.pro && \
+ qtbase/bin/qmake -o qttools/src/linguist/lupdate/Makefile qttools/src/linguist/lupdate/lupdate.pro
endef
define $(package)_build_cmds
- $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \
- $(MAKE) -C ../qttools/src/linguist/lrelease && \
- $(MAKE) -C ../qttools/src/linguist/lupdate && \
- $(MAKE) -C ../qttranslations
+ $(MAKE) -C qtbase/src $(addprefix sub-,$($(package)_qt_libs)) && \
+ $(MAKE) -C qttools/src/linguist/lrelease && \
+ $(MAKE) -C qttools/src/linguist/lupdate && \
+ $(MAKE) -C qttranslations
endef
define $(package)_stage_cmds
- $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. && \
+ $(MAKE) -C qtbase/src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && \
$(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \
$(MAKE) -C qttools/src/linguist/lupdate INSTALL_ROOT=$($(package)_staging_dir) install_target && \
$(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets
diff --git a/depends/patches/fontconfig/gperf_header_regen.patch b/depends/patches/fontconfig/gperf_header_regen.patch
index 7401b83d84..3ffd1674e0 100644
--- a/depends/patches/fontconfig/gperf_header_regen.patch
+++ b/depends/patches/fontconfig/gperf_header_regen.patch
@@ -2,7 +2,7 @@ commit 7b6eb33ecd88768b28c67ce5d2d68a7eed5936b6
Author: fanquake <fanquake@gmail.com>
Date: Tue Aug 25 14:34:53 2020 +0800
- Remove rule that causes inadvertant header regeneration
+ Remove rule that causes inadvertent header regeneration
Otherwise the makefile will needlessly attempt to re-generate the
headers with gperf. This can be dropped once the upstream build is fixed.
diff --git a/depends/patches/native_cctools/ld64_disable_threading.patch b/depends/patches/native_cctools/ld64_disable_threading.patch
index d6c58c102f..2de6874cd4 100644
--- a/depends/patches/native_cctools/ld64_disable_threading.patch
+++ b/depends/patches/native_cctools/ld64_disable_threading.patch
@@ -8,7 +8,7 @@ Date: Tue Aug 18 01:20:24 2020 +0000
differently based on which files have already been parsed. This is more
likely to occur on systems with more CPUs.
- Just disable threading for now. There is no noticable slowdown.
+ Just disable threading for now. There is no noticeable slowdown.
See #9891.
diff --git a/depends/patches/qt/freetype_back_compat.patch b/depends/patches/qt/freetype_back_compat.patch
index b0f1c98aa6..1ca55f1ce3 100644
--- a/depends/patches/qt/freetype_back_compat.patch
+++ b/depends/patches/qt/freetype_back_compat.patch
@@ -9,7 +9,7 @@ Date: Tue Aug 18 15:15:08 2020 +0800
backwards-compatibility.
Qt 5.9 introduced a call to FT_Get_Font_Format(). Replace it with FT_Get_X11_Font_Format()
- in order to remain compatibile with older freetype, which is still used by e.g. Ubuntu Trusty.
+ in order to remain compatible with older freetype, which is still used by e.g. Ubuntu Trusty.
See #14348.
diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md
index c66e79af71..12807bfb86 100644
--- a/doc/JSON-RPC-interface.md
+++ b/doc/JSON-RPC-interface.md
@@ -88,13 +88,14 @@ RPC interface will be abused.
- **Secure string handling:** The RPC interface does not guarantee any
escaping of data beyond what's necessary to encode it as JSON,
although it does usually provide serialized data using a hex
- representation of the bytes. If you use RPC data in your programs or
- provide its data to other programs, you must ensure any problem
- strings are properly escaped. For example, multiple websites have
- been manipulated because they displayed decoded hex strings that
- included HTML `<script>` tags. For this reason, and other
- non-security reasons, it is recommended to display all serialized data
- in hex form only.
+ representation of the bytes. If you use RPC data in your programs or
+ provide its data to other programs, you must ensure any problem strings
+ are properly escaped. For example, the `createwallet` RPC accepts
+ arguments such as `wallet_name` which is a string and could be used
+ for a path traversal attack without application level checks. Multiple
+ websites have been manipulated because they displayed decoded hex strings
+ that included HTML `<script>` tags. For this reason, and others, it is
+ recommended to display all serialized data in hex form only.
## RPC consistency guarantees
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 3b127703b7..6237734390 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -4,7 +4,7 @@ Unauthenticated REST Interface
The REST API can be enabled with the `-rest` option.
The interface runs on the same port as the JSON-RPC interface, by default port 8332 for mainnet, port 18332 for testnet,
-and port 18443 for regtest.
+port 38332 for signet, and port 18443 for regtest.
REST Interface consistency guarantees
-------------------------------------
@@ -62,7 +62,7 @@ Given a height: returns hash of block in best-block-chain at height provided.
Returns various state info regarding block chain processing.
Only supports JSON as output format.
-* chain : (string) current network name (main, test, regtest)
+* chain : (string) current network name (main, test, signet, regtest)
* blocks : (numeric) the current number of blocks processed in the server
* headers : (numeric) the current number of headers we have validated
* bestblockhash : (string) the hash of the currently best block
diff --git a/doc/build-osx.md b/doc/build-osx.md
index c1d101fde1..04ee43f81d 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -19,7 +19,7 @@ Then install [Homebrew](https://brew.sh).
## Dependencies
```shell
-brew install automake libtool boost miniupnpc pkg-config python qt libevent qrencode
+brew install automake libtool boost miniupnpc libnatpmp pkg-config python qt libevent qrencode
```
If you run into issues, check [Homebrew's troubleshooting page](https://docs.brew.sh/Troubleshooting).
@@ -30,6 +30,11 @@ If you want to build the disk image with `make deploy` (.dmg / optional), you ne
brew install librsvg
```
+and [`macdeployqtplus`](../contrib/macdeploy/README.md) dependencies:
+```shell
+pip3 install ds_store mac_alias
+```
+
The wallet support requires one or both of the dependencies ([*SQLite*](#sqlite) and [*Berkeley DB*](#berkeley-db)) in the sections below.
To build Bitcoin Core without wallet, see [*Disable-wallet mode*](#disable-wallet-mode).
diff --git a/doc/build-unix.md b/doc/build-unix.md
index cfe3328b45..5c24886dbf 100644
--- a/doc/build-unix.md
+++ b/doc/build-unix.md
@@ -41,6 +41,7 @@ Optional dependencies:
Library | Purpose | Description
------------|------------------|----------------------
miniupnpc | UPnP Support | Firewall-jumping support
+ libnatpmp | NAT-PMP Support | Firewall-jumping support
libdb4.8 | Berkeley DB | Optional, wallet storage (only needed when wallet enabled)
qt | GUI | GUI toolkit (only needed when GUI enabled)
libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled)
@@ -99,9 +100,9 @@ SQLite is required for the wallet:
To build Bitcoin Core without wallet, see [*Disable-wallet mode*](/doc/build-unix.md#disable-wallet-mode)
-Optional (see `--with-miniupnpc` and `--enable-upnp-default`):
+Optional port mapping libraries (see: `--with-miniupnpc`, and `--enable-upnp-default`, `--with-natpmp`, `--enable-natpmp-default`):
- sudo apt-get install libminiupnpc-dev
+ sudo apt install libminiupnpc-dev libnatpmp-dev
ZMQ dependencies (provides ZMQ API):
@@ -133,9 +134,9 @@ Build requirements:
sudo dnf install gcc-c++ libtool make autoconf automake libevent-devel boost-devel libdb4-devel libdb4-cxx-devel python3
-Optional (see `--with-miniupnpc` and `--enable-upnp-default`):
+Optional port mapping libraries (see: `--with-miniupnpc`, and `--enable-upnp-default`, `--with-natpmp`, `--enable-natpmp-default`):
- sudo dnf install miniupnpc-devel
+ sudo dnf install miniupnpc-devel libnatpmp-devel
ZMQ dependencies (provides ZMQ API):
@@ -158,18 +159,27 @@ Notes
The release is built with GCC and then "strip bitcoind" to strip the debug
symbols, which reduces the executable size by about 90%.
-
miniupnpc
---------
[miniupnpc](https://miniupnp.tuxfamily.org) may be used for UPnP port mapping. It can be downloaded from [here](
https://miniupnp.tuxfamily.org/files/). UPnP support is compiled in and
-turned off by default. See the configure options for upnp behavior desired:
+turned off by default. See the configure options for UPnP behavior desired:
- --without-miniupnpc No UPnP support miniupnp not required
+ --without-miniupnpc No UPnP support, miniupnp not required
--disable-upnp-default (the default) UPnP support turned off by default at runtime
--enable-upnp-default UPnP support turned on by default at runtime
+libnatpmp
+---------
+
+[libnatpmp](https://miniupnp.tuxfamily.org/libnatpmp.html) may be used for NAT-PMP port mapping. It can be downloaded
+from [here](https://miniupnp.tuxfamily.org/files/). NAT-PMP support is compiled in and
+turned off by default. See the configure options for NAT-PMP behavior desired:
+
+ --without-natpmp No NAT-PMP support, libnatpmp not required
+ --disable-natpmp-default (the default) NAT-PMP support turned off by default at runtime
+ --enable-natpmp-default NAT-PMP support turned on by default at runtime
Berkeley DB
-----------
diff --git a/doc/dependencies.md b/doc/dependencies.md
index 76e8910871..6b2b904632 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -14,6 +14,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| GCC | | [7+](https://gcc.gnu.org/) (C++17 support) | | | |
| HarfBuzz-NG | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
| libevent | [2.1.11-stable](https://github.com/libevent/libevent/releases) | [2.0.21](https://github.com/bitcoin/bitcoin/pull/18676) | No | | |
+| libnatpmp | [20150609](https://miniupnp.tuxfamily.org/files) | | No | | |
| libpng | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk) |
| librsvg | | | | | |
| MiniUPnPc | [2.0.20180203](https://miniupnp.tuxfamily.org/files) | | No | | |
@@ -32,7 +33,8 @@ Controlling dependencies
Some dependencies are not needed in all configurations. The following are some factors that affect the dependency list.
#### Options passed to `./configure`
-* MiniUPnPc is not needed with `--with-miniupnpc=no`.
+* MiniUPnPc is not needed with `--without-miniupnpc`.
+* libnatpmp is not needed with `--without-natpmp`.
* Berkeley DB is not needed with `--disable-wallet` or `--without-bdb`.
* SQLite is not needed with `--disable-wallet` or `--without-sqlite`.
* Qt is not needed with `--without-gui`.
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 9cb416bb30..596f65cf10 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -14,7 +14,7 @@ Developer Notes
- [Compiling for debugging](#compiling-for-debugging)
- [Compiling for gprof profiling](#compiling-for-gprof-profiling)
- [`debug.log`](#debuglog)
- - [Testnet and Regtest modes](#testnet-and-regtest-modes)
+ - [Signet, testnet, and regtest modes](#signet-testnet-and-regtest-modes)
- [DEBUG_LOCKORDER](#debug_lockorder)
- [Valgrind suppressions file](#valgrind-suppressions-file)
- [Compiling for test coverage](#compiling-for-test-coverage)
@@ -135,7 +135,7 @@ Refer to [/test/functional/README.md#style-guidelines](/test/functional/README.m
Coding Style (Doxygen-compatible comments)
------------------------------------------
-Bitcoin Core uses [Doxygen](http://www.doxygen.nl/) to generate its official documentation.
+Bitcoin Core uses [Doxygen](https://www.doxygen.nl/) to generate its official documentation.
Use Doxygen-compatible comment blocks for functions, methods, and fields.
@@ -156,7 +156,7 @@ For example, to describe a function use:
bool function(int arg1, const char *arg2, std::string& arg3)
```
-A complete list of `@xxx` commands can be found at http://www.doxygen.nl/manual/commands.html.
+A complete list of `@xxx` commands can be found at https://www.doxygen.nl/manual/commands.html.
As Doxygen recognizes the comments by the delimiters (`/**` and `*/` in this case), you don't
*need* to provide any commands for a comment to be valid; just a description text is fine.
@@ -203,7 +203,7 @@ Also not picked up by Doxygen:
*/
```
-A full list of comment syntaxes picked up by Doxygen can be found at http://www.doxygen.nl/manual/docblocks.html,
+A full list of comment syntaxes picked up by Doxygen can be found at https://www.doxygen.nl/manual/docblocks.html,
but the above styles are favored.
Recommendations:
@@ -216,7 +216,7 @@ Recommendations:
- Backticks aren't required when referring to functions Doxygen already knows
about; it will build hyperlinks for these automatically. See
- http://www.doxygen.nl/manual/autolink.html for complete info.
+ https://www.doxygen.nl/manual/autolink.html for complete info.
- Avoid linking to external documentation; links can break.
@@ -259,14 +259,15 @@ on all categories (and give you a very large `debug.log` file).
The Qt code routes `qDebug()` output to `debug.log` under category "qt": run with `-debug=qt`
to see it.
-### Testnet and Regtest modes
+### Signet, testnet, and regtest modes
-Run with the `-testnet` option to run with "play bitcoins" on the test network, if you
-are testing multi-machine code that needs to operate across the internet.
+If you are testing multi-machine code that needs to operate across the internet,
+you can run with either the `-signet` or the `-testnet` config option to test
+with "play bitcoins" on a test network.
-If you are testing something that can run on one machine, run with the `-regtest` option.
-In regression test mode, blocks can be created on-demand; see [test/functional/](/test/functional) for tests
-that run in `-regtest` mode.
+If you are testing something that can run on one machine, run with the
+`-regtest` option. In regression test mode, blocks can be created on demand;
+see [test/functional/](/test/functional) for tests that run in `-regtest` mode.
### DEBUG_LOCKORDER
@@ -543,7 +544,7 @@ General Bitcoin Core
- *Rationale*: RPC allows for better automatic testing. The test suite for
the GUI is very limited.
-- Make sure pull requests pass Travis CI before merging.
+- Make sure pull requests pass CI before merging.
- *Rationale*: Makes sure that they pass thorough testing, and that the tester will keep passing
on the master branch. Otherwise, all new pull requests will start failing the tests, resulting in
@@ -1036,7 +1037,7 @@ Scripted diffs
--------------
For reformatting and refactoring commits where the changes can be easily automated using a bash script, we use
-scripted-diff commits. The bash script is included in the commit message and our Travis CI job checks that
+scripted-diff commits. The bash script is included in the commit message and our CI job checks that
the result of the script is identical to the commit. This aids reviewers since they can verify that the script
does exactly what it is supposed to do. It is also helpful for rebasing (since the same script can just be re-run
on the new master commit).
diff --git a/doc/guix.md b/doc/guix.md
new file mode 100644
index 0000000000..fa9c74f486
--- /dev/null
+++ b/doc/guix.md
@@ -0,0 +1,3 @@
+# Bootstrappable Bitcoin Core Builds
+
+See [contrib/guix/README.md](../contrib/guix/README.md)
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index edbc0911a1..8f890da532 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -16,6 +16,10 @@ if BUILD_BITCOIN_TX
dist_man1_MANS+=bitcoin-tx.1
endif
+if BUILD_BITCOIN_UTIL
+ dist_man1_MANS+=bitcoin-util.1
+endif
+
if ENABLE_WALLET
if BUILD_BITCOIN_WALLET
dist_man1_MANS+=bitcoin-wallet.1
diff --git a/doc/man/bitcoin-cli.1 b/doc/man/bitcoin-cli.1
index 588ae81fce..6bcad7006b 100644
--- a/doc/man/bitcoin-cli.1
+++ b/doc/man/bitcoin-cli.1
@@ -2,4 +2,4 @@
.SH NAME
bitcoin-cli \- manual page for bitcoin-cli
-This is a placefolder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
+This is a placeholder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
index 9c75e9fe54..ff4d1d2c7a 100644
--- a/doc/man/bitcoin-qt.1
+++ b/doc/man/bitcoin-qt.1
@@ -2,4 +2,4 @@
.SH NAME
bitcoin-qt \- manual page for bitcoin-qt
-This is a placefolder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
+This is a placeholder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
diff --git a/doc/man/bitcoin-tx.1 b/doc/man/bitcoin-tx.1
index 148a5890b0..776bb46234 100644
--- a/doc/man/bitcoin-tx.1
+++ b/doc/man/bitcoin-tx.1
@@ -2,4 +2,4 @@
.SH NAME
bitcoin-tx \- manual page for bitcoin-tx
-This is a placefolder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
+This is a placeholder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
diff --git a/doc/man/bitcoin-util.1 b/doc/man/bitcoin-util.1
new file mode 100644
index 0000000000..5c733c6e21
--- /dev/null
+++ b/doc/man/bitcoin-util.1
@@ -0,0 +1,5 @@
+.TH BITCOIN-UTIL "1"
+.SH NAME
+bitcoin-util \- manual page for bitcoin-util
+
+This is a placeholder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
diff --git a/doc/man/bitcoin-wallet.1 b/doc/man/bitcoin-wallet.1
index 69133b33f7..2da43dec66 100644
--- a/doc/man/bitcoin-wallet.1
+++ b/doc/man/bitcoin-wallet.1
@@ -2,4 +2,4 @@
.SH NAME
bitcoin-wallet \- manual page for bitcoin-wallet
-This is a placefolder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
+This is a placeholder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
index de338182ff..2c88f74520 100644
--- a/doc/man/bitcoind.1
+++ b/doc/man/bitcoind.1
@@ -2,4 +2,4 @@
.SH NAME
bitcoind \- manual page for bitcoind
-This is a placefolder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
+This is a placeholder file. Please follow the instructions in \fIcontrib/devtools/README.md\fR to generate the manual pages after a release.
diff --git a/doc/productivity.md b/doc/productivity.md
index 555f0afe3c..a01c6f545d 100644
--- a/doc/productivity.md
+++ b/doc/productivity.md
@@ -51,6 +51,7 @@ After running `./autogen.sh`, which generates the `./configure` file, use `./con
```sh
--without-miniupnpc
+--without-natpmp
--disable-bench
--disable-wallet
--without-gui
diff --git a/doc/release-notes-18077.md b/doc/release-notes-18077.md
new file mode 100644
index 0000000000..4034a4c19c
--- /dev/null
+++ b/doc/release-notes-18077.md
@@ -0,0 +1,10 @@
+P2P and network changes
+-----------------------
+
+- Added NAT-PMP port mapping support via [`libnatpmp`](https://miniupnp.tuxfamily.org/libnatpmp.html)
+
+Command-line options
+--------------------
+
+- The `-natpmp` option has been added to use NAT-PMP to map the listening port. If both UPnP
+and NAT-PMP are enabled, a successful allocation from UPnP prevails over one from NAT-PMP.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index f286a4493b..8f1e03e16b 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -63,6 +63,11 @@ P2P and network changes
Updated RPCs
------------
+- `getpeerinfo` no longer returns the following fields: `addnode`, `banscore`,
+ and `whitelisted`, which were previously deprecated in 0.21. Instead of
+ `addnode`, the `connection_type` field returns manual. Instead of
+ `whitelisted`, the `permissions` field indicates if the peer has special
+ privileges. The `banscore` field has simply been removed. (#20755)
Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section below.
diff --git a/doc/release-notes/release-notes-0.21.0.md b/doc/release-notes/release-notes-0.21.0.md
new file mode 100644
index 0000000000..3baba3d49b
--- /dev/null
+++ b/doc/release-notes/release-notes-0.21.0.md
@@ -0,0 +1,1336 @@
+0.21.0 Release Notes
+====================
+
+Bitcoin Core version 0.21.0 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-0.21.0/>
+
+This release includes new features, various bug fixes 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 in some cases), then run the
+installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
+or `bitcoind`/`bitcoin-qt` (on Linux).
+
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but it might take some time if the data directory needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.12+, and Windows 7 and newer. Bitcoin
+Core should also work on most other Unix-like systems but is not as
+frequently tested on them. It is not recommended to use Bitcoin Core on
+unsupported systems.
+
+From Bitcoin Core 0.20.0 onwards, macOS versions earlier than 10.12 are no
+longer supported. Additionally, Bitcoin Core does not yet change appearance
+when macOS "dark mode" is activated.
+
+The node's known peers are persisted to disk in a file called `peers.dat`. The
+format of this file has been changed in a backwards-incompatible way in order to
+accommodate the storage of Tor v3 and other BIP155 addresses. This means that if
+the file is modified by 0.21.0 or newer then older versions will not be able to
+read it. Those old versions, in the event of a downgrade, will log an error
+message "Incorrect keysize in addrman deserialization" and will continue normal
+operation as if the file was missing, creating a new empty one. (#19954, #20284)
+
+Notable changes
+===============
+
+P2P and network changes
+-----------------------
+
+- The mempool now tracks whether transactions submitted via the wallet or RPCs
+ have been successfully broadcast. Every 10-15 minutes, the node will try to
+ announce unbroadcast transactions until a peer requests it via a `getdata`
+ message or the transaction is removed from the mempool for other reasons.
+ The node will not track the broadcast status of transactions submitted to the
+ node using P2P relay. This version reduces the initial broadcast guarantees
+ for wallet transactions submitted via P2P to a node running the wallet. (#18038)
+
+- The size of the set of transactions that peers have announced and we consider
+ for requests has been reduced from 100000 to 5000 (per peer), and further
+ announcements will be ignored when that limit is reached. If you need to dump
+ (very) large batches of transactions, exceptions can be made for trusted
+ peers using the "relay" network permission. For localhost for example it can
+ be enabled using the command line option `-whitelist=relay@127.0.0.1`.
+ (#19988)
+
+- This release adds support for Tor version 3 hidden services, and rumoring them
+ over the network to other peers using
+ [BIP155](https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki).
+ Version 2 hidden services are still fully supported by Bitcoin Core, but the
+ Tor network will start
+ [deprecating](https://blog.torproject.org/v2-deprecation-timeline) them in the
+ coming months. (#19954)
+
+- The Tor onion service that is automatically created by setting the
+ `-listenonion` configuration parameter will now be created as a Tor v3 service
+ instead of Tor v2. The private key that was used for Tor v2 (if any) will be
+ left untouched in the `onion_private_key` file in the data directory (see
+ `-datadir`) and can be removed if not needed. Bitcoin Core will no longer
+ attempt to read it. The private key for the Tor v3 service will be saved in a
+ file named `onion_v3_private_key`. To use the deprecated Tor v2 service (not
+ recommended), the `onion_private_key` can be copied over
+ `onion_v3_private_key`, e.g.
+ `cp -f onion_private_key onion_v3_private_key`. (#19954)
+
+- The client writes a file (`anchors.dat`) at shutdown with the network addresses
+ of the node’s two outbound block-relay-only peers (so called "anchors"). The
+ next time the node starts, it reads this file and attempts to reconnect to those
+ same two peers. This prevents an attacker from using node restarts to trigger a
+ complete change in peers, which would be something they could use as part of an
+ eclipse attack. (#17428)
+
+- This release adds support for serving
+ [BIP157](https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki) compact
+ filters to peers on the network when enabled using
+ `-blockfilterindex=1 -peerblockfilters=1`. (#16442)
+
+- This release adds support for signets
+ ([BIP325](https://github.com/bitcoin/bips/blob/master/bip-0325.mediawiki)) in
+ addition to the existing mainnet, testnet, and regtest networks. Signets are
+ centrally-controlled test networks, allowing them to be more predictable
+ test environments than the older testnet. One public signet is maintained, and
+ selectable using `-signet`. It is also possible to create personal signets.
+ (#18267).
+
+- This release implements
+ [BIP339](https://github.com/bitcoin/bips/blob/master/bip-0339.mediawiki)
+ wtxid relay. When negotiated, transactions are announced using their wtxid
+ instead of their txid. (#18044).
+
+- This release implements the proposed Taproot consensus rules
+ ([BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) and
+ [BIP342](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki)),
+ without activation on mainnet. Experimentation with Taproot can be done on
+ signet, where its rules are already active. (#19553)
+
+Updated RPCs
+------------
+
+- The `getpeerinfo` RPC has a new `network` field that provides the type of
+ network ("ipv4", "ipv6", or "onion") that the peer connected through. (#20002)
+
+- The `getpeerinfo` RPC now has additional `last_block` and `last_transaction`
+ fields that return the UNIX epoch time of the last block and the last *valid*
+ transaction received from each peer. (#19731)
+
+- `getnetworkinfo` now returns two new fields, `connections_in` and
+ `connections_out`, that provide the number of inbound and outbound peer
+ connections. These new fields are in addition to the existing `connections`
+ field, which returns the total number of peer connections. (#19405)
+
+- Exposed transaction version numbers are now treated as unsigned 32-bit
+ integers instead of signed 32-bit integers. This matches their treatment in
+ consensus logic. Versions greater than 2 continue to be non-standard
+ (matching previous behavior of smaller than 1 or greater than 2 being
+ non-standard). Note that this includes the `joinpsbt` command, which combines
+ partially-signed transactions by selecting the highest version number.
+ (#16525)
+
+- `getmempoolinfo` now returns an additional `unbroadcastcount` field. The
+ mempool tracks locally submitted transactions until their initial broadcast
+ is acknowledged by a peer. This field returns the count of transactions
+ waiting for acknowledgement.
+
+- Mempool RPCs such as `getmempoolentry` and `getrawmempool` with
+ `verbose=true` now return an additional `unbroadcast` field. This indicates
+ whether initial broadcast of the transaction has been acknowledged by a
+ peer. `getmempoolancestors` and `getmempooldescendants` are also updated.
+
+- The `getpeerinfo` RPC no longer returns the `banscore` field unless the configuration
+ option `-deprecatedrpc=banscore` is used. The `banscore` field will be fully
+ removed in the next major release. (#19469)
+
+- The `testmempoolaccept` RPC returns `vsize` and a `fees` object with the `base` fee
+ if the transaction would pass validation. (#19940)
+
+- The `getpeerinfo` RPC now returns a `connection_type` field. This indicates
+ the type of connection established with the peer. It will return one of six
+ options. For more information, see the `getpeerinfo` help documentation.
+ (#19725)
+
+- The `getpeerinfo` RPC no longer returns the `addnode` field by default. This
+ field will be fully removed in the next major release. It can be accessed
+ with the configuration option `-deprecatedrpc=getpeerinfo_addnode`. However,
+ it is recommended to instead use the `connection_type` field (it will return
+ `manual` when addnode is true). (#19725)
+
+- The `getpeerinfo` RPC no longer returns the `whitelisted` field by default.
+ This field will be fully removed in the next major release. It can be accessed
+ with the configuration option `-deprecatedrpc=getpeerinfo_whitelisted`. However,
+ it is recommended to instead use the `permissions` field to understand if specific
+ privileges have been granted to the peer. (#19770)
+
+- The `walletcreatefundedpsbt` RPC call will now fail with
+ `Insufficient funds` when inputs are manually selected but are not enough to cover
+ the outputs and fee. Additional inputs can automatically be added through the
+ new `add_inputs` option. (#16377)
+
+- The `fundrawtransaction` RPC now supports `add_inputs` option that when `false`
+ prevents adding more inputs if necessary and consequently the RPC fails.
+
+Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section below.
+
+New RPCs
+--------
+
+- The `getindexinfo` RPC returns the actively running indices of the node,
+ including their current sync status and height. It also accepts an `index_name`
+ to specify returning the status of that index only. (#19550)
+
+Build System
+------------
+
+Updated settings
+----------------
+
+- The same ZeroMQ notification (e.g. `-zmqpubhashtx=address`) can now be
+ specified multiple times to publish the same notification to different ZeroMQ
+ sockets. (#18309)
+
+- The `-banscore` configuration option, which modified the default threshold for
+ disconnecting and discouraging misbehaving peers, has been removed as part of
+ changes in 0.20.1 and in this release to the handling of misbehaving peers.
+ Refer to "Changes regarding misbehaving peers" in the 0.20.1 release notes for
+ details. (#19464)
+
+- The `-debug=db` logging category, which was deprecated in 0.20 and replaced by
+ `-debug=walletdb` to distinguish it from `coindb`, has been removed. (#19202)
+
+- A `download` permission has been extracted from the `noban` permission. For
+ compatibility, `noban` implies the `download` permission, but this may change
+ in future releases. Refer to the help of the affected settings `-whitebind`
+ and `-whitelist` for more details. (#19191)
+
+- Netmasks that contain 1-bits after 0-bits (the 1-bits are not contiguous on
+ the left side, e.g. 255.0.255.255) are no longer accepted. They are invalid
+ according to RFC 4632. Netmasks are used in the `-rpcallowip` and `-whitelist`
+ configuration options and in the `setban` RPC. (#19628)
+
+- The `-blocksonly` setting now completely disables fee estimation. (#18766)
+
+Changes to Wallet or GUI related settings can be found in the GUI or Wallet section below.
+
+Tools and Utilities
+-------------------
+
+- A new `bitcoin-cli -netinfo` command provides a network peer connections
+ dashboard that displays data from the `getpeerinfo` and `getnetworkinfo` RPCs
+ in a human-readable format. An optional integer argument from `0` to `4` may
+ be passed to see increasing levels of detail. (#19643)
+
+- A new `bitcoin-cli -generate` command, equivalent to RPC `generatenewaddress`
+ followed by `generatetoaddress`, can generate blocks for command line testing
+ purposes. This is a client-side version of the former `generate` RPC. See the
+ help for details. (#19133)
+
+- The `bitcoin-cli -getinfo` command now displays the wallet name and balance for
+ each of the loaded wallets when more than one is loaded (e.g. in multiwallet
+ mode) and a wallet is not specified with `-rpcwallet`. (#18594)
+
+- The `connections` field of `bitcoin-cli -getinfo` is now expanded to return a JSON
+ object with `in`, `out` and `total` numbers of peer connections. It previously
+ returned a single integer value for the total number of peer connections. (#19405)
+
+New settings
+------------
+
+- The `startupnotify` option is used to specify a command to
+ execute when Bitcoin Core has finished with its startup
+ sequence. (#15367)
+
+Wallet
+------
+
+- Backwards compatibility has been dropped for two `getaddressinfo` RPC
+ deprecations, as notified in the 0.20 release notes. The deprecated `label`
+ field has been removed as well as the deprecated `labels` behavior of
+ returning a JSON object containing `name` and `purpose` key-value pairs. Since
+ 0.20, the `labels` field returns a JSON array of label names. (#19200)
+
+- To improve wallet privacy, the frequency of wallet rebroadcast attempts is
+ reduced from approximately once every 15 minutes to once every 12-36 hours.
+ To maintain a similar level of guarantee for initial broadcast of wallet
+ transactions, the mempool tracks these transactions as a part of the newly
+ introduced unbroadcast set. See the "P2P and network changes" section for
+ more information on the unbroadcast set. (#18038)
+
+- The `sendtoaddress` and `sendmany` RPCs accept an optional `verbose=True`
+ argument to also return the fee reason about the sent tx. (#19501)
+
+- The wallet can create a transaction without change even when the keypool is
+ empty. Previously it failed. (#17219)
+
+- The `-salvagewallet` startup option has been removed. A new `salvage` command
+ has been added to the `bitcoin-wallet` tool which performs the salvage
+ operations that `-salvagewallet` did. (#18918)
+
+- A new configuration flag `-maxapsfee` has been added, which sets the max
+ allowed avoid partial spends (APS) fee. It defaults to 0 (i.e. fee is the
+ same with and without APS). Setting it to -1 will disable APS, unless
+ `-avoidpartialspends` is set. (#14582)
+
+- The wallet will now avoid partial spends (APS) by default, if this does not
+ result in a difference in fees compared to the non-APS variant. The allowed
+ fee threshold can be adjusted using the new `-maxapsfee` configuration
+ option. (#14582)
+
+- The `createwallet`, `loadwallet`, and `unloadwallet` RPCs now accept
+ `load_on_startup` options to modify the settings list. Unless these options
+ are explicitly set to true or false, the list is not modified, so the RPC
+ methods remain backwards compatible. (#15937)
+
+- A new `send` RPC with similar syntax to `walletcreatefundedpsbt`, including
+ support for coin selection and a custom fee rate, is added. The `send` RPC is
+ experimental and may change in subsequent releases. (#16378)
+
+- The `estimate_mode` parameter is now case-insensitive in the `bumpfee`,
+ `fundrawtransaction`, `sendmany`, `sendtoaddress`, `send` and
+ `walletcreatefundedpsbt` RPCs. (#11413)
+
+- The `bumpfee` RPC now uses `conf_target` rather than `confTarget` in the
+ options. (#11413)
+
+- `fundrawtransaction` and `walletcreatefundedpsbt` when used with the
+ `lockUnspents` argument now lock manually selected coins, in addition to
+ automatically selected coins. Note that locked coins are never used in
+ automatic coin selection, but can still be manually selected. (#18244)
+
+- The `-zapwallettxes` startup option has been removed and its functionality
+ removed from the wallet. This option was originally intended to allow for
+ rescuing wallets which were affected by a malleability attack. More recently,
+ it has been used in the fee bumping of transactions that did not signal RBF.
+ This functionality has been superseded with the abandon transaction feature. (#19671)
+
+- The error code when no wallet is loaded, but a wallet RPC is called, has been
+ changed from `-32601` (method not found) to `-18` (wallet not found).
+ (#20101)
+
+### Automatic wallet creation removed
+
+Bitcoin Core will no longer automatically create new wallets on startup. It will
+load existing wallets specified by `-wallet` options on the command line or in
+`bitcoin.conf` or `settings.json` files. And by default it will also load a
+top-level unnamed ("") wallet. However, if specified wallets don't exist,
+Bitcoin Core will now just log warnings instead of creating new wallets with
+new keys and addresses like previous releases did.
+
+New wallets can be created through the GUI (which has a more prominent create
+wallet option), through the `bitcoin-cli createwallet` or `bitcoin-wallet
+create` commands, or the `createwallet` RPC. (#15454, #20186)
+
+### Experimental Descriptor Wallets
+
+Please note that Descriptor Wallets are still experimental and not all expected functionality
+is available. Additionally there may be some bugs and current functions may change in the future.
+Bugs and missing functionality can be reported to the [issue tracker](https://github.com/bitcoin/bitcoin/issues).
+
+0.21 introduces a new type of wallet - Descriptor Wallets. Descriptor Wallets store
+scriptPubKey information using output descriptors. This is in contrast to the Legacy Wallet
+structure where keys are used to implicitly generate scriptPubKeys and addresses. Because of this
+shift to being script based instead of key based, many of the confusing things that Legacy
+Wallets do are not possible with Descriptor Wallets. Descriptor Wallets use a definition
+of "mine" for scripts which is simpler and more intuitive than that used by Legacy Wallets.
+Descriptor Wallets also uses different semantics for watch-only things and imports.
+
+As Descriptor Wallets are a new type of wallet, their introduction does not affect existing wallets.
+Users who already have a Bitcoin Core wallet can continue to use it as they did before without
+any change in behavior. Newly created Legacy Wallets (which remains the default type of wallet) will
+behave as they did in previous versions of Bitcoin Core.
+
+The differences between Descriptor Wallets and Legacy Wallets are largely limited to non user facing
+things. They are intended to behave similarly except for the import/export and watchonly functionality
+as described below.
+
+#### Creating Descriptor Wallets
+
+Descriptor wallets are not the default type of wallet.
+
+In the GUI, a checkbox has been added to the Create Wallet Dialog to indicate that a
+Descriptor Wallet should be created. And a `descriptors` option has been added to `createwallet` RPC.
+Setting `descriptors` to `true` will create a Descriptor Wallet instead of a Legacy Wallet.
+
+Without those options being set, a Legacy Wallet will be created instead.
+
+#### `IsMine` Semantics
+
+`IsMine` refers to the function used to determine whether a script belongs to the wallet.
+This is used to determine whether an output belongs to the wallet. `IsMine` in Legacy Wallets
+returns true if the wallet would be able to sign an input that spends an output with that script.
+Since keys can be involved in a variety of different scripts, this definition for `IsMine` can
+lead to many unexpected scripts being considered part of the wallet.
+
+With Descriptor Wallets, descriptors explicitly specify the set of scripts that are owned by
+the wallet. Since descriptors are deterministic and easily enumerable, users will know exactly
+what scripts the wallet will consider to belong to it. Additionally the implementation of `IsMine`
+in Descriptor Wallets is far simpler than for Legacy Wallets. Notably, in Legacy Wallets, `IsMine`
+allowed for users to take one type of address (e.g. P2PKH), mutate it into another address type
+(e.g. P2WPKH), and the wallet would still detect outputs sending to the new address type
+even without that address being requested from the wallet. Descriptor Wallets do not
+allow for this and will only watch for the addresses that were explicitly requested from the wallet.
+
+These changes to `IsMine` will make it easier to reason about what scripts the wallet will
+actually be watching for in outputs. However for the vast majority of users, this change is
+largely transparent and will not have noticeable effect.
+
+#### Imports and Exports
+
+In Legacy Wallets, raw scripts and keys could be imported to the wallet. Those imported scripts
+and keys are treated separately from the keys generated by the wallet. This complicates the `IsMine`
+logic as it has to distinguish between spendable and watchonly.
+
+Descriptor Wallets handle importing scripts and keys differently. Only complete descriptors can be
+imported. These descriptors are then added to the wallet as if it were a descriptor generated by
+the wallet itself. This simplifies the `IsMine` logic so that it no longer has to distinguish
+between spendable and watchonly. As such, the watchonly model for Descriptor Wallets is also
+different and described in more detail in the next section.
+
+To import into a Descriptor Wallet, a new `importdescriptors` RPC has been added that uses a syntax
+similar to that of `importmulti`.
+
+As Legacy Wallets and Descriptor Wallets use different mechanisms for storing and importing scripts and keys
+the existing import RPCs have been disabled for descriptor wallets.
+New export RPCs for Descriptor Wallets have not yet been added.
+
+The following RPCs are disabled for Descriptor Wallets:
+
+* `importprivkey`
+* `importpubkey`
+* `importaddress`
+* `importwallet`
+* `dumpprivkey`
+* `dumpwallet`
+* `importmulti`
+* `addmultisigaddress`
+* `sethdseed`
+
+#### Watchonly Wallets
+
+A Legacy Wallet contains both private keys and scripts that were being watched.
+Those watched scripts would not contribute to your normal balance. In order to see the watchonly
+balance and to use watchonly things in transactions, an `include_watchonly` option was added
+to many RPCs that would allow users to do that. However it is easy to forget to include this option.
+
+Descriptor Wallets move to a per-wallet watchonly model. Instead an entire wallet is considered to be
+watchonly depending on whether it was created with private keys disabled. This eliminates the need
+to distinguish between things that are watchonly and things that are not within a wallet itself.
+
+This change does have a caveat. If a Descriptor Wallet with private keys *enabled* has
+a multiple key descriptor without all of the private keys (e.g. `multi(...)` with only one private key),
+then the wallet will fail to sign and broadcast transactions. Such wallets would need to use the PSBT
+workflow but the typical GUI Send, `sendtoaddress`, etc. workflows would still be available, just
+non-functional.
+
+This issue is worsened if the wallet contains both single key (e.g. `wpkh(...)`) descriptors and such
+multiple key descriptors as some transactions could be signed and broadcast and others not. This is
+due to some transactions containing only single key inputs, while others would contain both single
+key and multiple key inputs, depending on which are available and how the coin selection algorithm
+selects inputs. However this is not considered to be a supported use case; multisigs
+should be in their own wallets which do not already have descriptors. Although users cannot export
+descriptors with private keys for now as explained earlier.
+
+#### BIP 44/49/84 Support
+
+The change to using descriptors changes the default derivation paths used by Bitcoin Core
+to adhere to BIP 44/49/84. Descriptors with different derivation paths can be imported without
+issue.
+
+#### SQLite Database Backend
+
+Descriptor wallets use SQLite for the wallet file instead of the Berkeley DB used in legacy wallets.
+This will break compatibility with any existing tooling that operates on wallets, however compatibility
+was already being broken by the move to descriptors.
+
+### Wallet RPC changes
+
+- The `upgradewallet` RPC replaces the `-upgradewallet` command line option.
+ (#15761)
+
+- The `settxfee` RPC will fail if the fee was set higher than the `-maxtxfee`
+ command line setting. The wallet will already fail to create transactions
+ with fees higher than `-maxtxfee`. (#18467)
+
+- A new `fee_rate` parameter/option denominated in satoshis per vbyte (sat/vB)
+ is introduced to the `sendtoaddress`, `sendmany`, `fundrawtransaction` and
+ `walletcreatefundedpsbt` RPCs as well as to the experimental new `send`
+ RPC. The legacy `feeRate` option in `fundrawtransaction` and
+ `walletcreatefundedpsbt` still exists for setting a fee rate in BTC per 1,000
+ vbytes (BTC/kvB), but it is expected to be deprecated soon to avoid
+ confusion. For these RPCs, the fee rate error message is updated from BTC/kB
+ to sat/vB and the help documentation in BTC/kB is updated to BTC/kvB. The
+ `send` and `sendtoaddress` RPC examples are updated to aid users in creating
+ transactions with explicit fee rates. (#20305, #11413)
+
+- The `bumpfee` RPC `fee_rate` option is changed from BTC/kvB to sat/vB and the
+ help documentation is updated. Users are warned that this is a breaking API
+ change, but it should be relatively benign: the large (100,000 times)
+ difference between BTC/kvB and sat/vB units means that a transaction with a
+ fee rate mistakenly calculated in BTC/kvB rather than sat/vB should raise an
+ error due to the fee rate being set too low. In the worst case, the
+ transaction may send at 1 sat/vB, but as Replace-by-Fee (BIP125 RBF) is active
+ by default when an explicit fee rate is used, the transaction fee can be
+ bumped. (#20305)
+
+GUI changes
+-----------
+
+- Wallets created or loaded in the GUI will now be automatically loaded on
+ startup, so they don't need to be manually reloaded next time Bitcoin Core is
+ started. The list of wallets to load on startup is stored in
+ `\<datadir\>/settings.json` and augments any command line or `bitcoin.conf`
+ `-wallet=` settings that specify more wallets to load. Wallets that are
+ unloaded in the GUI get removed from the settings list so they won't load
+ again automatically next startup. (#19754)
+
+- The GUI Peers window no longer displays a "Ban Score" field. This is part of
+ changes in 0.20.1 and in this release to the handling of misbehaving
+ peers. Refer to "Changes regarding misbehaving peers" in the 0.20.1 release
+ notes for details. (#19512)
+
+Low-level changes
+=================
+
+RPC
+---
+
+- To make RPC `sendtoaddress` more consistent with `sendmany` the following error
+ `sendtoaddress` codes were changed from `-4` to `-6`:
+ - Insufficient funds
+ - Fee estimation failed
+ - Transaction has too long of a mempool chain
+
+- The `sendrawtransaction` error code for exceeding `maxfeerate` has been changed from
+ `-26` to `-25`. The error string has been changed from "absurdly-high-fee" to
+ "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)." The
+ `testmempoolaccept` RPC returns `max-fee-exceeded` rather than `absurdly-high-fee`
+ as the `reject-reason`. (#19339)
+
+- To make wallet and rawtransaction RPCs more consistent, the error message for
+ exceeding maximum feerate has been changed to "Fee exceeds maximum configured by user
+ (e.g. -maxtxfee, maxfeerate)." (#19339)
+
+Tests
+-----
+
+- The BIP 325 default signet can be enabled by the `-chain=signet` or `-signet`
+ setting. The settings `-signetchallenge` and `-signetseednode` allow
+ enabling a custom signet.
+
+- The `generateblock` RPC allows testers using regtest mode to
+ generate blocks that consist of a custom set of transactions. (#17693)
+
+0.21.0 change log
+=================
+
+### Consensus
+- #18267 BIP-325: Signet (kallewoof)
+- #20016 uint256: 1 is a constant (ajtowns)
+- #20006 Fix misleading error message: Clean stack rule (sanket1729)
+- #19953 Implement BIP 340-342 validation (Schnorr/taproot/tapscript) (sipa)
+- #20169 Taproot follow-up: Make ComputeEntrySchnorr and ComputeEntryECDSA const to clarify contract (practicalswift)
+
+### Policy
+- #18766 Disable fee estimation in blocksonly mode (darosior)
+- #19630 Cleanup fee estimation code (darosior)
+- #20165 Only relay Taproot spends if next block has it active (sipa)
+
+### Mining
+- #17946 Fix GBT: Restore "!segwit" and "csv" to "rules" key (luke-jr)
+
+### Privacy
+- #16432 Add privacy to the Overview page (hebasto)
+- #18861 Do not answer GETDATA for to-be-announced tx (sipa)
+- #18038 Mempool tracks locally submitted transactions to improve wallet privacy (amitiuttarwar)
+- #19109 Only allow getdata of recently announced invs (sipa)
+
+### Block and transaction handling
+- #17737 Add ChainstateManager, remove BlockManager global (jamesob)
+- #18960 indexes: Add compact block filter headers cache (jnewbery)
+- #13204 Faster sigcache nonce (JeremyRubin)
+- #19088 Use std::chrono throughout some validation functions (fanquake)
+- #19142 Make VerifyDB level 4 interruptible (MarcoFalke)
+- #17994 Flush undo files after last block write (kallewoof)
+- #18990 log: Properly log txs rejected from mempool (MarcoFalke)
+- #18984 Remove unnecessary input blockfile SetPos (dgenr8)
+- #19526 log: Avoid treating remote misbehvior as local system error (MarcoFalke)
+- #18044 Use wtxid for transaction relay (sdaftuar)
+- #18637 coins: allow cache resize after init (jamesob)
+- #19854 Avoid locking CTxMemPool::cs recursively in simple cases (hebasto)
+- #19478 Remove CTxMempool::mapLinks data structure member (JeremyRubin)
+- #19927 Reduce direct `g_chainman` usage (dongcarl)
+- #19898 log: print unexpected version warning in validation log category (n-thumann)
+- #20036 signet: Add assumed values for default signet (MarcoFalke)
+- #20048 chainparams: do not log signet startup messages for other chains (jonatack)
+- #19339 re-delegate absurd fee checking from mempool to clients (glozow)
+- #20035 signet: Fix uninitialized read in validation (MarcoFalke)
+- #20157 Bugfix: chainparams: Add missing (always enabled) Taproot deployment for Signet (luke-jr)
+- #20263 Update assumed chain params (MarcoFalke)
+- #20372 Avoid signed integer overflow when loading a mempool.dat file with a malformed time field (practicalswift)
+- #18621 script: Disallow silent bool -> cscript conversion (MarcoFalke)
+- #18612, #18732 script: Remove undocumented and unused operator+ (MarcoFalke)
+- #19317 Add a left-justified width field to `log2_work` component for a uniform debug.log output (jamesgmorgan)
+
+### P2P protocol and network code
+- #18544 Limit BIP37 filter lifespan (active between `filterload`..`filterclear`) (theStack)
+- #18806 Remove is{Empty,Full} flags from CBloomFilter, clarify CVE fix (theStack)
+- #18512 Improve asmap checks and add sanity check (sipa)
+- #18877 Serve cfcheckpt requests (jnewbery)
+- #18895 Unbroadcast followups: rpcs, nLastResend, mempool sanity check (gzhao408)
+- #19010 net processing: Add support for `getcfheaders` (jnewbery)
+- #16939 Delay querying DNS seeds (ajtowns)
+- #18807 Unbroadcast follow-ups (amitiuttarwar)
+- #19044 Add support for getcfilters (jnewbery)
+- #19084 improve code documentation for dns seed behaviour (ajtowns)
+- #19260 disconnect peers that send filterclear + update existing filter msg disconnect logic (gzhao408)
+- #19284 Add seed.bitcoin.wiz.biz to DNS seeds (wiz)
+- #19322 split PushInventory() (jnewbery)
+- #19204 Reduce inv traffic during IBD (MarcoFalke)
+- #19470 banlist: log post-swept banlist size at startup (fanquake)
+- #19191 Extract download permission from noban (MarcoFalke)
+- #14033 Drop `CADDR_TIME_VERSION` checks now that `MIN_PEER_PROTO_VERSION` is greater (Empact)
+- #19464 net, rpc: remove -banscore option, deprecate banscore in getpeerinfo (jonatack)
+- #19514 [net/net processing] check banman pointer before dereferencing (jnewbery)
+- #19512 banscore updates to gui, tests, release notes (jonatack)
+- #19360 improve encapsulation of CNetAddr (vasild)
+- #19217 disambiguate block-relay-only variable names from blocksonly variables (glowang)
+- #19473 Add -networkactive option (hebasto)
+- #19472 [net processing] Reduce `cs_main` scope in MaybeDiscourageAndDisconnect() (jnewbery)
+- #19583 clean up Misbehaving() (jnewbery)
+- #19534 save the network type explicitly in CNetAddr (vasild)
+- #19569 Enable fetching of orphan parents from wtxid peers (sipa)
+- #18991 Cache responses to GETADDR to prevent topology leaks (naumenkogs)
+- #19596 Deduplicate parent txid loop of requested transactions and missing parents of orphan transactions (sdaftuar)
+- #19316 Cleanup logic around connection types (amitiuttarwar)
+- #19070 Signal support for compact block filters with `NODE_COMPACT_FILTERS` (jnewbery)
+- #19705 Shrink CAddress from 48 to 40 bytes on x64 (vasild)
+- #19704 Move ProcessMessage() to PeerLogicValidation (jnewbery)
+- #19628 Change CNetAddr::ip to have flexible size (vasild)
+- #19797 Remove old check for 3-byte shifted IP addresses from pre-0.2.9 nodes (#19797)
+- #19607 Add Peer struct for per-peer data in net processing (jnewbery)
+- #19857 improve nLastBlockTime and nLastTXTime documentation (jonatack)
+- #19724 Cleanup connection types- followups (amitiuttarwar)
+- #19670 Protect localhost and block-relay-only peers from eviction (sdaftuar)
+- #19728 Increase the ip address relay branching factor for unreachable networks (sipa)
+- #19879 Miscellaneous wtxid followups (amitiuttarwar)
+- #19697 Improvements on ADDR caching (naumenkogs)
+- #17785 Unify Send and Receive protocol versions (hebasto)
+- #19845 CNetAddr: add support to (un)serialize as ADDRv2 (vasild)
+- #19107 Move all header verification into the network layer, extend logging (troygiorshev)
+- #20003 Exit with error message if -proxy is specified without arguments (instead of continuing without proxy server) (practicalswift)
+- #19991 Use alternative port for incoming Tor connections (hebasto)
+- #19723 Ignore unknown messages before VERACK (sdaftuar)
+- #19954 Complete the BIP155 implementation and upgrade to TORv3 (vasild)
+- #20119 BIP155 follow-ups (sipa)
+- #19988 Overhaul transaction request logic (sipa)
+- #17428 Try to preserve outbound block-relay-only connections during restart (hebasto)
+- #19911 Guard `vRecvGetData` with `cs_vRecv` and `orphan_work_set` with `g_cs_orphans` (narula)
+- #19753 Don't add AlreadyHave transactions to recentRejects (troygiorshev)
+- #20187 Test-before-evict bugfix and improvements for block-relay-only peers (sdaftuar)
+- #20237 Hardcoded seeds update for 0.21 (laanwj)
+- #20212 Fix output of peer address in version message (vasild)
+- #20284 Ensure old versions don't parse peers.dat (vasild)
+- #20405 Avoid calculating onion address checksum when version is not 3 (lontivero)
+- #20564 Don't send 'sendaddrv2' to pre-70016 software, and send before 'verack' (sipa)
+- #20660 Move signet onion seed from v2 to v3 (Sjors)
+
+### Wallet
+- #18262 Exit selection when `best_waste` is 0 (achow101)
+- #17824 Prefer full destination groups in coin selection (fjahr)
+- #17219 Allow transaction without change if keypool is empty (Sjors)
+- #15761 Replace -upgradewallet startup option with upgradewallet RPC (achow101)
+- #18671 Add BlockUntilSyncedToCurrentChain to dumpwallet (MarcoFalke)
+- #16528 Native Descriptor Wallets using DescriptorScriptPubKeyMan (achow101)
+- #18777 Recommend absolute path for dumpwallet (MarcoFalke)
+- #16426 Reverse `cs_main`, `cs_wallet` lock order and reduce `cs_main` locking (ariard)
+- #18699 Avoid translating RPC errors (MarcoFalke)
+- #18782 Make sure no DescriptorScriptPubKeyMan or WalletDescriptor members are left uninitialized after construction (practicalswift)
+- #9381 Remove CWalletTx merging logic from AddToWallet (ryanofsky)
+- #16946 Include a checksum of encrypted private keys (achow101)
+- #17681 Keep inactive seeds after sethdseed and derive keys from them as needed (achow101)
+- #18918 Move salvagewallet into wallettool (achow101)
+- #14988 Fix for confirmed column in csv export for payment to self transactions (benthecarman)
+- #18275 Error if an explicit fee rate was given but the needed fee rate differed (kallewoof)
+- #19054 Skip hdKeypath of 'm' when determining inactive hd seeds (achow101)
+- #17938 Disallow automatic conversion between disparate hash types (Empact)
+- #19237 Check size after unserializing a pubkey (elichai)
+- #11413 sendtoaddress/sendmany: Add explicit feerate option (kallewoof)
+- #18850 Fix ZapSelectTx to sync wallet spends (bvbfan)
+- #18923 Never schedule MaybeCompactWalletDB when `-flushwallet` is off (MarcoFalke)
+- #19441 walletdb: Don't reinitialize desc cache with multiple cache entries (achow101)
+- #18907 walletdb: Don't remove database transaction logs and instead error (achow101)
+- #19334 Introduce WalletDatabase abstract class (achow101)
+- #19335 Cleanup and separate BerkeleyDatabase and BerkeleyBatch (achow101)
+- #19102 Introduce and use DummyDatabase instead of dummy BerkeleyDatabase (achow101)
+- #19568 Wallet should not override signing errors (fjahr)
+- #17204 Do not turn `OP_1NEGATE` in scriptSig into `0x0181` in signing code (sipa) (meshcollider)
+- #19457 Cleanup wallettool salvage and walletdb extraneous declarations (achow101)
+- #15937 Add loadwallet and createwallet `load_on_startup` options (ryanofsky)
+- #16841 Replace GetScriptForWitness with GetScriptForDestination (meshcollider)
+- #14582 always do avoid partial spends if fees are within a specified range (kallewoof)
+- #19743 -maxapsfee follow-up (kallewoof)
+- #19289 GetWalletTx and IsMine require `cs_wallet` lock (promag)
+- #19671 Remove -zapwallettxes (achow101)
+- #19805 Avoid deserializing unused records when salvaging (achow101)
+- #19754 wallet, gui: Reload previously loaded wallets on startup (achow101)
+- #19738 Avoid multiple BerkeleyBatch in DelAddressBook (promag)
+- #19919 bugfix: make LoadWallet assigns status always (AkioNak)
+- #16378 The ultimate send RPC (Sjors)
+- #15454 Remove the automatic creation and loading of the default wallet (achow101)
+- #19501 `send*` RPCs in the wallet returns the "fee reason" (stackman27)
+- #20130 Remove db mode string (S3RK)
+- #19077 Add sqlite as an alternative wallet database and use it for new descriptor wallets (achow101)
+- #20125 Expose database format in getwalletinfo (promag)
+- #20198 Show name, format and if uses descriptors in bitcoin-wallet tool (jonasschnelli)
+- #20216 Fix buffer over-read in SQLite file magic check (theStack)
+- #20186 Make -wallet setting not create wallets (ryanofsky)
+- #20230 Fix bug when just created encrypted wallet cannot get address (hebasto)
+- #20282 Change `upgradewallet` return type to be an object (jnewbery)
+- #20220 Explicit fee rate follow-ups/fixes for 0.21 (jonatack)
+- #20199 Ignore (but warn) on duplicate -wallet parameters (jonasschnelli)
+- #20324 Set DatabaseStatus::SUCCESS in MakeSQLiteDatabase (MarcoFalke)
+- #20266 Fix change detection of imported internal descriptors (achow101)
+- #20153 Do not import a descriptor with hardened derivations into a watch-only wallet (S3RK)
+- #20344 Fix scanning progress calculation for single block range (theStack)
+- #19502 Bugfix: Wallet: Soft-fail exceptions within ListWalletDir file checks (luke-jr)
+- #20378 Fix potential division by 0 in WalletLogPrintf (jonasschnelli)
+- #18836 Upgradewallet fixes and additional tests (achow101)
+- #20139 Do not return warnings from UpgradeWallet() (stackman27)
+- #20305 Introduce `fee_rate` sat/vB param/option (jonatack)
+- #20426 Allow zero-fee fundrawtransaction/walletcreatefundedpsbt and other fixes (jonatack)
+- #20573 wallet, bugfix: allow send with string `fee_rate` amounts (jonatack)
+
+### RPC and other APIs
+- #18574 cli: Call getbalances.ismine.trusted instead of getwalletinfo.balance (jonatack)
+- #17693 Add `generateblock` to mine a custom set of transactions (andrewtoth)
+- #18495 Remove deprecated migration code (vasild)
+- #18493 Remove deprecated "size" from mempool txs (vasild)
+- #18467 Improve documentation and return value of settxfee (fjahr)
+- #18607 Fix named arguments in documentation (MarcoFalke)
+- #17831 doc: Fix and extend getblockstats examples (asoltys)
+- #18785 Prevent valgrind false positive in `rest_blockhash_by_height` (ryanofsky)
+- #18999 log: Remove "No rpcpassword set" from logs (MarcoFalke)
+- #19006 Avoid crash when `g_thread_http` was never started (MarcoFalke)
+- #18594 cli: Display multiwallet balances in -getinfo (jonatack)
+- #19056 Make gettxoutsetinfo/GetUTXOStats interruptible (MarcoFalke)
+- #19112 Remove special case for unknown service flags (MarcoFalke)
+- #18826 Expose txinwitness for coinbase in JSON form from RPC (rvagg)
+- #19282 Rephrase generatetoaddress help, and use `PACKAGE_NAME` (luke-jr)
+- #16377 don't automatically append inputs in walletcreatefundedpsbt (Sjors)
+- #19200 Remove deprecated getaddressinfo fields (jonatack)
+- #19133 rpc, cli, test: add bitcoin-cli -generate command (jonatack)
+- #19469 Deprecate banscore field in getpeerinfo (jonatack)
+- #16525 Dump transaction version as an unsigned integer in RPC/TxToUniv (TheBlueMatt)
+- #19555 Deduplicate WriteHDKeypath() used in decodepsbt (theStack)
+- #19589 Avoid useless mempool query in gettxoutproof (MarcoFalke)
+- #19585 RPCResult Type of MempoolEntryDescription should be OBJ (stylesuxx)
+- #19634 Document getwalletinfo's `unlocked_until` field as optional (justinmoon)
+- #19658 Allow RPC to fetch all addrman records and add records to addrman (jnewbery)
+- #19696 Fix addnode remove command error (fjahr)
+- #18654 Separate bumpfee's psbt creation function into psbtbumpfee (achow101)
+- #19655 Catch listsinceblock `target_confirmations` exceeding block count (adaminsky)
+- #19644 Document returned error fields as optional if applicable (theStack)
+- #19455 rpc generate: print useful help and error message (jonatack)
+- #19550 Add listindices RPC (fjahr)
+- #19169 Validate provided keys for `query_options` parameter in listunspent (PastaPastaPasta)
+- #18244 fundrawtransaction and walletcreatefundedpsbt also lock manually selected coins (Sjors)
+- #14687 zmq: Enable TCP keepalive (mruddy)
+- #19405 Add network in/out connections to `getnetworkinfo` and `-getinfo` (jonatack)
+- #19878 rawtransaction: Fix argument in combinerawtransaction help message (pinheadmz)
+- #19940 Return fee and vsize from testmempoolaccept (gzhao408)
+- #13686 zmq: Small cleanups in the ZMQ code (domob1812)
+- #19386, #19528, #19717, #19849, #19994 Assert that RPCArg names are equal to CRPCCommand ones (MarcoFalke)
+- #19725 Add connection type to getpeerinfo, improve logs (amitiuttarwar)
+- #19969 Send RPC bug fix and touch-ups (Sjors)
+- #18309 zmq: Add support to listen on multiple interfaces (n-thumann)
+- #20055 Set HTTP Content-Type in bitcoin-cli (laanwj)
+- #19956 Improve invalid vout value rpc error message (n1rna)
+- #20101 Change no wallet loaded message to be clearer (achow101)
+- #19998 Add `via_tor` to `getpeerinfo` output (hebasto)
+- #19770 getpeerinfo: Deprecate "whitelisted" field (replaced by "permissions") (luke-jr)
+- #20120 net, rpc, test, bugfix: update GetNetworkName, GetNetworksInfo, regression tests (jonatack)
+- #20595 Improve heuristic hex transaction decoding (sipa)
+- #20731 Add missing description of vout in getrawtransaction help text (benthecarman)
+- #19328 Add gettxoutsetinfo `hash_type` option (fjahr)
+- #19731 Expose nLastBlockTime/nLastTXTime as last `block/last_transaction` in getpeerinfo (jonatack)
+- #19572 zmq: Create "sequence" notifier, enabling client-side mempool tracking (instagibbs)
+- #20002 Expose peer network in getpeerinfo; simplify/improve -netinfo (jonatack)
+
+### GUI
+- #17905 Avoid redundant tx status updates (ryanofsky)
+- #18646 Use `PACKAGE_NAME` in exception message (fanquake)
+- #17509 Save and load PSBT (Sjors)
+- #18769 Remove bug fix for Qt < 5.5 (10xcryptodev)
+- #15768 Add close window shortcut (IPGlider)
+- #16224 Bilingual GUI error messages (hebasto)
+- #18922 Do not translate InitWarning messages in debug.log (hebasto)
+- #18152 Use NotificationStatus enum for signals to GUI (hebasto)
+- #18587 Avoid wallet tryGetBalances calls in WalletModel::pollBalanceChanged (ryanofsky)
+- #17597 Fix height of QR-less ReceiveRequestDialog (hebasto)
+- #17918 Hide non PKHash-Addresses in signing address book (emilengler)
+- #17956 Disable unavailable context menu items in transactions tab (kristapsk)
+- #17968 Ensure that ModalOverlay is resized properly (hebasto)
+- #17993 Balance/TxStatus polling update based on last block hash (furszy)
+- #18424 Use parent-child relation to manage lifetime of OptionsModel object (hebasto)
+- #18452 Fix shutdown when `waitfor*` cmds are called from RPC console (hebasto)
+- #15202 Add Close All Wallets action (promag)
+- #19132 lock `cs_main`, `m_cached_tip_mutex` in that order (vasild)
+- #18898 Display warnings as rich text (hebasto)
+- #19231 add missing translation.h include to fix build (fanquake)
+- #18027 "PSBT Operations" dialog (gwillen)
+- #19256 Change combiner for signals to `optional_last_value` (fanquake)
+- #18896 Reset toolbar after all wallets are closed (hebasto)
+- #18993 increase console command max length (10xcryptodev)
+- #19323 Fix regression in *txoutset* in GUI console (hebasto)
+- #19210 Get rid of cursor in out-of-focus labels (hebasto)
+- #19011 Reduce `cs_main` lock accumulation during GUI startup (jonasschnelli)
+- #19844 Remove usage of boost::bind (fanquake)
+- #20479 Fix QPainter non-determinism on macOS (0.21 backport) (laanwj)
+- gui#6 Do not truncate node flag strings in debugwindow peers details tab (Saibato)
+- gui#8 Fix regression in TransactionTableModel (hebasto)
+- gui#17 doc: Remove outdated comment in TransactionTablePriv (MarcoFalke)
+- gui#20 Wrap tooltips in the intro window (hebasto)
+- gui#30 Disable the main window toolbar when the modal overlay is shown (hebasto)
+- gui#34 Show permissions instead of whitelisted (laanwj)
+- gui#35 Parse params directly instead of through node (ryanofsky)
+- gui#39 Add visual accenting for the 'Create new receiving address' button (hebasto)
+- gui#40 Clarify block height label (hebasto)
+- gui#43 bugfix: Call setWalletActionsEnabled(true) only for the first wallet (hebasto)
+- gui#97 Relax GUI freezes during IBD (jonasschnelli)
+- gui#71 Fix visual quality of text in QR image (hebasto)
+- gui#96 Slight improve create wallet dialog (Sjors)
+- gui#102 Fix SplashScreen crash when run with -disablewallet (hebasto)
+- gui#116 Fix unreasonable default size of the main window without loaded wallets (hebasto)
+- gui#120 Fix multiwallet transaction notifications (promag)
+
+### Build system
+- #18504 Drop bitcoin-tx and bitcoin-wallet dependencies on libevent (ryanofsky)
+- #18586 Bump gitian descriptors to 0.21 (laanwj)
+- #17595 guix: Enable building for `x86_64-w64-mingw32` target (dongcarl)
+- #17929 add linker optimisation flags to gitian & guix (Linux) (fanquake)
+- #18556 Drop make dist in gitian builds (hebasto)
+- #18088 ensure we aren't using GNU extensions (fanquake)
+- #18741 guix: Make source tarball using git-archive (dongcarl)
+- #18843 warn on potentially uninitialized reads (vasild)
+- #17874 make linker checks more robust (fanquake)
+- #18535 remove -Qunused-arguments workaround for clang + ccache (fanquake)
+- #18743 Add --sysroot option to mac os native compile flags (ryanofsky)
+- #18216 test, build: Enable -Werror=sign-compare (Empact)
+- #18928 don't pass -w when building for Windows (fanquake)
+- #16710 Enable -Wsuggest-override if available (hebasto)
+- #18738 Suppress -Wdeprecated-copy warnings (hebasto)
+- #18862 Remove fdelt_chk back-compat code and sanity check (fanquake)
+- #18887 enable -Werror=gnu (vasild)
+- #18956 enforce minimum required Windows version (7) (fanquake)
+- #18958 guix: Make V=1 more powerful for debugging (dongcarl)
+- #18677 Multiprocess build support (ryanofsky)
+- #19094 Only allow ASCII identifiers (laanwj)
+- #18820 Propagate well-known vars into depends (dongcarl)
+- #19173 turn on --enable-c++17 by --enable-fuzz (vasild)
+- #18297 Use pkg-config in BITCOIN_QT_CONFIGURE for all hosts including Windows (hebasto)
+- #19301 don't warn when doxygen isn't found (fanquake)
+- #19240 macOS toolchain simplification and bump (dongcarl)
+- #19356 Fix search for brew-installed BDB 4 on OS X (gwillen)
+- #19394 Remove unused `RES_IMAGES` (Bushstar)
+- #19403 improve `__builtin_clz*` detection (fanquake)
+- #19375 target Windows 7 when building libevent and fix ipv6 usage (fanquake)
+- #19331 Do not include server symbols in wallet (MarcoFalke)
+- #19257 remove BIP70 configure option (fanquake)
+- #18288 Add MemorySanitizer (MSan) in Travis to detect use of uninitialized memory (practicalswift)
+- #18307 Require pkg-config for all of the hosts (hebasto)
+- #19445 Update msvc build to use ISO standard C++17 (sipsorcery)
+- #18882 fix -Wformat-security check when compiling with GCC (fanquake)
+- #17919 Allow building with system clang (dongcarl)
+- #19553 pass -fcommon when building genisoimage (fanquake)
+- #19565 call `AC_PATH_TOOL` for dsymutil in macOS cross-compile (fanquake)
+- #19530 build LTO support into Apple's ld64 (theuni)
+- #19525 add -Wl,-z,separate-code to hardening flags (fanquake)
+- #19667 set minimum required Boost to 1.58.0 (fanquake)
+- #19672 make clean removes .gcda and .gcno files from fuzz directory (Crypt-iQ)
+- #19622 Drop ancient hack in gitian-linux descriptor (hebasto)
+- #19688 Add support for llvm-cov (hebasto)
+- #19718 Add missed gcov files to 'make clean' (hebasto)
+- #19719 Add Werror=range-loop-analysis (MarcoFalke)
+- #19015 Enable some commonly enabled compiler diagnostics (practicalswift)
+- #19689 build, qt: Add Qt version checking (hebasto)
+- #17396 modest Android improvements (icota)
+- #18405 Drop all of the ZeroMQ patches (hebasto)
+- #15704 Move Win32 defines to configure.ac to ensure they are globally defined (luke-jr)
+- #19761 improve sed robustness by not using sed (fanquake)
+- #19758 Drop deprecated and unused `GUARDED_VAR` and `PT_GUARDED_VAR` annotations (hebasto)
+- #18921 add stack-clash and control-flow protection options to hardening flags (fanquake)
+- #19803 Bugfix: Define and use `HAVE_FDATASYNC` correctly outside LevelDB (luke-jr)
+- #19685 CMake invocation cleanup (dongcarl)
+- #19861 add /usr/local/ to `LCOV_FILTER_PATTERN` for macOS builds (Crypt-iQ)
+- #19916 allow user to specify `DIR_FUZZ_SEED_CORPUS` for `cov_fuzz` (Crypt-iQ)
+- #19944 Update secp256k1 subtree (including BIP340 support) (sipa)
+- #19558 Split pthread flags out of ldflags and dont use when building libconsensus (fanquake)
+- #19959 patch qt libpng to fix powerpc build (fanquake)
+- #19868 Fix target name (hebasto)
+- #19960 The vcpkg tool has introduced a proper way to use manifests (sipsorcery)
+- #20065 fuzz: Configure check for main function (MarcoFalke)
+- #18750 Optionally skip external warnings (vasild)
+- #20147 Update libsecp256k1 (endomorphism, test improvements) (sipa)
+- #20156 Make sqlite support optional (compile-time) (luke-jr)
+- #20318 Ensure source tarball has leading directory name (MarcoFalke)
+- #20447 Patch `qt_intersect_spans` to avoid non-deterministic behavior in LLVM 8 (achow101)
+- #20505 Avoid secp256k1.h include from system (dergoegge)
+- #20527 Do not ignore Homebrew's SQLite on macOS (hebasto)
+- #20478 Don't set BDB flags when configuring without (jonasschnelli)
+- #20563 Check that Homebrew's berkeley-db4 package is actually installed (hebasto)
+- #19493 Fix clang build on Mac (bvbfan)
+
+### Tests and QA
+- #18593 Complete impl. of `msg_merkleblock` and `wait_for_merkleblock` (theStack)
+- #18609 Remove REJECT message code (hebasto)
+- #18584 Check that the version message does not leak the local address (MarcoFalke)
+- #18597 Extend `wallet_dump` test to cover comments (MarcoFalke)
+- #18596 Try once more when RPC connection fails on Windows (MarcoFalke)
+- #18451 shift coverage from getunconfirmedbalance to getbalances (jonatack)
+- #18631 appveyor: Disable functional tests for now (MarcoFalke)
+- #18628 Add various low-level p2p tests (MarcoFalke)
+- #18615 Avoid accessing free'd memory in `validation_chainstatemanager_tests` (MarcoFalke)
+- #18571 fuzz: Disable debug log file (MarcoFalke)
+- #18653 add coverage for bitcoin-cli -rpcwait (jonatack)
+- #18660 Verify findCommonAncestor always initializes outputs (ryanofsky)
+- #17669 Have coins simulation test also use CCoinsViewDB (jamesob)
+- #18662 Replace gArgs with local argsman in bench (MarcoFalke)
+- #18641 Create cached blocks not in the future (MarcoFalke)
+- #18682 fuzz: `http_request` workaround for libevent < 2.1.1 (theStack)
+- #18692 Bump timeout in `wallet_import_rescan` (MarcoFalke)
+- #18695 Replace boost::mutex with std::mutex (hebasto)
+- #18633 Properly raise FailedToStartError when rpc shutdown before warmup finished (MarcoFalke)
+- #18675 Don't initialize PrecomputedTransactionData in txvalidationcache tests (jnewbery)
+- #18691 Add `wait_for_cookie_credentials()` to framework for rpcwait tests (jonatack)
+- #18672 Add further BIP37 size limit checks to `p2p_filter.py` (theStack)
+- #18721 Fix linter issue (hebasto)
+- #18384 More specific `feature_segwit` test error messages and fixing incorrect comments (gzhao408)
+- #18575 bench: Remove requirement that all benches use same testing setup (MarcoFalke)
+- #18690 Check object hashes in `wait_for_getdata` (robot-visions)
+- #18712 display command line options passed to `send_cli()` in debug log (jonatack)
+- #18745 Check submitblock return values (MarcoFalke)
+- #18756 Use `wait_for_getdata()` in `p2p_compactblocks.py` (theStack)
+- #18724 Add coverage for -rpcwallet cli option (jonatack)
+- #18754 bench: Add caddrman benchmarks (vasild)
+- #18585 Use zero-argument super() shortcut (Python 3.0+) (theStack)
+- #18688 fuzz: Run in parallel (MarcoFalke)
+- #18770 Remove raw-tx byte juggling in `mempool_reorg` (MarcoFalke)
+- #18805 Add missing `sync_all` to `wallet_importdescriptors.py` (achow101)
+- #18759 bench: Start nodes with -nodebuglogfile (MarcoFalke)
+- #18774 Added test for upgradewallet RPC (brakmic)
+- #18485 Add `mempool_updatefromblock.py` (hebasto)
+- #18727 Add CreateWalletFromFile test (ryanofsky)
+- #18726 Check misbehavior more independently in `p2p_filter.py` (robot-visions)
+- #18825 Fix message for `ECC_InitSanityCheck` test (fanquake)
+- #18576 Use unittest for `test_framework` unit testing (gzhao408)
+- #18828 Strip down previous releases boilerplate (MarcoFalke)
+- #18617 Add factor option to adjust test timeouts (brakmic)
+- #18855 `feature_backwards_compatibility.py` test downgrade after upgrade (achow101)
+- #18864 Add v0.16.3 backwards compatibility test, bump v0.19.0.1 to v0.19.1 (Sjors)
+- #18917 fuzz: Fix vector size problem in system fuzzer (brakmic)
+- #18901 fuzz: use std::optional for `sep_pos_opt` variable (brakmic)
+- #18888 Remove RPCOverloadWrapper boilerplate (MarcoFalke)
+- #18952 Avoid os-dependent path (fametrano)
+- #18938 Fill fuzzing coverage gaps for functions in consensus/validation.h, primitives/block.h and util/translation.h (practicalswift)
+- #18986 Add capability to disable RPC timeout in functional tests (rajarshimaitra)
+- #18530 Add test for -blocksonly and -whitelistforcerelay param interaction (glowang)
+- #19014 Replace `TEST_PREVIOUS_RELEASES` env var with `test_framework` option (MarcoFalke)
+- #19052 Don't limit fuzzing inputs to 1 MB for afl-fuzz (now: ∞ ∀ fuzzers) (practicalswift)
+- #19060 Remove global `wait_until` from `p2p_getdata` (MarcoFalke)
+- #18926 Pass ArgsManager into `getarg_tests` (glowang)
+- #19110 Explain that a bug should be filed when the tests fail (MarcoFalke)
+- #18965 Implement `base58_decode` (10xcryptodev)
+- #16564 Always define the `raii_event_tests` test suite (candrews)
+- #19122 Add missing `sync_blocks` to `wallet_hd` (MarcoFalke)
+- #18875 fuzz: Stop nodes in `process_message*` fuzzers (MarcoFalke)
+- #18974 Check that invalid witness destinations can not be imported (MarcoFalke)
+- #18210 Type hints in Python tests (kiminuo)
+- #19159 Make valgrind.supp work on aarch64 (MarcoFalke)
+- #19082 Moved the CScriptNum asserts into the unit test in script.py (gillichu)
+- #19172 Do not swallow flake8 exit code (hebasto)
+- #19188 Avoid overwriting the NodeContext member of the testing setup [-Wshadow-field] (MarcoFalke)
+- #18890 `disconnect_nodes` should warn if nodes were already disconnected (robot-visions)
+- #19227 change blacklist to blocklist (TrentZ)
+- #19230 Move base58 to own module to break circular dependency (sipa)
+- #19083 `msg_mempool`, `fRelay`, and other bloomfilter tests (gzhao408)
+- #16756 Connection eviction logic tests (mzumsande)
+- #19177 Fix and clean `p2p_invalid_messages` functional tests (troygiorshev)
+- #19264 Don't import asyncio to test magic bytes (jnewbery)
+- #19178 Make `mininode_lock` non-reentrant (jnewbery)
+- #19153 Mempool compatibility test (S3RK)
+- #18434 Add a test-security target and run it in CI (fanquake)
+- #19252 Wait for disconnect in `disconnect_p2ps` + bloomfilter test followups (gzhao408)
+- #19298 Add missing `sync_blocks` (MarcoFalke)
+- #19304 Check that message sends successfully when header is split across two buffers (troygiorshev)
+- #19208 move `sync_blocks` and `sync_mempool` functions to `test_framework.py` (ycshao)
+- #19198 Check that peers with forcerelay permission are not asked to feefilter (MarcoFalke)
+- #19351 add two edge case tests for CSubNet (vasild)
+- #19272 net, test: invalid p2p messages and test framework improvements (jonatack)
+- #19348 Bump linter versions (duncandean)
+- #19366 Provide main(…) function in fuzzer. Allow building uninstrumented harnesses with --enable-fuzz (practicalswift)
+- #19412 move `TEST_RUNNER_EXTRA` into native tsan setup (fanquake)
+- #19368 Improve functional tests compatibility with BSD/macOS (S3RK)
+- #19028 Set -logthreadnames in unit tests (MarcoFalke)
+- #18649 Add std::locale::global to list of locale dependent functions (practicalswift)
+- #19140 Avoid fuzzer-specific nullptr dereference in libevent when handling PROXY requests (practicalswift)
+- #19214 Auto-detect SHA256 implementation in benchmarks (sipa)
+- #19353 Fix mistakenly swapped "previous" and "current" lock orders (hebasto)
+- #19533 Remove unnecessary `cs_mains` in `denialofservice_tests` (jnewbery)
+- #19423 add functional test for txrelay during and after IBD (gzhao408)
+- #16878 Fix non-deterministic coverage of test `DoS_mapOrphans` (davereikher)
+- #19548 fuzz: add missing overrides to `signature_checker` (jonatack)
+- #19562 Fix fuzzer compilation on macOS (freenancial)
+- #19370 Static asserts for consistency of fee defaults (domob1812)
+- #19599 clean `message_count` and `last_message` (troygiorshev)
+- #19597 test decodepsbt fee calculation (count input value only once per UTXO) (theStack)
+- #18011 Replace current benchmarking framework with nanobench (martinus)
+- #19489 Fail `wait_until` early if connection is lost (MarcoFalke)
+- #19340 Preserve the `LockData` initial state if "potential deadlock detected" exception thrown (hebasto)
+- #19632 Catch decimal.InvalidOperation from `TestNodeCLI#send_cli` (Empact)
+- #19098 Remove duplicate NodeContext hacks (ryanofsky)
+- #19649 Restore test case for p2p transaction blinding (instagibbs)
+- #19657 Wait until `is_connected` in `add_p2p_connection` (MarcoFalke)
+- #19631 Wait for 'cmpctblock' in `p2p_compactblocks` when it is expected (Empact)
+- #19674 use throwaway _ variable for unused loop counters (theStack)
+- #19709 Fix 'make cov' with clang (hebasto)
+- #19564 `p2p_feefilter` improvements (logging, refactoring, speedup) (theStack)
+- #19756 add `sync_all` to fix race condition in wallet groups test (kallewoof)
+- #19727 Removing unused classes from `p2p_leak.py` (dhruv)
+- #19722 Add test for getblockheader verboseness (torhte)
+- #19659 Add a seed corpus generation option to the fuzzing `test_runner` (darosior)
+- #19775 Activate segwit in TestChain100Setup (MarcoFalke)
+- #19760 Remove confusing mininode terminology (jnewbery)
+- #19752 Update `wait_until` usage in tests not to use the one from utils (slmtpz)
+- #19839 Set appveyor VM version to previous Visual Studio 2019 release (sipsorcery)
+- #19830 Add tsan supp for leveldb::DBImpl::DeleteObsoleteFiles (MarcoFalke)
+- #19710 bench: Prevent thread oversubscription and decreases the variance of result values (hebasto)
+- #19842 Update the vcpkg checkout commit ID in appveyor config (sipsorcery)
+- #19507 Expand functional zmq transaction tests (instagibbs)
+- #19816 Rename wait until helper to `wait_until_helper` (MarcoFalke)
+- #19859 Fixes failing functional test by changing version (n-thumann)
+- #19887 Fix flaky `wallet_basic` test (fjahr)
+- #19897 Change `FILE_CHAR_BLOCKLIST` to `FILE_CHARS_DISALLOWED` (verretor)
+- #19800 Mockwallet (MarcoFalke)
+- #19922 Run `rpc_txoutproof.py` even with wallet disabled (MarcoFalke)
+- #19936 batch rpc with params (instagibbs)
+- #19971 create default wallet in extended tests (Sjors)
+- #19781 add parameterized constructor for `msg_sendcmpct()` (theStack)
+- #19963 Clarify blocksonly whitelistforcerelay test (t-bast)
+- #20022 Use explicit p2p objects where available (guggero)
+- #20028 Check that invalid peer traffic is accounted for (MarcoFalke)
+- #20004 Add signet witness commitment section parse tests (MarcoFalke)
+- #20034 Get rid of default wallet hacks (ryanofsky)
+- #20069 Mention commit id in scripted diff error (laanwj)
+- #19947 Cover `change_type` option of "walletcreatefundedpsbt" RPC (guggero)
+- #20126 `p2p_leak_tx.py` improvements (use MiniWallet, add `p2p_lock` acquires) (theStack)
+- #20129 Don't export `in6addr_loopback` (vasild)
+- #20131 Remove unused nVersion=1 in p2p tests (MarcoFalke)
+- #20161 Minor Taproot follow-ups (sipa)
+- #19401 Use GBT to get block versions correct (luke-jr)
+- #20159 `mining_getblocktemplate_longpoll.py` improvements (use MiniWallet, add logging) (theStack)
+- #20039 Convert amounts from float to decimal (prayank23)
+- #20112 Speed up `wallet_resendwallettransactions` with mockscheduler RPC (MarcoFalke)
+- #20247 fuzz: Check for addrv1 compatibility before using addrv1 serializer. Fuzz addrv2 serialization (practicalswift)
+- #20167 Add test for -blockversion (MarcoFalke)
+- #19877 Clarify `rpc_net` & `p2p_disconnect_ban functional` tests (amitiuttarwar)
+- #20258 Remove getnettotals/getpeerinfo consistency test (jnewbery)
+- #20242 fuzz: Properly initialize PrecomputedTransactionData (MarcoFalke)
+- #20262 Skip --descriptor tests if sqlite is not compiled (achow101)
+- #18788 Update more tests to work with descriptor wallets (achow101)
+- #20289 fuzz: Check for addrv1 compatibility before using addrv1 serializer/deserializer on CService (practicalswift)
+- #20290 fuzz: Fix DecodeHexTx fuzzing harness issue (practicalswift)
+- #20245 Run `script_assets_test` even if built --with-libs=no (MarcoFalke)
+- #20300 fuzz: Add missing `ECC_Start` to `descriptor_parse` test (S3RK)
+- #20283 Only try witness deser when checking for witness deser failure (MarcoFalke)
+- #20303 fuzz: Assert expected DecodeHexTx behaviour when using legacy decoding (practicalswift)
+- #20316 Fix `wallet_multiwallet` test issue on Windows (MarcoFalke)
+- #20326 Fix `ecdsa_verify` in test framework (stepansnigirev)
+- #20328 cirrus: Skip tasks on the gui repo main branch (MarcoFalke)
+- #20355 fuzz: Check for addrv1 compatibility before using addrv1 serializer/deserializer on CSubNet (practicalswift)
+- #20332 Mock IBD in `net_processing` fuzzers (MarcoFalke)
+- #20218 Suppress `epoll_ctl` data race (MarcoFalke)
+- #20375 fuzz: Improve coverage for CPartialMerkleTree fuzzing harness (practicalswift)
+- #19669 contrib: Fixup valgrind suppressions file (MarcoFalke)
+- #18879 valgrind: remove outdated suppressions (fanquake)
+- #19226 Add BerkeleyDatabase tsan suppression (MarcoFalke)
+- #20379 Remove no longer needed UBSan suppression (float divide-by-zero in validation.cpp) (practicalswift)
+- #18190, #18736, #18744, #18775, #18783, #18867, #18994, #19065,
+ #19067, #19143, #19222, #19247, #19286, #19296, #19379, #19934,
+ #20188, #20395 Add fuzzing harnessses (practicalswift)
+- #18638 Use mockable time for ping/pong, add tests (MarcoFalke)
+- #19951 CNetAddr scoped ipv6 test coverage, rename scopeId to `m_scope_id` (jonatack)
+- #20027 Use mockable time everywhere in `net_processing` (sipa)
+- #19105 Add Muhash3072 implementation in Python (fjahr)
+- #18704, #18752, #18753, #18765, #18839, #18866, #18873, #19022,
+ #19023, #19429, #19552, #19778, #20176, #20179, #20214, #20292,
+ #20299, #20322 Fix intermittent test issues (MarcoFalke)
+- #20390 CI/Cirrus: Skip `merge_base` step for non-PRs (luke-jr)
+- #18634 ci: Add fuzzbuzz integration configuration file (practicalswift)
+- #18591 Add C++17 build to Travis (sipa)
+- #18581, #18667, #18798, #19495, #19519, #19538 CI improvements (hebasto)
+- #18683, #18705, #18735, #18778, #18799, #18829, #18912, #18929,
+ #19008, #19041, #19164, #19201, #19267, #19276, #19321, #19371,
+ #19427, #19730, #19746, #19881, #20294, #20339, #20368 CI improvements (MarcoFalke)
+- #20489, #20506 MSVC CI improvements (sipsorcery)
+
+### Miscellaneous
+- #18713 scripts: Add macho stack canary check to security-check.py (fanquake)
+- #18629 scripts: Add pe .reloc section check to security-check.py (fanquake)
+- #18437 util: `Detect posix_fallocate()` instead of assuming (vasild)
+- #18413 script: Prevent ub when computing abs value for num opcode serialize (pierreN)
+- #18443 lockedpool: avoid sensitive data in core files (FreeBSD) (vasild)
+- #18885 contrib: Move optimize-pngs.py script to the maintainer repo (MarcoFalke)
+- #18317 Serialization improvements step 6 (all except wallet/gui) (sipa)
+- #16127 More thread safety annotation coverage (ajtowns)
+- #19228 Update libsecp256k1 subtree (sipa)
+- #19277 util: Add assert identity function (MarcoFalke)
+- #19491 util: Make assert work with any value (MarcoFalke)
+- #19205 script: `previous_release.sh` rewritten in python (bliotti)
+- #15935 Add <datadir>/settings.json persistent settings storage (ryanofsky)
+- #19439 script: Linter to check commit message formatting (Ghorbanian)
+- #19654 lint: Improve commit message linter in travis (fjahr)
+- #15382 util: Add runcommandparsejson (Sjors)
+- #19614 util: Use `have_fdatasync` to determine fdatasync() use (fanquake)
+- #19813 util, ci: Hard code previous release tarball checksums (hebasto)
+- #19841 Implement Keccak and `SHA3_256` (sipa)
+- #19643 Add -netinfo peer connections dashboard (jonatack)
+- #15367 feature: Added ability for users to add a startup command (benthecarman)
+- #19984 log: Remove static log message "Initializing chainstate Chainstate [ibd] @ height -1 (null)" (practicalswift)
+- #20092 util: Do not use gargs global in argsmanager member functions (hebasto)
+- #20168 contrib: Fix `gen_key_io_test_vectors.py` imports (MarcoFalke)
+- #19624 Warn on unknown `rw_settings` (MarcoFalke)
+- #20257 Update secp256k1 subtree to latest master (sipa)
+- #20346 script: Modify security-check.py to use "==" instead of "is" for literal comparison (tylerchambers)
+- #18881 Prevent UB in DeleteLock() function (hebasto)
+- #19180, #19189, #19190, #19220, #19399 Replace RecursiveMutex with Mutex (hebasto)
+- #19347 Make `cs_inventory` nonrecursive (jnewbery)
+- #19773 Avoid recursive lock in IsTrusted (promag)
+- #18790 Improve thread naming (hebasto)
+- #20140 Restore compatibility with old CSubNet serialization (sipa)
+- #17775 DecodeHexTx: Try case where txn has inputs first (instagibbs)
+
+### Documentation
+- #18502 Update docs for getbalance (default minconf should be 0) (uzyn)
+- #18632 Fix macos comments in release-notes (MarcoFalke)
+- #18645 Update thread information in developer docs (jnewbery)
+- #18709 Note why we can't use `thread_local` with glibc back compat (fanquake)
+- #18410 Improve commenting for coins.cpp|h (jnewbery)
+- #18157 fixing init.md documentation to not require rpcpassword (jkcd)
+- #18739 Document how to fuzz Bitcoin Core using Honggfuzz (practicalswift)
+- #18779 Better explain GNU ld's dislike of ld64's options (fanquake)
+- #18663 Mention build docs in README.md (saahilshangle)
+- #18810 Update rest info on block size and json (chrisabrams)
+- #18939 Add c++17-enable flag to fuzzing instructions (mzumsande)
+- #18957 Add a link from ZMQ doc to ZMQ example in contrib/ (meeDamian)
+- #19058 Drop protobuf stuff (hebasto)
+- #19061 Add link to Visual Studio build readme (maitrebitcoin)
+- #19072 Expand section on Getting Started (MarcoFalke)
+- #18968 noban precludes maxuploadtarget disconnects (MarcoFalke)
+- #19005 Add documentation for 'checklevel' argument in 'verifychain' RPC… (kcalvinalvin)
+- #19192 Extract net permissions doc (MarcoFalke)
+- #19071 Separate repository for the gui (MarcoFalke)
+- #19018 fixing description of the field sequence in walletcreatefundedpsbt RPC method (limpbrains)
+- #19367 Span pitfalls (sipa)
+- #19408 Windows WSL build recommendation to temporarily disable Win32 PE support (sipsorcery)
+- #19407 explain why passing -mlinker-version is required when cross-compiling (fanquake)
+- #19452 afl fuzzing comment about afl-gcc and afl-g++ (Crypt-iQ)
+- #19258 improve subtree check instructions (Sjors)
+- #19474 Use precise permission flags where possible (MarcoFalke)
+- #19494 CONTRIBUTING.md improvements (jonatack)
+- #19268 Add non-thread-safe note to FeeFilterRounder::round() (hebasto)
+- #19547 Update macOS cross compilation dependencies for Focal (hebasto)
+- #19617 Clang 8 or later is required with `FORCE_USE_SYSTEM_CLANG` (fanquake)
+- #19639 Remove Reference Links #19582 (RobertHosking)
+- #19605 Set `CC_FOR_BUILD` when building on OpenBSD (fanquake)
+- #19765 Fix getmempoolancestors RPC result doc (MarcoFalke)
+- #19786 Remove label from good first issue template (MarcoFalke)
+- #19646 Updated outdated help command for getblocktemplate (jakeleventhal)
+- #18817 Document differences in bitcoind and bitcoin-qt locale handling (practicalswift)
+- #19870 update PyZMQ install instructions, fix `zmq_sub.py` file permissions (jonatack)
+- #19903 Update build-openbsd.md with GUI support (grubles)
+- #19241 help: Generate checkpoint height from chainparams (luke-jr)
+- #18949 Add CODEOWNERS file to automatically nominate PR reviewers (adamjonas)
+- #20014 Mention signet in -help output (hebasto)
+- #20015 Added default signet config for linearize script (gr0kchain)
+- #19958 Better document features of feelers (naumenkogs)
+- #19871 Clarify scope of eviction protection of outbound block-relay peers (ariard)
+- #20076 Update and improve files.md (hebasto)
+- #20107 Collect release-notes snippets (MarcoFalke)
+- #20109 Release notes and followups from 19339 (glozow)
+- #20090 Tiny followups to new getpeerinfo connection type field (amitiuttarwar)
+- #20152 Update wallet files in files.md (hebasto)
+- #19124 Document `ALLOW_HOST_PACKAGES` dependency option (skmcontrib)
+- #20271 Document that wallet salvage is experimental (MarcoFalke)
+- #20281 Correct getblockstats documentation for `(sw)total_weight` (shesek)
+- #20279 release process updates/fixups (jonatack)
+- #20238 Missing comments for signet parameters (decryp2kanon)
+- #20756 Add missing field (permissions) to the getpeerinfo help (amitiuttarwar)
+- #20668 warn that incoming conns are unlikely when not using default ports (adamjonas)
+- #19961 tor.md updates (jonatack)
+- #19050 Add warning for rest interface limitation (fjahr)
+- #19390 doc/REST-interface: Remove stale info (luke-jr)
+- #19344 docs: update testgen usage example (Bushstar)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 10xcryptodev
+- Aaron Clauson
+- Aaron Hook
+- Adam Jonas
+- Adam Soltys
+- Adam Stein
+- Akio Nakamura
+- Alex Willmer
+- Amir Ghorbanian
+- Amiti Uttarwar
+- Andrew Chow
+- Andrew Toth
+- Anthony Fieroni
+- Anthony Towns
+- Antoine Poinsot
+- Antoine Riard
+- Ben Carman
+- Ben Woosley
+- Benoit Verret
+- Brian Liotti
+- Bushstar
+- Calvin Kim
+- Carl Dong
+- Chris Abrams
+- Chris L
+- Christopher Coverdale
+- codeShark149
+- Cory Fields
+- Craig Andrews
+- Damian Mee
+- Daniel Kraft
+- Danny Lee
+- David Reikher
+- DesWurstes
+- Dhruv Mehta
+- Duncan Dean
+- Elichai Turkel
+- Elliott Jin
+- Emil Engler
+- Ethan Heilman
+- eugene
+- Fabian Jahr
+- fanquake
+- Ferdinando M. Ametrano
+- freenancial
+- furszy
+- Gillian Chu
+- Gleb Naumenko
+- Glenn Willen
+- Gloria Zhao
+- glowang
+- gr0kchain
+- Gregory Sanders
+- grubles
+- gzhao408
+- Harris
+- Hennadii Stepanov
+- Hugo Nguyen
+- Igor Cota
+- Ivan Metlushko
+- Ivan Vershigora
+- Jake Leventhal
+- James O'Beirne
+- Jeremy Rubin
+- jgmorgan
+- Jim Posen
+- “jkcd”
+- jmorgan
+- John Newbery
+- Johnson Lau
+- Jon Atack
+- Jonas Schnelli
+- Jonathan Schoeller
+- João Barbosa
+- Justin Moon
+- kanon
+- Karl-Johan Alm
+- Kiminuo
+- Kristaps Kaupe
+- lontivero
+- Luke Dashjr
+- Marcin Jachymiak
+- MarcoFalke
+- Martin Ankerl
+- Martin Zumsande
+- maskoficarus
+- Matt Corallo
+- Matthew Zipkin
+- MeshCollider
+- Miguel Herranz
+- MIZUTA Takeshi
+- mruddy
+- Nadav Ivgi
+- Neha Narula
+- Nicolas Thumann
+- Niklas Gögge
+- Nima Yazdanmehr
+- nsa
+- nthumann
+- Oliver Gugger
+- pad
+- pasta
+- Peter Bushnell
+- pierrenn
+- Pieter Wuille
+- practicalswift
+- Prayank
+- Raúl Martínez (RME)
+- RandyMcMillan
+- Rene Pickhardt
+- Riccardo Masutti
+- Robert
+- Rod Vagg
+- Roy Shao
+- Russell Yanofsky
+- Saahil Shangle
+- sachinkm77
+- saibato
+- Samuel Dobson
+- sanket1729
+- Sebastian Falbesoner
+- Seleme Topuz
+- Sishir Giri
+- Sjors Provoost
+- skmcontrib
+- Stepan Snigirev
+- Stephan Oeste
+- Suhas Daftuar
+- t-bast
+- Tom Harding
+- Torhte Butler
+- TrentZ
+- Troy Giorshev
+- tryphe
+- Tyler Chambers
+- U-Zyn Chua
+- Vasil Dimov
+- wiz
+- Wladimir J. van der Laan
+
+As well as to everyone that helped with translations on
+[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
diff --git a/doc/release-process.md b/doc/release-process.md
index cedb36d51d..9fdb19edf1 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -307,9 +307,9 @@ bitcoin.org (see below for bitcoin.org update instructions).
- First, check to see if the Bitcoin.org maintainers have prepared a
release: https://github.com/bitcoin-dot-org/bitcoin.org/labels/Core
- - If they have, it will have previously failed their Travis CI
+ - If they have, it will have previously failed their CI
checks because the final release files weren't uploaded.
- Trigger a Travis CI rebuild---if it passes, merge.
+ Trigger a CI rebuild---if it passes, merge.
- If they have not prepared a release, follow the Bitcoin.org release
instructions: https://github.com/bitcoin-dot-org/bitcoin.org/blob/master/docs/adding-events-release-notes-and-alerts.md#release-notes
@@ -326,6 +326,18 @@ bitcoin.org (see below for bitcoin.org update instructions).
- bitcoincore.org RPC documentation update
+ - Install [golang](https://golang.org/doc/install)
+
+ - Install the new Bitcoin Core release
+
+ - Run bitcoind on regtest
+
+ - Clone the [bitcoincore.org repository](https://github.com/bitcoin-core/bitcoincore.org)
+
+ - Run: `go run generate.go` while being in `contrib/doc-gen` folder, and with bitcoin-cli in PATH
+
+ - Add the generated files to git
+
- Update packaging repo
- Push the flatpak to flathub, e.g. https://github.com/flathub/org.bitcoincore.bitcoin-qt/pull/2
diff --git a/doc/tor.md b/doc/tor.md
index 86e5d9ddf3..8a2aef2d07 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -23,14 +23,19 @@ outgoing connections, but more is possible.
-proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy
server will be used to try to reach .onion addresses as well.
+ You need to use -noonion or -onion=0 to explicitly disable
+ outbound access to onion services.
-onion=ip:port Set the proxy server to use for Tor onion services. You do not
- need to set this if it's the same as -proxy. You can use -noonion
+ need to set this if it's the same as -proxy. You can use -onion=0
to explicitly disable access to onion services.
+ Note: Only the -proxy option sets the proxy for DNS requests;
+ with -onion they will not route over Tor, so use -proxy if you
+ have privacy concerns.
-listen When using -proxy, listening is disabled by default. If you want
- to run an onion service (see next section), you'll need to enable
- it explicitly.
+ to manually configure an onion service (see section 3), you'll
+ need to enable it explicitly.
-connect=X When behind a Tor proxy, you can specify .onion addresses instead
-addnode=X of IP addresses or hostnames in these parameters. It requires
@@ -40,19 +45,112 @@ outgoing connections, but more is possible.
-onlynet=onion Make outgoing connections only to .onion addresses. Incoming
connections are not affected by this option. This option can be
specified multiple times to allow multiple network types, e.g.
- ipv4, ipv6, or onion.
+ ipv4, ipv6 or onion. If you use this option with values other
+ than onion you *cannot* disable onion connections; outgoing onion
+ connections will be enabled when you use -proxy or -onion. Use
+ -noonion or -onion=0 if you want to be sure there are no outbound
+ onion connections over the default proxy or your defined -proxy.
In a typical situation, this suffices to run behind a Tor proxy:
./bitcoind -proxy=127.0.0.1:9050
+## 2. Automatically create a Bitcoin Core onion service
-## 2. Manually create a Bitcoin Core onion service
+Bitcoin Core makes use of Tor's control socket API to create and destroy
+ephemeral onion services programmatically. This means that if Tor is running and
+proper authentication has been configured, Bitcoin Core automatically creates an
+onion service to listen on. The goal is to increase the number of available
+onion nodes.
-If you configure your Tor system accordingly, it is possible to make your node also
-reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent
-config file): *Needed for Tor version 0.2.7.0 and older versions of Tor only. For newer
-versions of Tor see [Section 3](#3-automatically-listen-on-tor).*
+This feature is enabled by default if Bitcoin Core is listening (`-listen`) and
+it requires a Tor connection to work. It can be explicitly disabled with
+`-listenonion=0`. If it is not disabled, it can be configured using the
+`-torcontrol` and `-torpassword` settings.
+
+To see verbose Tor information in the bitcoind debug log, pass `-debug=tor`.
+
+### Control Port
+
+You may need to set up the Tor Control Port. On Linux distributions there may be
+some or all of the following settings in `/etc/tor/torrc`, generally commented
+out by default (if not, add them):
+
+```
+ControlPort 9051
+CookieAuthentication 1
+CookieAuthFileGroupReadable 1
+```
+
+Add or uncomment those, save, and restart Tor (usually `systemctl restart tor`
+or `sudo systemctl restart tor` on most systemd-based systems, including recent
+Debian and Ubuntu, or just restart the computer).
+
+On some systems (such as Arch Linux), you may also need to add the following
+line:
+
+```
+DataDirectoryGroupReadable 1
+```
+
+### Authentication
+
+Connecting to Tor's control socket API requires one of two authentication
+methods to be configured: cookie authentication or bitcoind's `-torpassword`
+configuration option.
+
+#### Cookie authentication
+
+For cookie authentication, the user running bitcoind must have read access to
+the `CookieAuthFile` specified in the Tor configuration. In some cases this is
+preconfigured and the creation of an onion service is automatic. Don't forget to
+use the `-debug=tor` bitcoind configuration option to enable Tor debug logging.
+
+If a permissions problem is seen in the debug log, e.g. `tor: Authentication
+cookie /run/tor/control.authcookie could not be opened (check permissions)`, it
+can be resolved by adding both the user running Tor and the user running
+bitcoind to the same Tor group and setting permissions appropriately.
+
+On Debian-derived systems, the Tor group will likely be `debian-tor` and one way
+to verify could be to list the groups and grep for a "tor" group name:
+
+```
+getent group | cut -d: -f1 | grep -i tor
+```
+
+You can also check the group of the cookie file. On most Linux systems, the Tor
+auth cookie will usually be `/run/tor/control.authcookie`:
+
+```
+stat -c '%G' /run/tor/control.authcookie
+```
+
+Once you have determined the `${TORGROUP}` and selected the `${USER}` that will
+run bitcoind, run this as root:
+
+```
+usermod -a -G ${TORGROUP} ${USER}
+```
+
+Then restart the computer (or log out) and log in as the `${USER}` that will run
+bitcoind.
+
+#### `torpassword` authentication
+
+For the `-torpassword=password` option, the password is the clear text form that
+was used when generating the hashed password for the `HashedControlPassword`
+option in the Tor configuration file.
+
+The hashed password can be obtained with the command `tor --hash-password
+password` (refer to the [Tor Dev
+Manual](https://2019.www.torproject.org/docs/tor-manual.html.en) for more
+details).
+
+
+## 3. Manually create a Bitcoin Core onion service
+
+You can also manually configure your node to be reachable from the Tor network.
+Add these lines to your `/etc/tor/torrc` (or equivalent config file):
HiddenServiceDir /var/lib/tor/bitcoin-service/
HiddenServicePort 8333 127.0.0.1:8334
@@ -99,51 +197,17 @@ as well, use `discover` instead:
./bitcoind ... -discover
-and open port 8333 on your firewall (or use -upnp).
+and open port 8333 on your firewall (or use port mapping, i.e., `-upnp` or `-natpmp`).
If you only want to use Tor to reach .onion addresses, but not use it as a proxy
for normal IPv4/IPv6 communication, use:
./bitcoind -onion=127.0.0.1:9050 -externalip=7zvj7a2imdgkdbg4f2dryd5rgtrn7upivr5eeij4cicjh65pooxeshid.onion -discover
-## 3. Automatically create a Bitcoin Core onion service
-
-Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket
-API, to create and destroy 'ephemeral' onion services programmatically.
-Bitcoin Core has been updated to make use of this.
-
-This means that if Tor is running (and proper authentication has been configured),
-Bitcoin Core automatically creates an onion service to listen on. This will positively
-affect the number of available .onion nodes.
-
-This new feature is enabled by default if Bitcoin Core is listening (`-listen`), and
-requires a Tor connection to work. It can be explicitly disabled with `-listenonion=0`
-and, if not disabled, configured using the `-torcontrol` and `-torpassword` settings.
-To show verbose debugging information, pass `-debug=tor`.
-
-Connecting to Tor's control socket API requires one of two authentication methods to be
-configured. It also requires the control socket to be enabled, e.g. put `ControlPort 9051`
-in `torrc` config file. For cookie authentication the user running bitcoind must have read
-access to the `CookieAuthFile` specified in Tor configuration. In some cases this is
-preconfigured and the creation of an onion service is automatic. If permission problems
-are seen with `-debug=tor` they can be resolved by adding both the user running Tor and
-the user running bitcoind to the same group and setting permissions appropriately. On
-Debian-based systems the user running bitcoind can be added to the debian-tor group,
-which has the appropriate permissions. Before starting bitcoind you will need to re-login
-to allow debian-tor group to be applied. Otherwise you will see the following notice: "tor:
-Authentication cookie /run/tor/control.authcookie could not be opened (check permissions)"
-on debug.log.
-
-An alternative authentication method is the use
-of the `-torpassword=password` option. The `password` is the clear text form that
-was used when generating the hashed password for the `HashedControlPassword` option
-in the tor configuration file. The hashed password can be obtained with the command
-`tor --hash-password password` (read the tor manual for more details).
-
## 4. Privacy recommendations
-- Do not add anything but Bitcoin Core ports to the onion service created in section 2.
+- Do not add anything but Bitcoin Core ports to the onion service created in section 3.
If you run a web service too, create a new onion service for that.
Otherwise it is trivial to link them, which may reduce privacy. Onion
- services created automatically (as in section 3) always have only one port
+ services created automatically (as in section 2) always have only one port
open.
diff --git a/share/genbuild.sh b/share/genbuild.sh
index 1153df933f..fe89ae1fde 100755
--- a/share/genbuild.sh
+++ b/share/genbuild.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2012-2019 The Bitcoin Core developers
+# Copyright (c) 2012-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,7 +31,7 @@ if [ "${BITCOIN_GENBUILD_NO_GIT}" != "1" ] && [ -e "$(command -v git)" ] && [ "$
fi
# otherwise generate suffix from git, i.e. string like "59887e8-dirty"
- GIT_COMMIT=$(git rev-parse --short HEAD)
+ GIT_COMMIT=$(git rev-parse --short=12 HEAD)
git diff-index --quiet HEAD -- || GIT_COMMIT="$GIT_COMMIT-dirty"
fi
diff --git a/src/Makefile.am b/src/Makefile.am
index 48efdb24cd..2616eb8638 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,6 +2,10 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+# Pattern rule to print variables, e.g. make print-top_srcdir
+print-%:
+ @echo $* = $($*)
+
DIST_SUBDIRS = secp256k1 univalue
AM_LDFLAGS = $(LIBTOOL_LDFLAGS) $(HARDENED_LDFLAGS) $(GPROF_LDFLAGS) $(SANITIZER_LDFLAGS)
@@ -92,15 +96,21 @@ endif
if BUILD_BITCOIN_CLI
bin_PROGRAMS += bitcoin-cli
endif
+
if BUILD_BITCOIN_TX
bin_PROGRAMS += bitcoin-tx
endif
+
if ENABLE_WALLET
if BUILD_BITCOIN_WALLET
bin_PROGRAMS += bitcoin-wallet
endif
endif
+if BUILD_BITCOIN_UTIL
+ bin_PROGRAMS += bitcoin-util
+endif
+
.PHONY: FORCE check-symbols check-security
# bitcoin core #
BITCOIN_CORE_H = \
@@ -152,6 +162,7 @@ BITCOIN_CORE_H = \
key_io.h \
logging.h \
logging/timer.h \
+ mapport.h \
memusage.h \
merkleblock.h \
miner.h \
@@ -223,6 +234,7 @@ BITCOIN_CORE_H = \
util/error.h \
util/fees.h \
util/golombrice.h \
+ util/hasher.h \
util/macros.h \
util/memory.h \
util/message.h \
@@ -235,6 +247,7 @@ BITCOIN_CORE_H = \
util/system.h \
util/threadnames.h \
util/time.h \
+ util/trace.h \
util/translation.h \
util/ui_change_type.h \
util/url.h \
@@ -299,6 +312,7 @@ libbitcoin_server_a_SOURCES = \
index/blockfilterindex.cpp \
index/txindex.cpp \
init.cpp \
+ mapport.cpp \
miner.cpp \
net.cpp \
net_processing.cpp \
@@ -408,6 +422,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/hmac_sha512.h \
crypto/poly1305.h \
crypto/poly1305.cpp \
+ crypto/muhash.h \
+ crypto/muhash.cpp \
crypto/ripemd160.cpp \
crypto/ripemd160.h \
crypto/sha1.cpp \
@@ -540,6 +556,7 @@ libbitcoin_util_a_SOURCES = \
util/bytevectorhash.cpp \
util/error.cpp \
util/fees.cpp \
+ util/hasher.cpp \
util/system.cpp \
util/message.cpp \
util/moneystr.cpp \
@@ -596,7 +613,7 @@ bitcoin_bin_ldadd = \
$(LIBMEMENV) \
$(LIBSECP256K1)
-bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
+bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS)
bitcoind_SOURCES = $(bitcoin_daemon_sources)
bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags)
@@ -662,6 +679,27 @@ bitcoin_wallet_SOURCES += bitcoin-wallet-res.rc
endif
#
+# bitcoin-util binary #
+bitcoin_util_SOURCES = bitcoin-util.cpp
+bitcoin_util_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+bitcoin_util_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+bitcoin_util_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+
+if TARGET_WINDOWS
+bitcoin_util_SOURCES += bitcoin-util-res.rc
+endif
+
+bitcoin_util_LDADD = \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBUNIVALUE) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBSECP256K1)
+
+bitcoin_util_LDADD += $(BOOST_LIBS)
+#
+
# bitcoinconsensus library #
if BUILD_BITCOIN_LIBS
include_HEADERS = script/bitcoinconsensus.h
@@ -742,13 +780,13 @@ endif
if GLIBC_BACK_COMPAT
@echo "Checking glibc back compat..."
- $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
+ $(AM_V_at) CPPFILT=$(CPPFILT) $(PYTHON) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
endif
check-security: $(bin_PROGRAMS)
if HARDEN
@echo "Checking binary security..."
- $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS)
+ $(AM_V_at) OBJDUMP=$(OBJDUMP) OTOOL=$(OTOOL) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS)
endif
if EMBEDDED_LEVELDB
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index beb3f8dfd2..56b8ca8ce6 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -74,7 +74,7 @@ bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp
endif
-bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS)
+bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index f46310a603..969f0ca411 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -78,6 +78,7 @@ QT_MOC_CPP = \
qt/moc_transactiondesc.cpp \
qt/moc_transactiondescdialog.cpp \
qt/moc_transactionfilterproxy.cpp \
+ qt/moc_transactionoverviewwidget.cpp \
qt/moc_transactiontablemodel.cpp \
qt/moc_transactionview.cpp \
qt/moc_utilitydialog.cpp \
@@ -151,6 +152,7 @@ BITCOIN_QT_H = \
qt/transactiondesc.h \
qt/transactiondescdialog.h \
qt/transactionfilterproxy.h \
+ qt/transactionoverviewwidget.h \
qt/transactionrecord.h \
qt/transactiontablemodel.h \
qt/transactionview.h \
@@ -320,7 +322,7 @@ if ENABLE_ZMQ
bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index c05dd38737..a6a857d952 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -55,7 +55,7 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \
$(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \
$(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS)
qt_test_test_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index cbfe93df0a..e9f9b73abe 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -167,7 +167,7 @@ test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_C
$(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
-test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(SQLITE_LIBS)
+test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) -static
if ENABLE_ZMQ
@@ -210,6 +210,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp \
test/fuzz/crypto_poly1305.cpp \
test/fuzz/cuckoocache.cpp \
+ test/fuzz/data_stream.cpp \
test/fuzz/decode_tx.cpp \
test/fuzz/descriptor_parse.cpp \
test/fuzz/deserialize.cpp \
@@ -229,10 +230,12 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/locale.cpp \
test/fuzz/merkleblock.cpp \
test/fuzz/message.cpp \
+ test/fuzz/muhash.cpp \
test/fuzz/multiplication_overflow.cpp \
test/fuzz/net.cpp \
test/fuzz/net_permissions.cpp \
test/fuzz/netaddress.cpp \
+ test/fuzz/node_eviction.cpp \
test/fuzz/p2p_transport_deserializer.cpp \
test/fuzz/parse_hd_keypath.cpp \
test/fuzz/parse_iso8601.cpp \
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index 4e858979fe..75fe68fcd1 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -16,6 +16,7 @@ libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAG
libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libtest_fuzz_a_SOURCES = \
test/fuzz/fuzz.cpp \
+ test/fuzz/util.cpp \
$(TEST_FUZZ_H)
LIBTEST_FUZZ += $(LIBBITCOIN_SERVER)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index 27f22826a9..8f77ed35ce 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/addrdb.h b/src/addrdb.h
index 4ac0e3e1b5..8953ebb169 100644
--- a/src/addrdb.h
+++ b/src/addrdb.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 7636c6bad2..ed7fccc0ff 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -617,7 +617,7 @@ CAddrInfo CAddrMan::SelectTriedCollision_()
return CAddrInfo();
}
- CAddrInfo& newInfo = mapInfo[id_new];
+ const CAddrInfo& newInfo = mapInfo[id_new];
// which tried bucket to move the entry to
int tried_bucket = newInfo.GetTriedBucket(nKey, m_asmap);
diff --git a/src/attributes.h b/src/attributes.h
index 995c24e13f..9957bcd84b 100644
--- a/src/attributes.h
+++ b/src/attributes.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/banman.cpp b/src/banman.cpp
index 995fef3d07..49bf6c43dc 100644
--- a/src/banman.cpp
+++ b/src/banman.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/base58.cpp b/src/base58.cpp
index 780846c6c5..65e373283c 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/base58.h b/src/base58.h
index 60551a12ae..9ba5af73e0 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 18cb5de196..6f6b4e3bfa 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 99a7ad237b..af5a82f69f 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp
index 913e0f8d57..a6f4eec4ca 100644
--- a/src/bench/chacha20.cpp
+++ b/src/bench/chacha20.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index ffa772d8c1..d7b8c1badc 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -10,8 +10,6 @@
#include <random.h>
#include <util/system.h>
-#include <boost/thread/thread.hpp>
-
#include <vector>
static const size_t BATCHES = 101;
@@ -44,12 +42,9 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
void swap(PrevectorJob& x){p.swap(x.p);};
};
CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
- boost::thread_group tg;
// The main thread should be counted to prevent thread oversubscription, and
// to decrease the variance of benchmark results.
- for (auto x = 0; x < GetNumCores() - 1; ++x) {
- tg.create_thread([&]{queue.Thread();});
- }
+ queue.StartWorkerThreads(GetNumCores() - 1);
// create all the data once, then submit copies in the benchmark.
FastRandomContext insecure_rand(true);
@@ -70,8 +65,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench)
// it is done explicitly here for clarity
control.Wait();
});
- tg.interrupt_all();
- tg.join_all();
+ queue.StopWorkerThreads();
ECC_Stop();
}
BENCHMARK(CCheckQueueSpeedPrevectorJob);
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 99aafd8dfc..e50c4476bb 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 65d16d47d8..30fe11be6b 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -4,6 +4,7 @@
#include <bench/bench.h>
+#include <crypto/muhash.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
@@ -105,6 +106,54 @@ static void FastRandom_1bit(benchmark::Bench& bench)
});
}
+static void MuHash(benchmark::Bench& bench)
+{
+ MuHash3072 acc;
+ unsigned char key[32] = {0};
+ int i = 0;
+ bench.run([&] {
+ key[0] = ++i;
+ acc *= MuHash3072(key);
+ });
+}
+
+static void MuHashMul(benchmark::Bench& bench)
+{
+ MuHash3072 acc;
+ FastRandomContext rng(true);
+ MuHash3072 muhash{rng.randbytes(32)};
+
+ bench.run([&] {
+ acc *= muhash;
+ });
+}
+
+static void MuHashDiv(benchmark::Bench& bench)
+{
+ MuHash3072 acc;
+ FastRandomContext rng(true);
+ MuHash3072 muhash{rng.randbytes(32)};
+
+ for (size_t i = 0; i < bench.epochIterations(); ++i) {
+ acc *= muhash;
+ }
+
+ bench.run([&] {
+ acc /= muhash;
+ });
+}
+
+static void MuHashPrecompute(benchmark::Bench& bench)
+{
+ MuHash3072 acc;
+ FastRandomContext rng(true);
+ std::vector<unsigned char> key{rng.randbytes(32)};
+
+ bench.run([&] {
+ MuHash3072{key};
+ });
+}
+
BENCHMARK(RIPEMD160);
BENCHMARK(SHA1);
BENCHMARK(SHA256);
@@ -116,3 +165,8 @@ BENCHMARK(SipHash_32b);
BENCHMARK(SHA256D64_1024);
BENCHMARK(FastRandom_32bit);
BENCHMARK(FastRandom_1bit);
+
+BENCHMARK(MuHash);
+BENCHMARK(MuHashMul);
+BENCHMARK(MuHashDiv);
+BENCHMARK(MuHashPrecompute);
diff --git a/src/bench/gcs_filter.cpp b/src/bench/gcs_filter.cpp
index ef83242e41..607e4392b7 100644
--- a/src/bench/gcs_filter.cpp
+++ b/src/bench/gcs_filter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/hashpadding.cpp b/src/bench/hashpadding.cpp
index 309cae3723..753c8c2881 100644
--- a/src/bench/hashpadding.cpp
+++ b/src/bench/hashpadding.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
index 32b060a15a..b6d8824aba 100644
--- a/src/bench/lockedpool.cpp
+++ b/src/bench/lockedpool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
index 1b9e428c9d..db9a5661fd 100644
--- a/src/bench/mempool_eviction.cpp
+++ b/src/bench/mempool_eviction.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp
index 89233e390c..9b862b735c 100644
--- a/src/bench/mempool_stress.cpp
+++ b/src/bench/mempool_stress.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp
index d8db99e7d4..cdef97c0ea 100644
--- a/src/bench/poly1305.cpp
+++ b/src/bench/poly1305.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp
index 73af244ce0..dcd0e10285 100644
--- a/src/bench/prevector.cpp
+++ b/src/bench/prevector.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 9b43951e6e..997ab56549 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp
index 4b45264a3c..45ed9f60dc 100644
--- a/src/bench/rpc_blockchain.cpp
+++ b/src/bench/rpc_blockchain.cpp
@@ -7,12 +7,15 @@
#include <rpc/blockchain.h>
#include <streams.h>
+#include <test/util/setup_common.h>
#include <validation.h>
#include <univalue.h>
static void BlockToJsonVerbose(benchmark::Bench& bench)
{
+ TestingSetup test_setup{};
+
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
char a = '\0';
stream.write(&a, 1); // Prevent compaction
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
index 1ff41765cf..f1eeef8885 100644
--- a/src/bench/rpc_mempool.cpp
+++ b/src/bench/rpc_mempool.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp
index fad179eb87..afc733482e 100644
--- a/src/bench/util_time.cpp
+++ b/src/bench/util_time.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 9af0b502eb..e3f6b35a7d 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
const int witnessversion = 0;
- // Keypair.
+ // Key pair.
CKey key;
static const std::array<unsigned char, 32> vchKey = {
{
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
index aa436ee3ea..b385cec085 100644
--- a/src/bench/wallet_balance.cpp
+++ b/src/bench/wallet_balance.cpp
@@ -36,7 +36,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b
if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
for (int i = 0; i < 100; ++i) {
- generatetoaddress(test_setup.m_node, address_mine.get_value_or(ADDRESS_WATCHONLY));
+ generatetoaddress(test_setup.m_node, address_mine.value_or(ADDRESS_WATCHONLY));
generatetoaddress(test_setup.m_node, ADDRESS_WATCHONLY);
}
SyncWithValidationInterfaceQueue();
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index ef4641cb63..6a0d44a183 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -57,9 +57,9 @@ static void SetupCliArgs(ArgsManager& argsman)
argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC generatenewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+ argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
- argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0).", ArgsManager::ALLOW_INT, OptionsCategory::OPTIONS);
+ argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
SetupChainParamsBaseOptions(argsman);
argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -309,7 +309,8 @@ private:
}
return UNKNOWN_NETWORK;
}
- uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level
+ uint8_t m_details_level{0}; //!< Optional user-supplied arg to set dashboard details level
+ bool m_is_help_requested{false}; //!< Optional user-supplied arg to print help documentation
bool DetailsRequested() const { return m_details_level > 0 && m_details_level < 5; }
bool IsAddressSelected() const { return m_details_level == 2 || m_details_level == 4; }
bool IsVersionSelected() const { return m_details_level == 3 || m_details_level == 4; }
@@ -349,6 +350,62 @@ private:
const double milliseconds{round(1000 * seconds)};
return milliseconds > 999999 ? "-" : ToString(milliseconds);
}
+ const UniValue NetinfoHelp()
+ {
+ return std::string{
+ "-netinfo level|\"help\" \n\n"
+ "Returns a network peer connections dashboard with information from the remote server.\n"
+ "Under the hood, -netinfo fetches the data by calling getpeerinfo and getnetworkinfo.\n"
+ "An optional integer argument from 0 to 4 can be passed for different peers listings.\n"
+ "Pass \"help\" to see this detailed help documentation.\n"
+ "If more than one argument is passed, only the first one is read and parsed.\n"
+ "Suggestion: use with the Linux watch(1) command for a live dashboard; see example below.\n\n"
+ "Arguments:\n"
+ "1. level (integer 0-4, optional) Specify the info level of the peers dashboard (default 0):\n"
+ " 0 - Connection counts and local addresses\n"
+ " 1 - Like 0 but with a peers listing (without address or version columns)\n"
+ " 2 - Like 1 but with an address column\n"
+ " 3 - Like 1 but with a version column\n"
+ " 4 - Like 1 but with both address and version columns\n"
+ "2. help (string \"help\", optional) Print this help documentation instead of the dashboard.\n\n"
+ "Result:\n\n"
+ "* The peers listing in levels 1-4 displays all of the peers sorted by direction and minimum ping time:\n\n"
+ " Column Description\n"
+ " ------ -----------\n"
+ " <-> Direction\n"
+ " \"in\" - inbound connections are those initiated by the peer\n"
+ " \"out\" - outbound connections are those initiated by us\n"
+ " type Type of peer connection\n"
+ " \"full\" - full relay, the default\n"
+ " \"block\" - block relay; like full relay but does not relay transactions or addresses\n"
+ " net Network the peer connected through (\"ipv4\", \"ipv6\", \"onion\", \"i2p\", or \"cjdns\")\n"
+ " mping Minimum observed ping time, in milliseconds (ms)\n"
+ " ping Last observed ping time, in milliseconds (ms)\n"
+ " send Time since last message sent to the peer, in seconds\n"
+ " recv Time since last message received from the peer, in seconds\n"
+ " txn Time since last novel transaction received from the peer and accepted into our mempool, in minutes\n"
+ " blk Time since last novel block passing initial validity checks received from the peer, in minutes\n"
+ " age Duration of connection to the peer, in minutes\n"
+ " asmap Mapped AS (Autonomous System) number in the BGP route to the peer, used for diversifying\n"
+ " peer selection (only displayed if the -asmap config option is set)\n"
+ " id Peer index, in increasing order of peer connections since node startup\n"
+ " address IP address and port of the peer\n"
+ " version Peer version and subversion concatenated, e.g. \"70016/Satoshi:21.0.0/\"\n\n"
+ "* The connection counts table displays the number of peers by direction, network, and the totals\n"
+ " for each, as well as a column for block relay peers.\n\n"
+ "* The local addresses table lists each local address broadcast by the node, the port, and the score.\n\n"
+ "Examples:\n\n"
+ "Connection counts and local addresses only\n"
+ "> bitcoin-cli -netinfo\n\n"
+ "Compact peers listing\n"
+ "> bitcoin-cli -netinfo 1\n\n"
+ "Full dashboard\n"
+ "> bitcoin-cli -netinfo 4\n\n"
+ "Full live dashboard, adjust --interval or --no-title as needed (Linux)\n"
+ "> watch --interval 1 --no-title bitcoin-cli -netinfo 4\n\n"
+ "See this help\n"
+ "> bitcoin-cli -netinfo help\n"};
+ }
const int64_t m_time_now{GetSystemTimeInSeconds()};
public:
@@ -361,6 +418,10 @@ public:
uint8_t n{0};
if (ParseUInt8(args.at(0), &n)) {
m_details_level = n;
+ } else if (args.at(0) == "help") {
+ m_is_help_requested = true;
+ } else {
+ throw std::runtime_error(strprintf("invalid -netinfo argument: %s", args.at(0)));
}
}
UniValue result(UniValue::VARR);
@@ -371,6 +432,9 @@ public:
UniValue ProcessReply(const UniValue& batch_in) override
{
+ if (m_is_help_requested) {
+ return JSONRPCReplyObj(NetinfoHelp(), NullUniValue, 1);
+ }
const std::vector<UniValue> batch{JSONRPCProcessBatchReply(batch_in)};
if (!batch[ID_PEERINFO]["error"].isNull()) return batch[ID_PEERINFO];
if (!batch[ID_NETWORKINFO]["error"].isNull()) return batch[ID_NETWORKINFO];
@@ -424,7 +488,7 @@ public:
// Report detailed peer connections list sorted by direction and minimum ping time.
if (DetailsRequested() && !m_peers.empty()) {
std::sort(m_peers.begin(), m_peers.end());
- result += strprintf("Peer connections sorted by direction and min ping\n<-> relay net mping ping send recv txn blk %*s ", m_max_age_length, "age");
+ result += strprintf("<-> relay net mping ping send recv txn blk %*s ", m_max_age_length, "age");
if (m_is_asmap_on) result += " asmap ";
result += strprintf("%*s %-*s%s\n", m_max_id_length, "id", IsAddressSelected() ? m_max_addr_length : 0, IsAddressSelected() ? "address" : "", IsVersionSelected() ? "version" : "");
for (const Peer& peer : m_peers) {
diff --git a/src/bitcoin-util-res.rc b/src/bitcoin-util-res.rc
new file mode 100644
index 0000000000..3f0fa8ab6d
--- /dev/null
+++ b/src/bitcoin-util-res.rc
@@ -0,0 +1,35 @@
+#include <windows.h> // needed for VERSIONINFO
+#include "clientversion.h" // holds the needed client version information
+
+#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_BUILD
+#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_BUILD)
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_APP
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4" // U.S. English - multilingual (hex)
+ BEGIN
+ VALUE "CompanyName", "Bitcoin"
+ VALUE "FileDescription", "bitcoin-util (CLI Bitcoin utility)"
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", "bitcoin-util"
+ VALUE "LegalCopyright", COPYRIGHT_STR
+ VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
+ VALUE "OriginalFilename", "bitcoin-util.exe"
+ VALUE "ProductName", "bitcoin-util"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal)
+ END
+END
diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp
new file mode 100644
index 0000000000..af07b28d3d
--- /dev/null
+++ b/src/bitcoin-util.cpp
@@ -0,0 +1,221 @@
+// Copyright (c) 2009-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <arith_uint256.h>
+#include <clientversion.h>
+#include <coins.h>
+#include <consensus/consensus.h>
+#include <core_io.h>
+#include <key_io.h>
+#include <policy/rbf.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
+#include <script/sign.h>
+#include <script/signingprovider.h>
+#include <univalue.h>
+#include <util/moneystr.h>
+#include <util/rbf.h>
+#include <util/strencodings.h>
+#include <util/string.h>
+#include <util/system.h>
+#include <util/translation.h>
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <stdio.h>
+#include <thread>
+
+#include <boost/algorithm/string.hpp>
+
+static const int CONTINUE_EXECUTION=-1;
+
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
+static void SetupBitcoinUtilArgs(ArgsManager &argsman)
+{
+ SetupHelpOptions(argsman);
+
+ argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
+
+ SetupChainParamsBaseOptions(argsman);
+}
+
+// This function returns either one of EXIT_ codes when it's expected to stop the process or
+// CONTINUE_EXECUTION when it's expected to continue further.
+static int AppInitUtil(int argc, char* argv[])
+{
+ SetupBitcoinUtilArgs(gArgs);
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
+ return EXIT_FAILURE;
+ }
+
+ // Check for chain settings (Params() calls are only valid after this clause)
+ try {
+ SelectParams(gArgs.GetChainName());
+ } catch (const std::exception& e) {
+ tfm::format(std::cerr, "Error: %s\n", e.what());
+ return EXIT_FAILURE;
+ }
+
+ if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
+ // First part of help message is specific to this utility
+ std::string strUsage = PACKAGE_NAME " bitcoin-util utility version " + FormatFullVersion() + "\n";
+ if (!gArgs.IsArgSet("-version")) {
+ strUsage += "\n"
+ "Usage: bitcoin-util [options] [commands] Do stuff\n";
+ strUsage += "\n" + gArgs.GetHelpMessage();
+ }
+
+ tfm::format(std::cout, "%s", strUsage);
+
+ if (argc < 2) {
+ tfm::format(std::cerr, "Error: too few parameters\n");
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+ }
+ return CONTINUE_EXECUTION;
+}
+
+static void grind_task(uint32_t nBits, CBlockHeader& header_orig, uint32_t offset, uint32_t step, std::atomic<bool>& found)
+{
+ arith_uint256 target;
+ bool neg, over;
+ target.SetCompact(nBits, &neg, &over);
+ if (target == 0 || neg || over) return;
+ CBlockHeader header = header_orig; // working copy
+ header.nNonce = offset;
+
+ uint32_t finish = std::numeric_limits<uint32_t>::max() - step;
+ finish = finish - (finish % step) + offset;
+
+ while (!found && header.nNonce < finish) {
+ const uint32_t next = (finish - header.nNonce < 5000*step) ? finish : header.nNonce + 5000*step;
+ do {
+ if (UintToArith256(header.GetHash()) <= target) {
+ if (!found.exchange(true)) {
+ header_orig.nNonce = header.nNonce;
+ }
+ return;
+ }
+ header.nNonce += step;
+ } while(header.nNonce != next);
+ }
+}
+
+static int Grind(int argc, char* argv[], std::string& strPrint)
+{
+ if (argc != 1) {
+ strPrint = "Must specify block header to grind";
+ return 1;
+ }
+
+ CBlockHeader header;
+ if (!DecodeHexBlockHeader(header, argv[0])) {
+ strPrint = "Could not decode block header";
+ return 1;
+ }
+
+ uint32_t nBits = header.nBits;
+ std::atomic<bool> found{false};
+
+ std::vector<std::thread> threads;
+ int n_tasks = std::max(1u, std::thread::hardware_concurrency());
+ for (int i = 0; i < n_tasks; ++i) {
+ threads.emplace_back( grind_task, nBits, std::ref(header), i, n_tasks, std::ref(found) );
+ }
+ for (auto& t : threads) {
+ t.join();
+ }
+ if (!found) {
+ strPrint = "Could not satisfy difficulty target";
+ return 1;
+ }
+
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss << header;
+ strPrint = HexStr(ss);
+ return 0;
+}
+
+static int CommandLineUtil(int argc, char* argv[])
+{
+ if (argc <= 1) return 1;
+
+ std::string strPrint;
+ int nRet = 0;
+
+ try {
+ while (argc > 1 && IsSwitchChar(argv[1][0]) && (argv[1][1] != 0)) {
+ --argc;
+ ++argv;
+ }
+
+ char* command = argv[1];
+ if (strcmp(command, "grind") == 0) {
+ nRet = Grind(argc-2, argv+2, strPrint);
+ } else {
+ strPrint = strprintf("Unknown command %s", command);
+ nRet = 1;
+ }
+ }
+ catch (const std::exception& e) {
+ strPrint = std::string("error: ") + e.what();
+ nRet = EXIT_FAILURE;
+ }
+ catch (...) {
+ PrintExceptionContinue(nullptr, "CommandLineUtil()");
+ throw;
+ }
+
+ if (strPrint != "") {
+ tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
+ }
+ return nRet;
+}
+
+#ifdef WIN32
+// Export main() and ensure working ASLR on Windows.
+// Exporting a symbol will prevent the linker from stripping
+// the .reloc section from the binary, which is a requirement
+// for ASLR. This is a temporary workaround until a fixed
+// version of binutils is used for releases.
+__declspec(dllexport) int main(int argc, char* argv[])
+#else
+int main(int argc, char* argv[])
+#endif
+{
+ SetupEnvironment();
+
+ try {
+ int ret = AppInitUtil(argc, argv);
+ if (ret != CONTINUE_EXECUTION)
+ return ret;
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "AppInitUtil()");
+ return EXIT_FAILURE;
+ } catch (...) {
+ PrintExceptionContinue(nullptr, "AppInitUtil()");
+ return EXIT_FAILURE;
+ }
+
+ int ret = EXIT_FAILURE;
+ try {
+ ret = CommandLineUtil(argc, argv);
+ }
+ catch (const std::exception& e) {
+ PrintExceptionContinue(&e, "CommandLineUtil()");
+ } catch (...) {
+ PrintExceptionContinue(nullptr, "CommandLineUtil()");
+ }
+ return ret;
+}
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 0f8d312c5e..3e8e5fc7bc 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -29,7 +29,7 @@ static void SetupWalletToolArgs(ArgsManager& argsman)
argsman.AddArg("-wallet=<wallet-name>", "Specify wallet name", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::OPTIONS);
argsman.AddArg("-dumpfile=<file name>", "When used with 'dump', writes out the records to this file. When used with 'createfromdump', loads the records into a new wallet.", ArgsManager::ALLOW_STRING, OptionsCategory::OPTIONS);
argsman.AddArg("-debug=<category>", "Output debugging information (default: 0).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
- argsman.AddArg("-descriptors", "Create descriptors wallet. Only for create", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
+ argsman.AddArg("-descriptors", "Create descriptors wallet. Only for 'create'", ArgsManager::ALLOW_BOOL, OptionsCategory::OPTIONS);
argsman.AddArg("-format=<format>", "The format of the wallet file to create. Either \"bdb\" or \"sqlite\". Only used with 'createfromdump'", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
argsman.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -debug is true, 0 otherwise).", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
@@ -120,8 +120,9 @@ int main(int argc, char* argv[])
ECCVerifyHandle globalVerifyHandle;
ECC_Start();
- if (!WalletTool::ExecuteWalletToolFunc(method, name))
+ if (!WalletTool::ExecuteWalletToolFunc(gArgs, method, name)) {
return EXIT_FAILURE;
+ }
ECC_Stop();
return EXIT_SUCCESS;
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index a47709cd82..aa111b5939 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 9a6fb4abd0..41fa0b6fa0 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bloom.cpp b/src/bloom.cpp
index d182f0728e..d0128a26d7 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/bloom.h b/src/bloom.h
index 24dc607cd9..fdaa8abfb2 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 603969aaea..2c517b58f8 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h
index 9b4ae2f7ab..d593cff722 100644
--- a/src/chainparamsbase.h
+++ b/src/chainparamsbase.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/checkqueue.h b/src/checkqueue.h
index e3faa1dec0..4ceeb3600a 100644
--- a/src/checkqueue.h
+++ b/src/checkqueue.h
@@ -6,13 +6,12 @@
#define BITCOIN_CHECKQUEUE_H
#include <sync.h>
+#include <tinyformat.h>
+#include <util/threadnames.h>
#include <algorithm>
#include <vector>
-#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/mutex.hpp>
-
template <typename T>
class CCheckQueueControl;
@@ -31,61 +30,64 @@ class CCheckQueue
{
private:
//! Mutex to protect the inner state
- boost::mutex mutex;
+ Mutex m_mutex;
//! Worker threads block on this when out of work
- boost::condition_variable condWorker;
+ std::condition_variable m_worker_cv;
//! Master thread blocks on this when out of work
- boost::condition_variable condMaster;
+ std::condition_variable m_master_cv;
//! The queue of elements to be processed.
//! As the order of booleans doesn't matter, it is used as a LIFO (stack)
- std::vector<T> queue;
+ std::vector<T> queue GUARDED_BY(m_mutex);
//! The number of workers (including the master) that are idle.
- int nIdle;
+ int nIdle GUARDED_BY(m_mutex){0};
//! The total number of workers (including the master).
- int nTotal;
+ int nTotal GUARDED_BY(m_mutex){0};
//! The temporary evaluation result.
- bool fAllOk;
+ bool fAllOk GUARDED_BY(m_mutex){true};
/**
* Number of verifications that haven't completed yet.
* This includes elements that are no longer queued, but still in the
* worker's own batches.
*/
- unsigned int nTodo;
+ unsigned int nTodo GUARDED_BY(m_mutex){0};
//! The maximum number of elements to be processed in one batch
- unsigned int nBatchSize;
+ const unsigned int nBatchSize;
+
+ std::vector<std::thread> m_worker_threads;
+ bool m_request_stop GUARDED_BY(m_mutex){false};
/** Internal function that does bulk of the verification work. */
- bool Loop(bool fMaster = false)
+ bool Loop(bool fMaster)
{
- boost::condition_variable& cond = fMaster ? condMaster : condWorker;
+ std::condition_variable& cond = fMaster ? m_master_cv : m_worker_cv;
std::vector<T> vChecks;
vChecks.reserve(nBatchSize);
unsigned int nNow = 0;
bool fOk = true;
do {
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ WAIT_LOCK(m_mutex, lock);
// first do the clean-up of the previous loop run (allowing us to do it in the same critsect)
if (nNow) {
fAllOk &= fOk;
nTodo -= nNow;
if (nTodo == 0 && !fMaster)
// We processed the last element; inform the master it can exit and return the result
- condMaster.notify_one();
+ m_master_cv.notify_one();
} else {
// first iteration
nTotal++;
}
// logically, the do loop starts here
- while (queue.empty()) {
+ while (queue.empty() && !m_request_stop) {
if (fMaster && nTodo == 0) {
nTotal--;
bool fRet = fAllOk;
@@ -98,6 +100,10 @@ private:
cond.wait(lock); // wait
nIdle--;
}
+ if (m_request_stop) {
+ return false;
+ }
+
// Decide how many work units to process now.
// * Do not try to do everything at once, but aim for increasingly smaller batches so
// all workers finish approximately simultaneously.
@@ -106,7 +112,7 @@ private:
nNow = std::max(1U, std::min(nBatchSize, (unsigned int)queue.size() / (nTotal + nIdle + 1)));
vChecks.resize(nNow);
for (unsigned int i = 0; i < nNow; i++) {
- // We want the lock on the mutex to be as short as possible, so swap jobs from the global
+ // We want the lock on the m_mutex to be as short as possible, so swap jobs from the global
// queue to the local batch vector instead of copying.
vChecks[i].swap(queue.back());
queue.pop_back();
@@ -124,40 +130,68 @@ private:
public:
//! Mutex to ensure only one concurrent CCheckQueueControl
- boost::mutex ControlMutex;
+ Mutex m_control_mutex;
//! Create a new check queue
- explicit CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), nBatchSize(nBatchSizeIn) {}
+ explicit CCheckQueue(unsigned int nBatchSizeIn)
+ : nBatchSize(nBatchSizeIn)
+ {
+ }
- //! Worker thread
- void Thread()
+ //! Create a pool of new worker threads.
+ void StartWorkerThreads(const int threads_num)
{
- Loop();
+ {
+ LOCK(m_mutex);
+ nIdle = 0;
+ nTotal = 0;
+ fAllOk = true;
+ }
+ assert(m_worker_threads.empty());
+ for (int n = 0; n < threads_num; ++n) {
+ m_worker_threads.emplace_back([this, n]() {
+ util::ThreadRename(strprintf("scriptch.%i", n));
+ Loop(false /* worker thread */);
+ });
+ }
}
//! Wait until execution finishes, and return whether all evaluations were successful.
bool Wait()
{
- return Loop(true);
+ return Loop(true /* master thread */);
}
//! Add a batch of checks to the queue
void Add(std::vector<T>& vChecks)
{
- boost::unique_lock<boost::mutex> lock(mutex);
+ LOCK(m_mutex);
for (T& check : vChecks) {
queue.push_back(T());
check.swap(queue.back());
}
nTodo += vChecks.size();
if (vChecks.size() == 1)
- condWorker.notify_one();
+ m_worker_cv.notify_one();
else if (vChecks.size() > 1)
- condWorker.notify_all();
+ m_worker_cv.notify_all();
+ }
+
+ //! Stop all of the worker threads.
+ void StopWorkerThreads()
+ {
+ WITH_LOCK(m_mutex, m_request_stop = true);
+ m_worker_cv.notify_all();
+ for (std::thread& t : m_worker_threads) {
+ t.join();
+ }
+ m_worker_threads.clear();
+ WITH_LOCK(m_mutex, m_request_stop = false);
}
~CCheckQueue()
{
+ assert(m_worker_threads.empty());
}
};
@@ -181,7 +215,7 @@ public:
{
// passed queue is supposed to be unused, or nullptr
if (pqueue != nullptr) {
- ENTER_CRITICAL_SECTION(pqueue->ControlMutex);
+ ENTER_CRITICAL_SECTION(pqueue->m_control_mutex);
}
}
@@ -205,7 +239,7 @@ public:
if (!fDone)
Wait();
if (pqueue != nullptr) {
- LEAVE_CRITICAL_SECTION(pqueue->ControlMutex);
+ LEAVE_CRITICAL_SECTION(pqueue->m_control_mutex);
}
}
};
diff --git a/src/clientversion.cpp b/src/clientversion.cpp
index aaf041602b..29c38e2d3b 100644
--- a/src/clientversion.cpp
+++ b/src/clientversion.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/clientversion.h b/src/clientversion.h
index c925b8f084..2da909f829 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/coins.cpp b/src/coins.cpp
index 5de2ed7810..dd84e720e7 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,8 +31,6 @@ bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock)
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
-SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
-
CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}
size_t CCoinsViewCache::DynamicMemoryUsage() const {
diff --git a/src/coins.h b/src/coins.h
index a3e241ac90..d2eb42d8cf 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -8,11 +8,11 @@
#include <compressor.h>
#include <core_memusage.h>
-#include <crypto/siphash.h>
#include <memusage.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <uint256.h>
+#include <util/hasher.h>
#include <assert.h>
#include <stdint.h>
@@ -82,33 +82,6 @@ public:
}
};
-class SaltedOutpointHasher
-{
-private:
- /** Salt */
- const uint64_t k0, k1;
-
-public:
- SaltedOutpointHasher();
-
- /**
- * This *must* return size_t. With Boost 1.46 on 32-bit systems the
- * unordered_map will behave unpredictably if the custom hasher returns a
- * uint64_t, resulting in failures when syncing the chain (#4634).
- *
- * Having the hash noexcept allows libstdc++'s unordered_map to recalculate
- * the hash during rehash, so it does not have to cache the value. This
- * reduces node's memory by sizeof(size_t). The required recalculation has
- * a slight performance penalty (around 1.6%), but this is compensated by
- * memory savings of about 9% which allow for a larger dbcache setting.
- *
- * @see https://gcc.gnu.org/onlinedocs/gcc-9.2.0/libstdc++/manual/manual/unordered_associative.html
- */
- size_t operator()(const COutPoint& id) const noexcept {
- return SipHashUint256Extra(k0, k1, id.hash, id.n);
- }
-};
-
/**
* A Coin in one level of the coins database caching hierarchy.
*
diff --git a/src/compat.h b/src/compat.h
index 5fa6589792..dad14748a2 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h
index 4b0b224c69..301c2d914c 100644
--- a/src/compat/assumptions.h
+++ b/src/compat/assumptions.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp
index d17de33e86..8a51f310f7 100644
--- a/src/compat/glibc_compat.cpp
+++ b/src/compat/glibc_compat.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -54,6 +54,12 @@ __asm(".symver log2f_old,log2f@GLIBC_2.2.5");
__asm(".symver log2f_old,log2f@GLIBC_2.4");
#elif defined(__aarch64__)
__asm(".symver log2f_old,log2f@GLIBC_2.17");
+#elif defined(__powerpc64__)
+# ifdef WORDS_BIGENDIAN
+__asm(".symver log2f_old,log2f@GLIBC_2.3");
+# else
+__asm(".symver log2f_old,log2f@GLIBC_2.17");
+# endif
#elif defined(__riscv)
__asm(".symver log2f_old,log2f@GLIBC_2.27");
#endif
diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp
index 0367b9a53f..06d0dd6fba 100644
--- a/src/compat/glibc_sanity.cpp
+++ b/src/compat/glibc_sanity.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 0983595c6a..217cb019e1 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 9e8e6530f1..f595f16eab 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index e2a9328df8..e78dc9f2a5 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index e007c481df..c4d305434a 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/core_io.h b/src/core_io.h
index aaee9c445d..5469a760ee 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,7 @@ class CTransaction;
struct CMutableTransaction;
class uint256;
class UniValue;
+class CTxUndo;
// core_read.cpp
CScript ParseScript(const std::string& s);
@@ -29,7 +30,7 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
/**
* Parse a hex string into 256 bits
* @param[in] strHex a hex-formatted, 64-character string
- * @param[out] result the result of the parasing
+ * @param[out] result the result of the parsing
* @returns true if successful, false if not
*
* @see ParseHashV for an RPC-oriented version of this
@@ -45,6 +46,6 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0);
std::string SighashToStr(unsigned char sighash_type);
void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
void ScriptToUniv(const CScript& script, UniValue& out, bool include_address);
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0);
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, const CTxUndo* txundo = nullptr);
#endif // BITCOIN_CORE_IO_H
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 7687a86185..b5fc93886d 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -128,7 +128,7 @@ static bool DecodeTx(CMutableTransaction& tx, const std::vector<unsigned char>&
{
// General strategy:
// - Decode both with extended serialization (which interprets the 0x0001 tag as a marker for
- // the presense of witnesses) and with legacy serialization (which interprets the tag as a
+ // the presence of witnesses) and with legacy serialization (which interprets the tag as a
// 0-input 1-output incomplete transaction).
// - Restricted by try_no_witness (which disables legacy if false) and try_witness (which
// disables extended if false).
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 3980d8cb2e..a3902863d6 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,7 +11,9 @@
#include <script/standard.h>
#include <serialize.h>
#include <streams.h>
+#include <undo.h>
#include <univalue.h>
+#include <util/check.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -177,7 +179,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("addresses", a);
}
-void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags)
+void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, const CTxUndo* txundo)
{
entry.pushKV("txid", tx.GetHash().GetHex());
entry.pushKV("hash", tx.GetWitnessHash().GetHex());
@@ -189,13 +191,20 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
entry.pushKV("weight", GetTransactionWeight(tx));
entry.pushKV("locktime", (int64_t)tx.nLockTime);
- UniValue vin(UniValue::VARR);
+ UniValue vin{UniValue::VARR};
+
+ // If available, use Undo data to calculate the fee. Note that txundo == nullptr
+ // for coinbase transactions and for transactions where undo data is unavailable.
+ const bool calculate_fee = txundo != nullptr;
+ CAmount amt_total_in = 0;
+ CAmount amt_total_out = 0;
+
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxIn& txin = tx.vin[i];
UniValue in(UniValue::VOBJ);
- if (tx.IsCoinBase())
+ if (tx.IsCoinBase()) {
in.pushKV("coinbase", HexStr(txin.scriptSig));
- else {
+ } else {
in.pushKV("txid", txin.prevout.hash.GetHex());
in.pushKV("vout", (int64_t)txin.prevout.n);
UniValue o(UniValue::VOBJ);
@@ -210,6 +219,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
}
in.pushKV("txinwitness", txinwitness);
}
+ if (calculate_fee) {
+ const CTxOut& prev_txout = txundo->vprevout[i].out;
+ amt_total_in += prev_txout.nValue;
+ }
in.pushKV("sequence", (int64_t)txin.nSequence);
vin.push_back(in);
}
@@ -228,9 +241,19 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
ScriptPubKeyToUniv(txout.scriptPubKey, o, true);
out.pushKV("scriptPubKey", o);
vout.push_back(out);
+
+ if (calculate_fee) {
+ amt_total_out += txout.nValue;
+ }
}
entry.pushKV("vout", vout);
+ if (calculate_fee) {
+ const CAmount fee = amt_total_in - amt_total_out;
+ CHECK_NONFATAL(MoneyRange(fee));
+ entry.pushKV("fee", ValueFromAmount(fee));
+ }
+
if (!hashBlock.IsNull())
entry.pushKV("blockhash", hashBlock.GetHex());
diff --git a/src/crypto/chacha_poly_aead.h b/src/crypto/chacha_poly_aead.h
index b3ba781cdd..0afe8fcc14 100644
--- a/src/crypto/chacha_poly_aead.h
+++ b/src/crypto/chacha_poly_aead.h
@@ -17,12 +17,12 @@ static constexpr int AAD_PACKAGES_PER_ROUND = 21; /* 64 / 3 round down*/
/* A AEAD class for ChaCha20-Poly1305@bitcoin.
*
* ChaCha20 is a stream cipher designed by Daniel Bernstein and described in
- * <ref>[http://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates
+ * <ref>[https://cr.yp.to/chacha/chacha-20080128.pdf ChaCha20]</ref>. It operates
* by permuting 128 fixed bits, 128 or 256 bits of key, a 64 bit nonce and a 64
* bit counter into 64 bytes of output. This output is used as a keystream, with
* any unused bytes simply discarded.
*
- * Poly1305 <ref>[http://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>, also
+ * Poly1305 <ref>[https://cr.yp.to/mac/poly1305-20050329.pdf Poly1305]</ref>, also
* by Daniel Bernstein, is a one-time Carter-Wegman MAC that computes a 128 bit
* integrity tag given a message and a single-use 256 bit secret key.
*
diff --git a/src/crypto/common.h b/src/crypto/common.h
index c1acf8b22e..dc12ed9942 100644
--- a/src/crypto/common.h
+++ b/src/crypto/common.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp
new file mode 100644
index 0000000000..fbd14f9325
--- /dev/null
+++ b/src/crypto/muhash.cpp
@@ -0,0 +1,338 @@
+// Copyright (c) 2017-2020 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 <crypto/muhash.h>
+
+#include <crypto/chacha20.h>
+#include <crypto/common.h>
+#include <hash.h>
+
+#include <cassert>
+#include <cstdio>
+#include <limits>
+
+namespace {
+
+using limb_t = Num3072::limb_t;
+using double_limb_t = Num3072::double_limb_t;
+constexpr int LIMB_SIZE = Num3072::LIMB_SIZE;
+constexpr int LIMBS = Num3072::LIMBS;
+/** 2^3072 - 1103717, the largest 3072-bit safe prime number, is used as the modulus. */
+constexpr limb_t MAX_PRIME_DIFF = 1103717;
+
+/** Extract the lowest limb of [c0,c1,c2] into n, and left shift the number by 1 limb. */
+inline void extract3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& n)
+{
+ n = c0;
+ c0 = c1;
+ c1 = c2;
+ c2 = 0;
+}
+
+/** [c0,c1] = a * b */
+inline void mul(limb_t& c0, limb_t& c1, const limb_t& a, const limb_t& b)
+{
+ double_limb_t t = (double_limb_t)a * b;
+ c1 = t >> LIMB_SIZE;
+ c0 = t;
+}
+
+/* [c0,c1,c2] += n * [d0,d1,d2]. c2 is 0 initially */
+inline void mulnadd3(limb_t& c0, limb_t& c1, limb_t& c2, limb_t& d0, limb_t& d1, limb_t& d2, const limb_t& n)
+{
+ double_limb_t t = (double_limb_t)d0 * n + c0;
+ c0 = t;
+ t >>= LIMB_SIZE;
+ t += (double_limb_t)d1 * n + c1;
+ c1 = t;
+ t >>= LIMB_SIZE;
+ c2 = t + d2 * n;
+}
+
+/* [c0,c1] *= n */
+inline void muln2(limb_t& c0, limb_t& c1, const limb_t& n)
+{
+ double_limb_t t = (double_limb_t)c0 * n;
+ c0 = t;
+ t >>= LIMB_SIZE;
+ t += (double_limb_t)c1 * n;
+ c1 = t;
+}
+
+/** [c0,c1,c2] += a * b */
+inline void muladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
+{
+ double_limb_t t = (double_limb_t)a * b;
+ limb_t th = t >> LIMB_SIZE;
+ limb_t tl = t;
+
+ c0 += tl;
+ th += (c0 < tl) ? 1 : 0;
+ c1 += th;
+ c2 += (c1 < th) ? 1 : 0;
+}
+
+/** [c0,c1,c2] += 2 * a * b */
+inline void muldbladd3(limb_t& c0, limb_t& c1, limb_t& c2, const limb_t& a, const limb_t& b)
+{
+ double_limb_t t = (double_limb_t)a * b;
+ limb_t th = t >> LIMB_SIZE;
+ limb_t tl = t;
+
+ c0 += tl;
+ limb_t tt = th + ((c0 < tl) ? 1 : 0);
+ c1 += tt;
+ c2 += (c1 < tt) ? 1 : 0;
+ c0 += tl;
+ th += (c0 < tl) ? 1 : 0;
+ c1 += th;
+ c2 += (c1 < th) ? 1 : 0;
+}
+
+/**
+ * Add limb a to [c0,c1]: [c0,c1] += a. Then extract the lowest
+ * limb of [c0,c1] into n, and left shift the number by 1 limb.
+ * */
+inline void addnextract2(limb_t& c0, limb_t& c1, const limb_t& a, limb_t& n)
+{
+ limb_t c2 = 0;
+
+ // add
+ c0 += a;
+ if (c0 < a) {
+ c1 += 1;
+
+ // Handle case when c1 has overflown
+ if (c1 == 0)
+ c2 = 1;
+ }
+
+ // extract
+ n = c0;
+ c0 = c1;
+ c1 = c2;
+}
+
+/** in_out = in_out^(2^sq) * mul */
+inline void square_n_mul(Num3072& in_out, const int sq, const Num3072& mul)
+{
+ for (int j = 0; j < sq; ++j) in_out.Square();
+ in_out.Multiply(mul);
+}
+
+} // namespace
+
+/** Indicates wether d is larger than the modulus. */
+bool Num3072::IsOverflow() const
+{
+ if (this->limbs[0] <= std::numeric_limits<limb_t>::max() - MAX_PRIME_DIFF) return false;
+ for (int i = 1; i < LIMBS; ++i) {
+ if (this->limbs[i] != std::numeric_limits<limb_t>::max()) return false;
+ }
+ return true;
+}
+
+void Num3072::FullReduce()
+{
+ limb_t c0 = MAX_PRIME_DIFF;
+ limb_t c1 = 0;
+ for (int i = 0; i < LIMBS; ++i) {
+ addnextract2(c0, c1, this->limbs[i], this->limbs[i]);
+ }
+}
+
+Num3072 Num3072::GetInverse() const
+{
+ // For fast exponentiation a sliding window exponentiation with repunit
+ // precomputation is utilized. See "Fast Point Decompression for Standard
+ // Elliptic Curves" (Brumley, Järvinen, 2008).
+
+ Num3072 p[12]; // p[i] = a^(2^(2^i)-1)
+ Num3072 out;
+
+ p[0] = *this;
+
+ for (int i = 0; i < 11; ++i) {
+ p[i + 1] = p[i];
+ for (int j = 0; j < (1 << i); ++j) p[i + 1].Square();
+ p[i + 1].Multiply(p[i]);
+ }
+
+ out = p[11];
+
+ square_n_mul(out, 512, p[9]);
+ square_n_mul(out, 256, p[8]);
+ square_n_mul(out, 128, p[7]);
+ square_n_mul(out, 64, p[6]);
+ square_n_mul(out, 32, p[5]);
+ square_n_mul(out, 8, p[3]);
+ square_n_mul(out, 2, p[1]);
+ square_n_mul(out, 1, p[0]);
+ square_n_mul(out, 5, p[2]);
+ square_n_mul(out, 3, p[0]);
+ square_n_mul(out, 2, p[0]);
+ square_n_mul(out, 4, p[0]);
+ square_n_mul(out, 4, p[1]);
+ square_n_mul(out, 3, p[0]);
+
+ return out;
+}
+
+void Num3072::Multiply(const Num3072& a)
+{
+ limb_t c0 = 0, c1 = 0, c2 = 0;
+ Num3072 tmp;
+
+ /* Compute limbs 0..N-2 of this*a into tmp, including one reduction. */
+ for (int j = 0; j < LIMBS - 1; ++j) {
+ limb_t d0 = 0, d1 = 0, d2 = 0;
+ mul(d0, d1, this->limbs[1 + j], a.limbs[LIMBS + j - (1 + j)]);
+ for (int i = 2 + j; i < LIMBS; ++i) muladd3(d0, d1, d2, this->limbs[i], a.limbs[LIMBS + j - i]);
+ mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
+ for (int i = 0; i < j + 1; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[j - i]);
+ extract3(c0, c1, c2, tmp.limbs[j]);
+ }
+
+ /* Compute limb N-1 of a*b into tmp. */
+ assert(c2 == 0);
+ for (int i = 0; i < LIMBS; ++i) muladd3(c0, c1, c2, this->limbs[i], a.limbs[LIMBS - 1 - i]);
+ extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
+
+ /* Perform a second reduction. */
+ muln2(c0, c1, MAX_PRIME_DIFF);
+ for (int j = 0; j < LIMBS; ++j) {
+ addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
+ }
+
+ assert(c1 == 0);
+ assert(c0 == 0 || c0 == 1);
+
+ /* Perform up to two more reductions if the internal state has already
+ * overflown the MAX of Num3072 or if it is larger than the modulus or
+ * if both are the case.
+ * */
+ if (this->IsOverflow()) this->FullReduce();
+ if (c0) this->FullReduce();
+}
+
+void Num3072::Square()
+{
+ limb_t c0 = 0, c1 = 0, c2 = 0;
+ Num3072 tmp;
+
+ /* Compute limbs 0..N-2 of this*this into tmp, including one reduction. */
+ for (int j = 0; j < LIMBS - 1; ++j) {
+ limb_t d0 = 0, d1 = 0, d2 = 0;
+ for (int i = 0; i < (LIMBS - 1 - j) / 2; ++i) muldbladd3(d0, d1, d2, this->limbs[i + j + 1], this->limbs[LIMBS - 1 - i]);
+ if ((j + 1) & 1) muladd3(d0, d1, d2, this->limbs[(LIMBS - 1 - j) / 2 + j + 1], this->limbs[LIMBS - 1 - (LIMBS - 1 - j) / 2]);
+ mulnadd3(c0, c1, c2, d0, d1, d2, MAX_PRIME_DIFF);
+ for (int i = 0; i < (j + 1) / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[j - i]);
+ if ((j + 1) & 1) muladd3(c0, c1, c2, this->limbs[(j + 1) / 2], this->limbs[j - (j + 1) / 2]);
+ extract3(c0, c1, c2, tmp.limbs[j]);
+ }
+
+ assert(c2 == 0);
+ for (int i = 0; i < LIMBS / 2; ++i) muldbladd3(c0, c1, c2, this->limbs[i], this->limbs[LIMBS - 1 - i]);
+ extract3(c0, c1, c2, tmp.limbs[LIMBS - 1]);
+
+ /* Perform a second reduction. */
+ muln2(c0, c1, MAX_PRIME_DIFF);
+ for (int j = 0; j < LIMBS; ++j) {
+ addnextract2(c0, c1, tmp.limbs[j], this->limbs[j]);
+ }
+
+ assert(c1 == 0);
+ assert(c0 == 0 || c0 == 1);
+
+ /* Perform up to two more reductions if the internal state has already
+ * overflown the MAX of Num3072 or if it is larger than the modulus or
+ * if both are the case.
+ * */
+ if (this->IsOverflow()) this->FullReduce();
+ if (c0) this->FullReduce();
+}
+
+void Num3072::SetToOne()
+{
+ this->limbs[0] = 1;
+ for (int i = 1; i < LIMBS; ++i) this->limbs[i] = 0;
+}
+
+void Num3072::Divide(const Num3072& a)
+{
+ if (this->IsOverflow()) this->FullReduce();
+
+ Num3072 inv{};
+ if (a.IsOverflow()) {
+ Num3072 b = a;
+ b.FullReduce();
+ inv = b.GetInverse();
+ } else {
+ inv = a.GetInverse();
+ }
+
+ this->Multiply(inv);
+ if (this->IsOverflow()) this->FullReduce();
+}
+
+Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
+ Num3072 out{};
+ uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
+ unsigned char tmp[BYTE_SIZE];
+ ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, BYTE_SIZE);
+ for (int i = 0; i < LIMBS; ++i) {
+ if (sizeof(limb_t) == 4) {
+ out.limbs[i] = ReadLE32(tmp + 4 * i);
+ } else if (sizeof(limb_t) == 8) {
+ out.limbs[i] = ReadLE64(tmp + 8 * i);
+ }
+ }
+ return out;
+}
+
+MuHash3072::MuHash3072(Span<const unsigned char> in) noexcept
+{
+ m_numerator = ToNum3072(in);
+}
+
+void MuHash3072::Finalize(uint256& out) noexcept
+{
+ m_numerator.Divide(m_denominator);
+ m_denominator.SetToOne(); // Needed to keep the MuHash object valid
+
+ unsigned char data[384];
+ for (int i = 0; i < LIMBS; ++i) {
+ if (sizeof(limb_t) == 4) {
+ WriteLE32(data + i * 4, m_numerator.limbs[i]);
+ } else if (sizeof(limb_t) == 8) {
+ WriteLE64(data + i * 8, m_numerator.limbs[i]);
+ }
+ }
+
+ out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
+}
+
+MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
+{
+ m_numerator.Multiply(mul.m_numerator);
+ m_denominator.Multiply(mul.m_denominator);
+ return *this;
+}
+
+MuHash3072& MuHash3072::operator/=(const MuHash3072& div) noexcept
+{
+ m_numerator.Multiply(div.m_denominator);
+ m_denominator.Multiply(div.m_numerator);
+ return *this;
+}
+
+MuHash3072& MuHash3072::Insert(Span<const unsigned char> in) noexcept {
+ m_numerator.Multiply(ToNum3072(in));
+ return *this;
+}
+
+MuHash3072& MuHash3072::Remove(Span<const unsigned char> in) noexcept {
+ m_numerator.Divide(ToNum3072(in));
+ return *this;
+}
diff --git a/src/crypto/muhash.h b/src/crypto/muhash.h
new file mode 100644
index 0000000000..0c710007c4
--- /dev/null
+++ b/src/crypto/muhash.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CRYPTO_MUHASH_H
+#define BITCOIN_CRYPTO_MUHASH_H
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <serialize.h>
+#include <uint256.h>
+
+#include <stdint.h>
+
+class Num3072
+{
+private:
+ void FullReduce();
+ bool IsOverflow() const;
+ Num3072 GetInverse() const;
+
+public:
+
+#ifdef HAVE___INT128
+ typedef unsigned __int128 double_limb_t;
+ typedef uint64_t limb_t;
+ static constexpr int LIMBS = 48;
+ static constexpr int LIMB_SIZE = 64;
+#else
+ typedef uint64_t double_limb_t;
+ typedef uint32_t limb_t;
+ static constexpr int LIMBS = 96;
+ static constexpr int LIMB_SIZE = 32;
+#endif
+ limb_t limbs[LIMBS];
+
+ // Sanity check for Num3072 constants
+ static_assert(LIMB_SIZE * LIMBS == 3072, "Num3072 isn't 3072 bits");
+ static_assert(sizeof(double_limb_t) == sizeof(limb_t) * 2, "bad size for double_limb_t");
+ static_assert(sizeof(limb_t) * 8 == LIMB_SIZE, "LIMB_SIZE is incorrect");
+
+ // Hard coded values in MuHash3072 constructor and Finalize
+ static_assert(sizeof(limb_t) == 4 || sizeof(limb_t) == 8, "bad size for limb_t");
+
+ void Multiply(const Num3072& a);
+ void Divide(const Num3072& a);
+ void SetToOne();
+ void Square();
+
+ Num3072() { this->SetToOne(); };
+
+ SERIALIZE_METHODS(Num3072, obj)
+ {
+ for (auto& limb : obj.limbs) {
+ READWRITE(limb);
+ }
+ }
+};
+
+/** A class representing MuHash sets
+ *
+ * MuHash is a hashing algorithm that supports adding set elements in any
+ * order but also deleting in any order. As a result, it can maintain a
+ * running sum for a set of data as a whole, and add/remove when data
+ * is added to or removed from it. A downside of MuHash is that computing
+ * an inverse is relatively expensive. This is solved by representing
+ * the running value as a fraction, and multiplying added elements into
+ * the numerator and removed elements into the denominator. Only when the
+ * final hash is desired, a single modular inverse and multiplication is
+ * needed to combine the two. The combination is also run on serialization
+ * to allow for space-efficient storage on disk.
+ *
+ * As the update operations are also associative, H(a)+H(b)+H(c)+H(d) can
+ * in fact be computed as (H(a)+H(b)) + (H(c)+H(d)). This implies that
+ * all of this is perfectly parallellizable: each thread can process an
+ * arbitrary subset of the update operations, allowing them to be
+ * efficiently combined later.
+ *
+ * Muhash does not support checking if an element is already part of the
+ * set. That is why this class does not enforce the use of a set as the
+ * data it represents because there is no efficient way to do so.
+ * It is possible to add elements more than once and also to remove
+ * elements that have not been added before. However, this implementation
+ * is intended to represent a set of elements.
+ *
+ * See also https://cseweb.ucsd.edu/~mihir/papers/inchash.pdf and
+ * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-May/014337.html.
+ */
+class MuHash3072
+{
+private:
+ static constexpr size_t BYTE_SIZE = 384;
+
+ Num3072 m_numerator;
+ Num3072 m_denominator;
+
+ Num3072 ToNum3072(Span<const unsigned char> in);
+
+public:
+ /* The empty set. */
+ MuHash3072() noexcept {};
+
+ /* A singleton with variable sized data in it. */
+ explicit MuHash3072(Span<const unsigned char> in) noexcept;
+
+ /* Insert a single piece of data into the set. */
+ MuHash3072& Insert(Span<const unsigned char> in) noexcept;
+
+ /* Remove a single piece of data from the set. */
+ MuHash3072& Remove(Span<const unsigned char> in) noexcept;
+
+ /* Multiply (resulting in a hash for the union of the sets) */
+ MuHash3072& operator*=(const MuHash3072& mul) noexcept;
+
+ /* Divide (resulting in a hash for the difference of the sets) */
+ MuHash3072& operator/=(const MuHash3072& div) noexcept;
+
+ /* Finalize into a 32-byte hash. Does not change this object's value. */
+ void Finalize(uint256& out) noexcept;
+
+ SERIALIZE_METHODS(MuHash3072, obj)
+ {
+ READWRITE(obj.m_numerator);
+ READWRITE(obj.m_denominator);
+ }
+};
+
+#endif // BITCOIN_CRYPTO_MUHASH_H
diff --git a/src/crypto/sha256_shani.cpp b/src/crypto/sha256_shani.cpp
index 3473f6e39f..4f4d5b5837 100644
--- a/src/crypto/sha256_shani.cpp
+++ b/src/crypto/sha256_shani.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/crypto/sha256_sse4.cpp b/src/crypto/sha256_sse4.cpp
index 89f529a3ab..143752c7cf 100644
--- a/src/crypto/sha256_sse4.cpp
+++ b/src/crypto/sha256_sse4.cpp
@@ -1001,7 +1001,7 @@ void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks)
; This code is described in an Intel White-Paper:
; "Fast SHA-256 Implementations on Intel Architecture Processors"
;
-; To find it, surf to http://www.intel.com/p/en_US/embedded
+; To find it, surf to https://www.intel.com/p/en_US/embedded
; and search for that title.
; The paper is expected to be released roughly at the end of April, 2012
;
diff --git a/src/crypto/siphash.cpp b/src/crypto/siphash.cpp
index 2e0106b165..2e90c393e1 100644
--- a/src/crypto/siphash.cpp
+++ b/src/crypto/siphash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/crypto/siphash.h b/src/crypto/siphash.h
index 6b38950f8e..b573526932 100644
--- a/src/crypto/siphash.h
+++ b/src/crypto/siphash.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index 2daf676c4a..1166466771 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -225,7 +225,7 @@ private:
* [0, 1) and simply multiply it by the size. Then we just shift the result down by
* 32-bits to get our bucket number. The result has non-uniformity the same as a
* mod, but it is much faster to compute. More about this technique can be found at
- * http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ .
+ * https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ .
*
* The resulting non-uniformity is also more equally distributed which would be
* advantageous for something like linear probing, though it shouldn't matter
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index 215b033708..33e4b366a1 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/flatfile.cpp b/src/flatfile.cpp
index 8a8f7b681c..11cf357f3d 100644
--- a/src/flatfile.cpp
+++ b/src/flatfile.cpp
@@ -92,6 +92,7 @@ bool FlatFileSeq::Flush(const FlatFilePos& pos, bool finalize)
fclose(file);
return error("%s: failed to commit file %d", __func__, pos.nFile);
}
+ DirectoryCommit(m_dir);
fclose(file);
return true;
diff --git a/src/fs.cpp b/src/fs.cpp
index eef9c81de9..4f20ca4d28 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,6 +31,12 @@ FILE *fopen(const fs::path& p, const char *mode)
#endif
}
+fs::path AbsPathJoin(const fs::path& base, const fs::path& path)
+{
+ assert(base.is_absolute());
+ return fs::absolute(path, base);
+}
+
#ifndef WIN32
static std::string GetErrorReason()
diff --git a/src/fs.h b/src/fs.h
index dfbecc18e6..d77b90be66 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -21,6 +21,17 @@ namespace fs = boost::filesystem;
namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode);
+ /**
+ * Helper function for joining two paths
+ *
+ * @param[in] base Base path
+ * @param[in] path Path to combine with base
+ * @returns path unchanged if it is an absolute path, otherwise returns base joined with path. Returns base unchanged if path is empty.
+ * @pre Base path must be absolute
+ * @post Returned path will always be absolute
+ */
+ fs::path AbsPathJoin(const fs::path& base, const fs::path& path);
+
class FileLock
{
public:
diff --git a/src/hash.cpp b/src/hash.cpp
index 3657b38639..cc46043c2b 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2018 The Bitcoin Core developers
+// Copyright (c) 2013-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@ inline uint32_t ROTL32(uint32_t x, int8_t r)
unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vDataToHash)
{
- // The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+ // The following is MurmurHash3 (x86_32), see https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
uint32_t h1 = nHashSeed;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
diff --git a/src/hash.h b/src/hash.h
index 083ac12523..1456a899d8 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/httprpc.h b/src/httprpc.h
index a6a38fc95a..97af6f7bb1 100644
--- a/src/httprpc.h
+++ b/src/httprpc.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index 65a5f03a8e..4f61bbeabd 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -51,7 +51,6 @@ struct DBVal {
struct DBHeightKey {
int height;
- DBHeightKey() : height(0) {}
explicit DBHeightKey(int height_in) : height(height_in) {}
template<typename Stream>
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index 317f8c0e40..221ac02c9e 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,15 +9,11 @@
#include <chain.h>
#include <flatfile.h>
#include <index/base.h>
+#include <util/hasher.h>
/** Interval between compact filter checkpoints. See BIP 157. */
static constexpr int CFCHECKPT_INTERVAL = 1000;
-struct FilterHeaderHasher
-{
- size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
-};
-
/**
* BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of
* blocks by height. An index is constructed for each supported filter type with its own database
diff --git a/src/index/disktxpos.h b/src/index/disktxpos.h
index 69696b0ec5..3166053226 100644
--- a/src/index/disktxpos.h
+++ b/src/index/disktxpos.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 462ac5962f..6398b7edc8 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/init.cpp b/src/init.cpp
index 1220f39b14..64bbf8988d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -26,6 +26,7 @@
#include <interfaces/chain.h>
#include <interfaces/node.h>
#include <key.h>
+#include <mapport.h>
#include <miner.h>
#include <net.h>
#include <net_permissions.h>
@@ -222,6 +223,7 @@ void Shutdown(NodeContext& node)
if (g_load_block.joinable()) g_load_block.join();
threadGroup.interrupt_all();
threadGroup.join_all();
+ StopScriptCheckWorkerThreads();
// After the threads that potentially access these pointers have been stopped,
// destruct and reset all to nullptr.
@@ -446,7 +448,7 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-maxtimeadjustment", strprintf("Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)", DEFAULT_MAX_TIME_ADJUSTMENT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-maxuploadtarget=<n>", strprintf("Tries to keep outbound traffic under the given target (in MiB per 24h). Limit does not apply to peers with 'download' permission. 0 = no limit (default: %d)", DEFAULT_MAX_UPLOAD_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-onion=<ip:port>", "Use separate SOCKS5 proxy to reach peers via Tor onion services, set -noonion to disable (default: -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
- argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
+ argsman.AddArg("-onlynet=<net>", "Make outgoing connections only through network <net> (ipv4, ipv6 or onion). Incoming connections are not affected by this option. This option can be specified multiple times to allow multiple networks. Warning: if it is used with ipv4 or ipv6 but not onion and the -onion or -proxy option is set, then outbound onion connections will still be made; use -noonion or -onion=0 to disable outbound onion connections in this case.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -468,6 +470,11 @@ void SetupServerArgs(NodeContext& node)
#else
hidden_args.emplace_back("-upnp");
#endif
+#ifdef USE_NATPMP
+ argsman.AddArg("-natpmp", strprintf("Use NAT-PMP to map the listening port (default: %s)", DEFAULT_NATPMP ? "1 when listening and no -proxy" : "0"), ArgsManager::ALLOW_BOOL, OptionsCategory::CONNECTION);
+#else
+ hidden_args.emplace_back("-natpmp");
+#endif // USE_NATPMP
argsman.AddArg("-whitebind=<[permissions@]addr>", "Bind to the given address and add permission flags to the peers connecting to it. "
"Use [host]:port notation for IPv6. Allowed permissions: " + Join(NET_PERMISSIONS_DOC, ", ") + ". "
"Specify multiple permissions separated by commas (default: download,noban,mempool,relay). Can be specified multiple times.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
@@ -508,7 +515,6 @@ void SetupServerArgs(NodeContext& node)
argsman.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-checkpoints", strprintf("Enable rejection of any forks from the known historical chain until block %s (default: %u)", defaultChainParams->Checkpoints().GetHeight(), DEFAULT_CHECKPOINTS_ENABLED), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
- argsman.AddArg("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
@@ -813,10 +819,13 @@ void InitParameterInteraction(ArgsManager& args)
// to protect privacy, do not listen by default if a default proxy server is specified
if (args.SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
- // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1
+ // to protect privacy, do not map ports when a proxy is set. The user may still specify -listen=1
// to listen locally, so don't rely on this happening through -listen below.
if (args.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
+ if (args.SoftSetBoolArg("-natpmp", false)) {
+ LogPrintf("%s: parameter interaction: -proxy set -> setting -natpmp=0\n", __func__);
+ }
// to protect privacy, do not discover addresses by default
if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
@@ -826,6 +835,9 @@ void InitParameterInteraction(ArgsManager& args)
// do not map ports or try to retrieve public IP when not listening (pointless)
if (args.SoftSetBoolArg("-upnp", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__);
+ if (args.SoftSetBoolArg("-natpmp", false)) {
+ LogPrintf("%s: parameter interaction: -listen=0 -> setting -natpmp=0\n", __func__);
+ }
if (args.SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__);
if (args.SoftSetBoolArg("-listenonion", false))
@@ -1323,9 +1335,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
LogPrintf("Script verification uses %d additional threads\n", script_threads);
if (script_threads >= 1) {
g_parallel_script_checks = true;
- for (int i = 0; i < script_threads; ++i) {
- threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
- }
+ StartScriptCheckWorkerThreads(script_threads);
}
assert(!node.scheduler);
@@ -1399,8 +1409,8 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
ChainstateManager& chainman = *Assert(node.chainman);
assert(!node.peerman);
- node.peerman = std::make_unique<PeerManager>(chainparams, *node.connman, node.banman.get(),
- *node.scheduler, chainman, *node.mempool, ignores_incoming_txs);
+ node.peerman = PeerManager::make(chainparams, *node.connman, node.banman.get(),
+ *node.scheduler, chainman, *node.mempool, ignores_incoming_txs);
RegisterValidationInterface(node.peerman.get());
// sanitize comments per BIP-0014, format user agent and check total size
@@ -1895,13 +1905,12 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
}
}
LogPrintf("nBestHeight = %d\n", chain_active_height);
+ if (node.peerman) node.peerman->SetBestHeight(chain_active_height);
Discover();
- // Map ports with UPnP
- if (args.GetBoolArg("-upnp", DEFAULT_UPNP)) {
- StartMapPort();
- }
+ // Map ports with UPnP or NAT-PMP.
+ StartMapPort(args.GetBoolArg("-upnp", DEFAULT_UPNP), gArgs.GetBoolArg("-natpmp", DEFAULT_NATPMP));
CConnman::Options connOptions;
connOptions.nLocalServices = nLocalServices;
@@ -1910,7 +1919,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
connOptions.m_max_outbound_block_relay = std::min(MAX_BLOCK_RELAY_ONLY_CONNECTIONS, connOptions.nMaxConnections-connOptions.m_max_outbound_full_relay);
connOptions.nMaxAddnode = MAX_ADDNODE_CONNECTIONS;
connOptions.nMaxFeeler = MAX_FEELER_CONNECTIONS;
- connOptions.nBestHeight = chain_active_height;
connOptions.uiInterface = &uiInterface;
connOptions.m_banman = node.banman.get();
connOptions.m_msgproc = node.peerman.get();
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 36f76aeb4f..15f7ef6256 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -82,7 +82,7 @@ public:
virtual bool shutdownRequested() = 0;
//! Map port.
- virtual void mapPort(bool use_upnp) = 0;
+ virtual void mapPort(bool use_upnp, bool use_natpmp) = 0;
//! Get proxy.
virtual bool getProxy(Network net, proxyType& proxy_info) = 0;
diff --git a/src/key.cpp b/src/key.cpp
index 868a8b9b0e..1e59b301cb 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,7 +18,7 @@ static secp256k1_context* secp256k1_context_sign = nullptr;
/**
* This parses a format loosely based on a DER encoding of the ECPrivateKey type from
- * section C.4 of SEC 1 <http://www.secg.org/sec1-v2.pdf>, with the following caveats:
+ * section C.4 of SEC 1 <https://www.secg.org/sec1-v2.pdf>, with the following caveats:
*
* * The octet-length of the SEQUENCE must be encoded as 1 or 2 octets. It is not
* required to be encoded as one octet if it is less than 256, as DER would require.
@@ -80,7 +80,7 @@ int ec_seckey_import_der(const secp256k1_context* ctx, unsigned char *out32, con
/**
* This serializes to a DER encoding of the ECPrivateKey type from section C.4 of SEC 1
- * <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
+ * <https://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
* included.
*
* seckey must point to an output buffer of length at least CKey::SIZE bytes.
diff --git a/src/key_io.cpp b/src/key_io.cpp
index d2f5be93f5..e27673fd16 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -8,16 +8,15 @@
#include <bech32.h>
#include <util/strencodings.h>
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-
+#include <algorithm>
#include <assert.h>
#include <string.h>
-#include <algorithm>
-namespace
-{
-class DestinationEncoder : public boost::static_visitor<std::string>
+/// Maximum witness length for Bech32 addresses.
+static constexpr std::size_t BECH32_WITNESS_PROG_MAX_LEN = 40;
+
+namespace {
+class DestinationEncoder
{
private:
const CChainParams& m_params;
@@ -69,10 +68,11 @@ public:
std::string operator()(const CNoDestination& no) const { return {}; }
};
-CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
+CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
{
std::vector<unsigned char> data;
uint160 hash;
+ error_str = "";
if (DecodeBase58Check(str, data, 21)) {
// base58-encoded Bitcoin addresses.
// Public-key-hash-addresses have version 0 (or 111 testnet).
@@ -89,10 +89,21 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
return ScriptHash(hash);
}
+
+ // Set potential error message.
+ // This message may be changed if the address can also be interpreted as a Bech32 address.
+ error_str = "Invalid prefix for Base58-encoded address";
}
data.clear();
auto bech = bech32::Decode(str);
- if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
+ if (bech.second.size() > 0) {
+ error_str = "";
+
+ if (bech.first != params.Bech32HRP()) {
+ error_str = "Invalid prefix for Bech32 address";
+ return CNoDestination();
+ }
+
// Bech32 decoding
int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
// The rest of the symbols are converted witness program bytes.
@@ -113,11 +124,21 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return scriptid;
}
}
+
+ error_str = "Invalid Bech32 v0 address data size";
return CNoDestination();
}
- if (version > 16 || data.size() < 2 || data.size() > 40) {
+
+ if (version > 16) {
+ error_str = "Invalid Bech32 address witness version";
return CNoDestination();
}
+
+ if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) {
+ error_str = "Invalid Bech32 address data size";
+ return CNoDestination();
+ }
+
WitnessUnknown unk;
unk.version = version;
std::copy(data.begin(), data.end(), unk.program);
@@ -125,6 +146,10 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return unk;
}
}
+
+ // Set error message if address can't be interpreted as Base58 or Bech32.
+ if (error_str.empty()) error_str = "Invalid address format";
+
return CNoDestination();
}
} // namespace
@@ -209,17 +234,24 @@ std::string EncodeExtKey(const CExtKey& key)
std::string EncodeDestination(const CTxDestination& dest)
{
- return boost::apply_visitor(DestinationEncoder(Params()), dest);
+ return std::visit(DestinationEncoder(Params()), dest);
+}
+
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
+{
+ return DecodeDestination(str, Params(), error_msg);
}
CTxDestination DecodeDestination(const std::string& str)
{
- return DecodeDestination(str, Params());
+ std::string error_msg;
+ return DecodeDestination(str, error_msg);
}
bool IsValidDestinationString(const std::string& str, const CChainParams& params)
{
- return IsValidDestination(DecodeDestination(str, params));
+ std::string error_msg;
+ return IsValidDestination(DecodeDestination(str, params, error_msg));
}
bool IsValidDestinationString(const std::string& str)
diff --git a/src/key_io.h b/src/key_io.h
index d80c08f49c..bd81f7847e 100644
--- a/src/key_io.h
+++ b/src/key_io.h
@@ -23,6 +23,7 @@ std::string EncodeExtPubKey(const CExtPubKey& extpubkey);
std::string EncodeDestination(const CTxDestination& dest);
CTxDestination DecodeDestination(const std::string& str);
+CTxDestination DecodeDestination(const std::string& str, std::string& error_msg);
bool IsValidDestinationString(const std::string& str);
bool IsValidDestinationString(const std::string& str, const CChainParams& params);
diff --git a/src/logging.cpp b/src/logging.cpp
index 35e0754f20..4ddcf1d930 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -174,7 +174,7 @@ bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str)
return false;
}
-std::vector<LogCategory> BCLog::Logger::LogCategoriesList()
+std::vector<LogCategory> BCLog::Logger::LogCategoriesList() const
{
std::vector<LogCategory> ret;
for (const CLogCategoryDesc& category_desc : LogCategories) {
diff --git a/src/logging.h b/src/logging.h
index 7e646ef67a..9efecc7c12 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -135,9 +135,9 @@ namespace BCLog {
bool WillLogCategory(LogFlags category) const;
/** Returns a vector of the log categories */
- std::vector<LogCategory> LogCategoriesList();
+ std::vector<LogCategory> LogCategoriesList() const;
/** Returns a string with the log categories */
- std::string LogCategoriesString()
+ std::string LogCategoriesString() const
{
return Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; });
};
diff --git a/src/mapport.cpp b/src/mapport.cpp
new file mode 100644
index 0000000000..2df4ce45d2
--- /dev/null
+++ b/src/mapport.cpp
@@ -0,0 +1,336 @@
+// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <mapport.h>
+
+#include <clientversion.h>
+#include <logging.h>
+#include <net.h>
+#include <netaddress.h>
+#include <netbase.h>
+#include <threadinterrupt.h>
+#include <util/system.h>
+
+#ifdef USE_NATPMP
+#include <compat.h>
+#include <natpmp.h>
+#endif // USE_NATPMP
+
+#ifdef USE_UPNP
+#include <miniupnpc/miniupnpc.h>
+#include <miniupnpc/upnpcommands.h>
+#include <miniupnpc/upnperrors.h>
+// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
+// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
+static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
+#endif // USE_UPNP
+
+#include <atomic>
+#include <cassert>
+#include <chrono>
+#include <functional>
+#include <string>
+#include <thread>
+
+#if defined(USE_NATPMP) || defined(USE_UPNP)
+static CThreadInterrupt g_mapport_interrupt;
+static std::thread g_mapport_thread;
+static std::atomic_uint g_mapport_enabled_protos{MapPortProtoFlag::NONE};
+static std::atomic<MapPortProtoFlag> g_mapport_current_proto{MapPortProtoFlag::NONE};
+
+using namespace std::chrono_literals;
+static constexpr auto PORT_MAPPING_REANNOUNCE_PERIOD{20min};
+static constexpr auto PORT_MAPPING_RETRY_PERIOD{5min};
+
+#ifdef USE_NATPMP
+static uint16_t g_mapport_external_port = 0;
+static bool NatpmpInit(natpmp_t* natpmp)
+{
+ const int r_init = initnatpmp(natpmp, /* detect gateway automatically */ 0, /* forced gateway - NOT APPLIED*/ 0);
+ if (r_init == 0) return true;
+ LogPrintf("natpmp: initnatpmp() failed with %d error.\n", r_init);
+ return false;
+}
+
+static bool NatpmpDiscover(natpmp_t* natpmp, struct in_addr& external_ipv4_addr)
+{
+ const int r_send = sendpublicaddressrequest(natpmp);
+ if (r_send == 2 /* OK */) {
+ int r_read;
+ natpmpresp_t response;
+ do {
+ r_read = readnatpmpresponseorretry(natpmp, &response);
+ } while (r_read == NATPMP_TRYAGAIN);
+
+ if (r_read == 0) {
+ external_ipv4_addr = response.pnu.publicaddress.addr;
+ return true;
+ } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
+ LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
+ } else {
+ LogPrintf("natpmp: readnatpmpresponseorretry() for public address failed with %d error.\n", r_read);
+ }
+ } else {
+ LogPrintf("natpmp: sendpublicaddressrequest() failed with %d error.\n", r_send);
+ }
+
+ return false;
+}
+
+static bool NatpmpMapping(natpmp_t* natpmp, const struct in_addr& external_ipv4_addr, uint16_t private_port, bool& external_ip_discovered)
+{
+ const uint16_t suggested_external_port = g_mapport_external_port ? g_mapport_external_port : private_port;
+ const int r_send = sendnewportmappingrequest(natpmp, NATPMP_PROTOCOL_TCP, private_port, suggested_external_port, 3600 /*seconds*/);
+ if (r_send == 12 /* OK */) {
+ int r_read;
+ natpmpresp_t response;
+ do {
+ r_read = readnatpmpresponseorretry(natpmp, &response);
+ } while (r_read == NATPMP_TRYAGAIN);
+
+ if (r_read == 0) {
+ auto pm = response.pnu.newportmapping;
+ if (private_port == pm.privateport && pm.lifetime > 0) {
+ g_mapport_external_port = pm.mappedpublicport;
+ const CService external{external_ipv4_addr, pm.mappedpublicport};
+ if (!external_ip_discovered && fDiscover) {
+ AddLocal(external, LOCAL_MAPPED);
+ external_ip_discovered = true;
+ }
+ LogPrintf("natpmp: Port mapping successful. External address = %s\n", external.ToString());
+ return true;
+ } else {
+ LogPrintf("natpmp: Port mapping failed.\n");
+ }
+ } else if (r_read == NATPMP_ERR_NOGATEWAYSUPPORT) {
+ LogPrintf("natpmp: The gateway does not support NAT-PMP.\n");
+ } else {
+ LogPrintf("natpmp: readnatpmpresponseorretry() for port mapping failed with %d error.\n", r_read);
+ }
+ } else {
+ LogPrintf("natpmp: sendnewportmappingrequest() failed with %d error.\n", r_send);
+ }
+
+ return false;
+}
+
+static bool ProcessNatpmp()
+{
+ bool ret = false;
+ natpmp_t natpmp;
+ struct in_addr external_ipv4_addr;
+ if (NatpmpInit(&natpmp) && NatpmpDiscover(&natpmp, external_ipv4_addr)) {
+ bool external_ip_discovered = false;
+ const uint16_t private_port = GetListenPort();
+ do {
+ ret = NatpmpMapping(&natpmp, external_ipv4_addr, private_port, external_ip_discovered);
+ } while (ret && g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
+ g_mapport_interrupt.reset();
+
+ const int r_send = sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, private_port, g_mapport_external_port, /* remove a port mapping */ 0);
+ g_mapport_external_port = 0;
+ if (r_send == 12 /* OK */) {
+ LogPrintf("natpmp: Port mapping removed successfully.\n");
+ } else {
+ LogPrintf("natpmp: sendnewportmappingrequest(0) failed with %d error.\n", r_send);
+ }
+ }
+
+ closenatpmp(&natpmp);
+ return ret;
+}
+#endif // USE_NATPMP
+
+#ifdef USE_UPNP
+static bool ProcessUpnp()
+{
+ bool ret = false;
+ std::string port = strprintf("%u", GetListenPort());
+ const char * multicastif = nullptr;
+ const char * minissdpdpath = nullptr;
+ struct UPNPDev * devlist = nullptr;
+ char lanaddr[64];
+
+ int error = 0;
+#if MINIUPNPC_API_VERSION < 14
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+#else
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
+#endif
+
+ struct UPNPUrls urls;
+ struct IGDdatas data;
+ int r;
+
+ r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
+ if (r == 1)
+ {
+ if (fDiscover) {
+ char externalIPAddress[40];
+ r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
+ if (r != UPNPCOMMAND_SUCCESS) {
+ LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
+ } else {
+ if (externalIPAddress[0]) {
+ CNetAddr resolved;
+ if (LookupHost(externalIPAddress, resolved, false)) {
+ LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString());
+ AddLocal(resolved, LOCAL_MAPPED);
+ }
+ } else {
+ LogPrintf("UPnP: GetExternalIPAddress failed.\n");
+ }
+ }
+ }
+
+ std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
+
+ do {
+ r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
+
+ if (r != UPNPCOMMAND_SUCCESS) {
+ ret = false;
+ LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
+ break;
+ } else {
+ ret = true;
+ LogPrintf("UPnP Port Mapping successful.\n");
+ }
+ } while (g_mapport_interrupt.sleep_for(PORT_MAPPING_REANNOUNCE_PERIOD));
+ g_mapport_interrupt.reset();
+
+ r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
+ LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
+ freeUPNPDevlist(devlist); devlist = nullptr;
+ FreeUPNPUrls(&urls);
+ } else {
+ LogPrintf("No valid UPnP IGDs found\n");
+ freeUPNPDevlist(devlist); devlist = nullptr;
+ if (r != 0)
+ FreeUPNPUrls(&urls);
+ }
+
+ return ret;
+}
+#endif // USE_UPNP
+
+static void ThreadMapPort()
+{
+ bool ok;
+ do {
+ ok = false;
+
+#ifdef USE_UPNP
+ // High priority protocol.
+ if (g_mapport_enabled_protos & MapPortProtoFlag::UPNP) {
+ g_mapport_current_proto = MapPortProtoFlag::UPNP;
+ ok = ProcessUpnp();
+ if (ok) continue;
+ }
+#endif // USE_UPNP
+
+#ifdef USE_NATPMP
+ // Low priority protocol.
+ if (g_mapport_enabled_protos & MapPortProtoFlag::NAT_PMP) {
+ g_mapport_current_proto = MapPortProtoFlag::NAT_PMP;
+ ok = ProcessNatpmp();
+ if (ok) continue;
+ }
+#endif // USE_NATPMP
+
+ g_mapport_current_proto = MapPortProtoFlag::NONE;
+ if (g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ return;
+ }
+
+ } while (ok || g_mapport_interrupt.sleep_for(PORT_MAPPING_RETRY_PERIOD));
+}
+
+void StartThreadMapPort()
+{
+ if (!g_mapport_thread.joinable()) {
+ assert(!g_mapport_interrupt);
+ g_mapport_thread = std::thread(std::bind(&TraceThread<void (*)()>, "mapport", &ThreadMapPort));
+ }
+}
+
+static void DispatchMapPort()
+{
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ return;
+ }
+
+ if (g_mapport_current_proto == MapPortProtoFlag::NONE && g_mapport_enabled_protos != MapPortProtoFlag::NONE) {
+ StartThreadMapPort();
+ return;
+ }
+
+ if (g_mapport_current_proto != MapPortProtoFlag::NONE && g_mapport_enabled_protos == MapPortProtoFlag::NONE) {
+ InterruptMapPort();
+ StopMapPort();
+ return;
+ }
+
+ if (g_mapport_enabled_protos & g_mapport_current_proto) {
+ // Enabling another protocol does not cause switching from the currently used one.
+ return;
+ }
+
+ assert(g_mapport_thread.joinable());
+ assert(!g_mapport_interrupt);
+ // Interrupt a protocol-specific loop in the ThreadUpnp() or in the ThreadNatpmp()
+ // to force trying the next protocol in the ThreadMapPort() loop.
+ g_mapport_interrupt();
+}
+
+static void MapPortProtoSetEnabled(MapPortProtoFlag proto, bool enabled)
+{
+ if (enabled) {
+ g_mapport_enabled_protos |= proto;
+ } else {
+ g_mapport_enabled_protos &= ~proto;
+ }
+}
+
+void StartMapPort(bool use_upnp, bool use_natpmp)
+{
+ MapPortProtoSetEnabled(MapPortProtoFlag::UPNP, use_upnp);
+ MapPortProtoSetEnabled(MapPortProtoFlag::NAT_PMP, use_natpmp);
+ DispatchMapPort();
+}
+
+void InterruptMapPort()
+{
+ g_mapport_enabled_protos = MapPortProtoFlag::NONE;
+ if (g_mapport_thread.joinable()) {
+ g_mapport_interrupt();
+ }
+}
+
+void StopMapPort()
+{
+ if (g_mapport_thread.joinable()) {
+ g_mapport_thread.join();
+ g_mapport_interrupt.reset();
+ }
+}
+
+#else // #if defined(USE_NATPMP) || defined(USE_UPNP)
+void StartMapPort(bool use_upnp, bool use_natpmp)
+{
+ // Intentionally left blank.
+}
+void InterruptMapPort()
+{
+ // Intentionally left blank.
+}
+void StopMapPort()
+{
+ // Intentionally left blank.
+}
+#endif // #if defined(USE_NATPMP) || defined(USE_UPNP)
diff --git a/src/mapport.h b/src/mapport.h
new file mode 100644
index 0000000000..279d65167f
--- /dev/null
+++ b/src/mapport.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011-2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_MAPPORT_H
+#define BITCOIN_MAPPORT_H
+
+#ifdef USE_UPNP
+static constexpr bool DEFAULT_UPNP = USE_UPNP;
+#else
+static constexpr bool DEFAULT_UPNP = false;
+#endif // USE_UPNP
+
+#ifdef USE_NATPMP
+static constexpr bool DEFAULT_NATPMP = USE_NATPMP;
+#else
+static constexpr bool DEFAULT_NATPMP = false;
+#endif // USE_NATPMP
+
+enum MapPortProtoFlag : unsigned int {
+ NONE = 0x00,
+ UPNP = 0x01,
+ NAT_PMP = 0x02,
+};
+
+void StartMapPort(bool use_upnp, bool use_natpmp);
+void InterruptMapPort();
+void StopMapPort();
+
+#endif // BITCOIN_MAPPORT_H
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index b571d463c9..3ffe1465da 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -59,7 +59,7 @@ uint256 CPartialMerkleTree::CalcHash(int height, unsigned int pos, const std::ve
//if we do not have this assert, we can hit a memory access violation when indexing into vTxid
assert(vTxid.size() != 0);
if (height == 0) {
- // hash at height 0 is the txids themself
+ // hash at height 0 is the txids themselves
return vTxid[pos];
} else {
// calculate left hash
diff --git a/src/merkleblock.h b/src/merkleblock.h
index b2d2828784..0e4ed72130 100644
--- a/src/merkleblock.h
+++ b/src/merkleblock.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/miner.cpp b/src/miner.cpp
index 41a835f70a..009ae6b13a 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -213,7 +213,7 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
// - transaction finality (locktime)
// - premature witness (in case segwit transactions are added to mempool before
// segwit activation)
-bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package)
+bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const
{
for (CTxMemPool::txiter it : package) {
if (!IsFinalTx(it->GetTx(), nHeight, nLockTimeCutoff))
diff --git a/src/miner.h b/src/miner.h
index bb7a30b184..9a2b7063f4 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -185,7 +185,7 @@ private:
* locktime, premature-witness, serialized size (if necessary)
* These checks should always succeed, and they're here
* only as an extra check in case of suboptimal node configuration */
- bool TestPackageTransactions(const CTxMemPool::setEntries& package);
+ bool TestPackageTransactions(const CTxMemPool::setEntries& package) const;
/** Return true if given transaction from mapTx has already been evaluated,
* or if the transaction's cached data in mapTx is incorrect. */
bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set& mapModifiedTx, CTxMemPool::setEntries& failedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
diff --git a/src/net.cpp b/src/net.cpp
index b3c521116b..76bf7effa4 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -33,17 +33,9 @@
#include <poll.h>
#endif
-#ifdef USE_UPNP
-#include <miniupnpc/miniupnpc.h>
-#include <miniupnpc/upnpcommands.h>
-#include <miniupnpc/upnperrors.h>
-// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility
-// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages.
-static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed");
-#endif
-
#include <algorithm>
#include <cstdint>
+#include <functional>
#include <unordered_map>
#include <math.h>
@@ -481,7 +473,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
NodeId id = GetNewNodeId();
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 : "", conn_type);
+ CNode* pnode = new CNode(id, nLocalServices, hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type);
pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count)
@@ -507,9 +499,9 @@ void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNet
}
}
-std::string CNode::ConnectionTypeAsString() const
+std::string ConnectionTypeAsString(ConnectionType conn_type)
{
- switch (m_conn_type) {
+ switch (conn_type) {
case ConnectionType::INBOUND:
return "inbound";
case ConnectionType::MANUAL:
@@ -555,7 +547,7 @@ void CNode::SetAddrLocal(const CService& addrLocalIn) {
Network CNode::ConnectedThroughNetwork() const
{
- return IsInboundConn() && m_inbound_onion ? NET_ONION : addr.GetNetClass();
+ return m_inbound_onion ? NET_ONION : addr.GetNetClass();
}
#undef X
@@ -566,7 +558,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
X(nServices);
X(addr);
X(addrBind);
- stats.m_network = GetNetworkName(ConnectedThroughNetwork());
+ stats.m_network = ConnectedThroughNetwork();
stats.m_mapped_as = addr.GetMappedAS(m_asmap);
if (m_tx_relay != nullptr) {
LOCK(m_tx_relay->cs_filter);
@@ -587,10 +579,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
X(cleanSubVer);
}
stats.fInbound = IsInboundConn();
- stats.m_manual_connection = IsManualConn();
X(m_bip152_highbandwidth_to);
X(m_bip152_highbandwidth_from);
- X(nStartingHeight);
{
LOCK(cs_vSend);
X(mapSendBytesPerMsgCmd);
@@ -601,10 +591,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
X(mapRecvBytesPerMsgCmd);
X(nRecvBytes);
}
- X(m_legacyWhitelisted);
X(m_permissionFlags);
if (m_tx_relay != nullptr) {
- LOCK(m_tx_relay->cs_feeFilter);
stats.minFeeFilter = m_tx_relay->minFeeFilter;
} else {
stats.minFeeFilter = 0;
@@ -630,7 +618,7 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
CService addrLocalUnlocked = GetAddrLocal();
stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToString() : "";
- stats.m_conn_type_string = ConnectionTypeAsString();
+ X(m_conn_type);
}
#undef X
@@ -793,30 +781,30 @@ void V1TransportSerializer::prepareForTransport(CSerializedNetMsg& msg, std::vec
CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, header, 0, hdr};
}
-size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pnode->cs_vSend)
+size_t CConnman::SocketSendData(CNode& node) const
{
- auto it = pnode->vSendMsg.begin();
+ auto it = node.vSendMsg.begin();
size_t nSentSize = 0;
- while (it != pnode->vSendMsg.end()) {
- const auto &data = *it;
- assert(data.size() > pnode->nSendOffset);
+ while (it != node.vSendMsg.end()) {
+ const auto& data = *it;
+ assert(data.size() > node.nSendOffset);
int nBytes = 0;
{
- LOCK(pnode->cs_hSocket);
- if (pnode->hSocket == INVALID_SOCKET)
+ LOCK(node.cs_hSocket);
+ if (node.hSocket == INVALID_SOCKET)
break;
- nBytes = send(pnode->hSocket, reinterpret_cast<const char*>(data.data()) + pnode->nSendOffset, data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
+ nBytes = send(node.hSocket, reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
}
if (nBytes > 0) {
- pnode->nLastSend = GetSystemTimeInSeconds();
- pnode->nSendBytes += nBytes;
- pnode->nSendOffset += nBytes;
+ node.nLastSend = GetSystemTimeInSeconds();
+ node.nSendBytes += nBytes;
+ node.nSendOffset += nBytes;
nSentSize += nBytes;
- if (pnode->nSendOffset == data.size()) {
- pnode->nSendOffset = 0;
- pnode->nSendSize -= data.size();
- pnode->fPauseSend = pnode->nSendSize > nSendBufferMaxSize;
+ if (node.nSendOffset == data.size()) {
+ node.nSendOffset = 0;
+ node.nSendSize -= data.size();
+ node.fPauseSend = node.nSendSize > nSendBufferMaxSize;
it++;
} else {
// could not send full message; stop sending more
@@ -826,10 +814,9 @@ size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pno
if (nBytes < 0) {
// error
int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
- {
- LogPrintf("socket send error %s\n", NetworkErrorString(nErr));
- pnode->CloseSocketDisconnect();
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) {
+ LogPrint(BCLog::NET, "socket send error for peer=%d: %s\n", node.GetId(), NetworkErrorString(nErr));
+ node.CloseSocketDisconnect();
}
}
// couldn't send anything at all
@@ -837,11 +824,11 @@ size_t CConnman::SocketSendData(CNode *pnode) const EXCLUSIVE_LOCKS_REQUIRED(pno
}
}
- if (it == pnode->vSendMsg.end()) {
- assert(pnode->nSendOffset == 0);
- assert(pnode->nSendSize == 0);
+ if (it == node.vSendMsg.end()) {
+ assert(node.nSendOffset == 0);
+ assert(node.nSendSize == 0);
}
- pnode->vSendMsg.erase(pnode->vSendMsg.begin(), it);
+ node.vSendMsg.erase(node.vSendMsg.begin(), it);
return nSentSize;
}
@@ -1017,6 +1004,7 @@ bool CConnman::AttemptToEvictConnection()
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (pnode->GetId() == *node_id_to_evict) {
+ LogPrint(BCLog::NET, "selected %s connection for eviction peer=%d; disconnecting\n", pnode->ConnectionTypeAsString(), pnode->GetId());
pnode->fDisconnect = true;
return true;
}
@@ -1041,14 +1029,12 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
NetPermissionFlags permissionFlags = NetPermissionFlags::PF_NONE;
hListenSocket.AddSocketPermissionFlags(permissionFlags);
AddWhitelistPermissionFlags(permissionFlags, addr);
- bool legacyWhitelisted = false;
if (NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::PF_ISIMPLICIT)) {
NetPermissions::ClearFlag(permissionFlags, PF_ISIMPLICIT);
if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) NetPermissions::AddFlag(permissionFlags, PF_FORCERELAY);
if (gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) NetPermissions::AddFlag(permissionFlags, PF_RELAY);
NetPermissions::AddFlag(permissionFlags, PF_MEMPOOL);
NetPermissions::AddFlag(permissionFlags, PF_NOBAN);
- legacyWhitelisted = true;
}
{
@@ -1067,7 +1053,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
}
if (!fNetworkActive) {
- LogPrintf("connection from %s dropped: not accepting new connections\n", addr.ToString());
+ LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToString());
CloseSocket(hSocket);
return;
}
@@ -1121,11 +1107,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
}
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
- CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND, inbound_onion);
+ CNode* pnode = new CNode(id, nodeServices, hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND, inbound_onion);
pnode->AddRef();
pnode->m_permissionFlags = permissionFlags;
- // If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility)
- pnode->m_legacyWhitelisted = legacyWhitelisted;
pnode->m_prefer_evict = discouraged;
m_msgproc->InitializeNode(pnode);
@@ -1140,6 +1124,27 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
RandAddEvent((uint32_t)id);
}
+bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
+{
+ if (conn_type != ConnectionType::OUTBOUND_FULL_RELAY && conn_type != ConnectionType::BLOCK_RELAY) return false;
+
+ const int max_connections = conn_type == ConnectionType::OUTBOUND_FULL_RELAY ? m_max_outbound_full_relay : m_max_outbound_block_relay;
+
+ // Count existing connections
+ int existing_connections = WITH_LOCK(cs_vNodes,
+ return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
+
+ // Max connections of specified type already exist
+ if (existing_connections >= max_connections) return false;
+
+ // Max total outbound connections already exist
+ CSemaphoreGrant grant(*semOutbound, true);
+ if (!grant) return false;
+
+ OpenNetworkConnection(CAddress(), false, &grant, address.c_str(), conn_type);
+ return true;
+}
+
void CConnman::DisconnectNodes()
{
{
@@ -1213,37 +1218,47 @@ void CConnman::NotifyNumConnectionsChanged()
}
}
-void CConnman::InactivityCheck(CNode *pnode)
+bool CConnman::InactivityCheck(const CNode& node) const
{
- int64_t nTime = GetSystemTimeInSeconds();
- if (nTime - pnode->nTimeConnected > m_peer_connect_timeout)
- {
- if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)
- {
- LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d from %d\n", m_peer_connect_timeout, pnode->nLastRecv != 0, pnode->nLastSend != 0, pnode->GetId());
- pnode->fDisconnect = true;
- }
- else if (nTime - pnode->nLastSend > TIMEOUT_INTERVAL)
- {
- LogPrintf("socket sending timeout: %is\n", nTime - pnode->nLastSend);
- pnode->fDisconnect = true;
- }
- else if (nTime - pnode->nLastRecv > TIMEOUT_INTERVAL)
- {
- LogPrintf("socket receive timeout: %is\n", nTime - pnode->nLastRecv);
- pnode->fDisconnect = true;
- }
- else if (pnode->nPingNonceSent && pnode->m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>())
- {
- LogPrintf("ping timeout: %fs\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - pnode->m_ping_start.load()));
- pnode->fDisconnect = true;
- }
- else if (!pnode->fSuccessfullyConnected)
- {
- LogPrint(BCLog::NET, "version handshake timeout from %d\n", pnode->GetId());
- pnode->fDisconnect = true;
- }
+ // Use non-mockable system time (otherwise these timers will pop when we
+ // use setmocktime in the tests).
+ int64_t now = GetSystemTimeInSeconds();
+
+ if (now <= node.nTimeConnected + m_peer_connect_timeout) {
+ // Only run inactivity checks if the peer has been connected longer
+ // than m_peer_connect_timeout.
+ return false;
+ }
+
+ if (node.nLastRecv == 0 || node.nLastSend == 0) {
+ LogPrint(BCLog::NET, "socket no message in first %i seconds, %d %d peer=%d\n", m_peer_connect_timeout, node.nLastRecv != 0, node.nLastSend != 0, node.GetId());
+ return true;
+ }
+
+ if (now > node.nLastSend + TIMEOUT_INTERVAL) {
+ LogPrint(BCLog::NET, "socket sending timeout: %is peer=%d\n", now - node.nLastSend, node.GetId());
+ return true;
+ }
+
+ if (now > node.nLastRecv + TIMEOUT_INTERVAL) {
+ LogPrint(BCLog::NET, "socket receive timeout: %is peer=%d\n", now - node.nLastRecv, node.GetId());
+ return true;
}
+
+ if (node.nPingNonceSent && node.m_ping_start.load() + std::chrono::seconds{TIMEOUT_INTERVAL} < GetTime<std::chrono::microseconds>()) {
+ // We use mockable time for ping timeouts. This means that setmocktime
+ // may cause pings to time out for peers that have been connected for
+ // longer than m_peer_connect_timeout.
+ LogPrint(BCLog::NET, "ping timeout: %fs peer=%d\n", 0.000001 * count_microseconds(GetTime<std::chrono::microseconds>() - node.m_ping_start.load()), node.GetId());
+ return true;
+ }
+
+ if (!node.fSuccessfullyConnected) {
+ LogPrint(BCLog::NET, "version handshake timeout peer=%d\n", node.GetId());
+ return true;
+ }
+
+ return false;
}
bool CConnman::GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set)
@@ -1513,19 +1528,13 @@ void CConnman::SocketHandler()
}
}
- //
- // Send
- //
- if (sendSet)
- {
- LOCK(pnode->cs_vSend);
- size_t nBytes = SocketSendData(pnode);
- if (nBytes) {
- RecordBytesSent(nBytes);
- }
+ if (sendSet) {
+ // Send data
+ size_t bytes_sent = WITH_LOCK(pnode->cs_vSend, return SocketSendData(*pnode));
+ if (bytes_sent) RecordBytesSent(bytes_sent);
}
- InactivityCheck(pnode);
+ if (InactivityCheck(*pnode)) pnode->fDisconnect = true;
}
{
LOCK(cs_vNodes);
@@ -1553,121 +1562,6 @@ void CConnman::WakeMessageHandler()
condMsgProc.notify_one();
}
-
-
-
-
-
-#ifdef USE_UPNP
-static CThreadInterrupt g_upnp_interrupt;
-static std::thread g_upnp_thread;
-static void ThreadMapPort()
-{
- std::string port = strprintf("%u", GetListenPort());
- const char * multicastif = nullptr;
- const char * minissdpdpath = nullptr;
- struct UPNPDev * devlist = nullptr;
- char lanaddr[64];
-
- int error = 0;
-#if MINIUPNPC_API_VERSION < 14
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
-#else
- devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
-#endif
-
- struct UPNPUrls urls;
- struct IGDdatas data;
- int r;
-
- r = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
- if (r == 1)
- {
- if (fDiscover) {
- char externalIPAddress[40];
- r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress);
- if (r != UPNPCOMMAND_SUCCESS) {
- LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r);
- } else {
- if (externalIPAddress[0]) {
- CNetAddr resolved;
- if (LookupHost(externalIPAddress, resolved, false)) {
- LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString());
- AddLocal(resolved, LOCAL_UPNP);
- }
- } else {
- LogPrintf("UPnP: GetExternalIPAddress failed.\n");
- }
- }
- }
-
- std::string strDesc = PACKAGE_NAME " " + FormatFullVersion();
-
- do {
- r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0");
-
- if (r != UPNPCOMMAND_SUCCESS) {
- LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r));
- } else {
- LogPrintf("UPnP Port Mapping successful.\n");
- }
- } while (g_upnp_interrupt.sleep_for(std::chrono::minutes(20)));
-
- r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0);
- LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r);
- freeUPNPDevlist(devlist); devlist = nullptr;
- FreeUPNPUrls(&urls);
- } else {
- LogPrintf("No valid UPnP IGDs found\n");
- freeUPNPDevlist(devlist); devlist = nullptr;
- if (r != 0)
- FreeUPNPUrls(&urls);
- }
-}
-
-void StartMapPort()
-{
- if (!g_upnp_thread.joinable()) {
- assert(!g_upnp_interrupt);
- g_upnp_thread = std::thread((std::bind(&TraceThread<void (*)()>, "upnp", &ThreadMapPort)));
- }
-}
-
-void InterruptMapPort()
-{
- if(g_upnp_thread.joinable()) {
- g_upnp_interrupt();
- }
-}
-
-void StopMapPort()
-{
- if(g_upnp_thread.joinable()) {
- g_upnp_thread.join();
- g_upnp_interrupt.reset();
- }
-}
-
-#else
-void StartMapPort()
-{
- // Intentionally left blank.
-}
-void InterruptMapPort()
-{
- // Intentionally left blank.
-}
-void StopMapPort()
-{
- // Intentionally left blank.
-}
-#endif
-
-
-
-
-
-
void CConnman::ThreadDNSAddressSeed()
{
FastRandomContext rng;
@@ -2800,6 +2694,7 @@ bool CConnman::DisconnectNode(const std::string& strNode)
{
LOCK(cs_vNodes);
if (CNode* pnode = FindNode(strNode)) {
+ LogPrint(BCLog::NET, "disconnect by address%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->GetId());
pnode->fDisconnect = true;
return true;
}
@@ -2812,6 +2707,7 @@ bool CConnman::DisconnectNode(const CSubNet& subnet)
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (subnet.Match(pnode->addr)) {
+ LogPrint(BCLog::NET, "disconnect by subnet%s matched peer=%d; disconnecting\n", (fLogIPs ? strprintf("=%s", subnet.ToString()) : ""), pnode->GetId());
pnode->fDisconnect = true;
disconnected = true;
}
@@ -2829,6 +2725,7 @@ bool CConnman::DisconnectNode(NodeId id)
LOCK(cs_vNodes);
for(CNode* pnode : vNodes) {
if (id == pnode->GetId()) {
+ LogPrint(BCLog::NET, "disconnect by id peer=%d; disconnecting\n", pnode->GetId());
pnode->fDisconnect = true;
return true;
}
@@ -2930,19 +2827,9 @@ ServiceFlags CConnman::GetLocalServices() const
return nLocalServices;
}
-void CConnman::SetBestHeight(int height)
-{
- nBestHeight.store(height, std::memory_order_release);
-}
-
-int CConnman::GetBestHeight() const
-{
- return nBestHeight.load(std::memory_order_acquire);
-}
-
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion)
+CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion)
: nTimeConnected(GetSystemTimeInSeconds()),
addr(addrIn),
addrBind(addrBindIn),
@@ -2951,12 +2838,11 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
nLocalHostNonce(nLocalHostNonceIn),
m_conn_type(conn_type_in),
nLocalServices(nLocalServicesIn),
- nMyStartingHeight(nMyStartingHeightIn),
m_inbound_onion(inbound_onion)
{
+ if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
hSocket = hSocketIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
- hashContinue = uint256();
if (conn_type_in != ConnectionType::BLOCK_RELAY) {
m_tx_relay = MakeUnique<TxRelay>();
}
@@ -3016,7 +2902,7 @@ void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
// If write queue empty, attempt "optimistic write"
if (optimisticSend == true)
- nBytesSent = SocketSendData(pnode);
+ nBytesSent = SocketSendData(*pnode);
}
if (nBytesSent)
RecordBytesSent(nBytesSent);
diff --git a/src/net.h b/src/net.h
index b7c45abb09..86fcee512a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -67,12 +67,6 @@ static const int MAX_BLOCK_RELAY_ONLY_CONNECTIONS = 2;
static const int MAX_FEELER_CONNECTIONS = 1;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
-/** -upnp default */
-#ifdef USE_UPNP
-static const bool DEFAULT_UPNP = USE_UPNP;
-#else
-static const bool DEFAULT_UPNP = false;
-#endif
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
@@ -117,7 +111,8 @@ struct CSerializedNetMsg
* connection. Aside from INBOUND, all types are initiated by us.
*
* If adding or removing types, please update CONNECTION_TYPE_DOC in
- * src/rpc/net.cpp. */
+ * src/rpc/net.cpp and src/qt/rpcconsole.cpp, as well as the descriptions in
+ * src/qt/guiutil.cpp and src/bitcoin-cli.cpp::NetinfoRequestHandler. */
enum class ConnectionType {
/**
* Inbound connections are those initiated by a peer. This is the only
@@ -128,7 +123,7 @@ enum class ConnectionType {
/**
* These are the default connections that we use to connect with the
- * network. There is no restriction on what is relayed- by default we relay
+ * network. There is no restriction on what is relayed; by default we relay
* blocks, addresses & transactions. We automatically attempt to open
* MAX_OUTBOUND_FULL_RELAY_CONNECTIONS using addresses from our AddrMan.
*/
@@ -136,8 +131,8 @@ enum class ConnectionType {
/**
- * We open manual connections to addresses that users explicitly inputted
- * via the addnode RPC, or the -connect command line argument. Even if a
+ * We open manual connections to addresses that users explicitly requested
+ * via the addnode RPC or the -addnode/-connect configuration options. Even if a
* manual connection is misbehaving, we do not automatically disconnect or
* add it to our discouragement filter.
*/
@@ -156,7 +151,7 @@ enum class ConnectionType {
* although in our codebase feeler connections encompass test-before-evict as well.
* We make these connections approximately every FEELER_INTERVAL:
* first we resolve previously found collisions if they exist (test-before-evict),
- * otherwise connect to a node from the new table.
+ * otherwise we connect to a node from the new table.
*/
FEELER,
@@ -180,468 +175,17 @@ enum class ConnectionType {
ADDR_FETCH,
};
-class NetEventsInterface;
-class CConnman
-{
-public:
-
- enum NumConnections {
- CONNECTIONS_NONE = 0,
- CONNECTIONS_IN = (1U << 0),
- CONNECTIONS_OUT = (1U << 1),
- CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
- };
-
- struct Options
- {
- ServiceFlags nLocalServices = NODE_NONE;
- int nMaxConnections = 0;
- int m_max_outbound_full_relay = 0;
- int m_max_outbound_block_relay = 0;
- int nMaxAddnode = 0;
- int nMaxFeeler = 0;
- int nBestHeight = 0;
- CClientUIInterface* uiInterface = nullptr;
- NetEventsInterface* m_msgproc = nullptr;
- BanMan* m_banman = nullptr;
- unsigned int nSendBufferMaxSize = 0;
- unsigned int nReceiveFloodSize = 0;
- uint64_t nMaxOutboundLimit = 0;
- int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT;
- std::vector<std::string> vSeedNodes;
- std::vector<NetWhitelistPermissions> vWhitelistedRange;
- std::vector<NetWhitebindPermissions> vWhiteBinds;
- std::vector<CService> vBinds;
- std::vector<CService> onion_binds;
- bool m_use_addrman_outgoing = true;
- std::vector<std::string> m_specified_outgoing;
- std::vector<std::string> m_added_nodes;
- std::vector<bool> m_asmap;
- };
-
- void Init(const Options& connOptions) {
- nLocalServices = connOptions.nLocalServices;
- nMaxConnections = connOptions.nMaxConnections;
- m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
- m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay;
- m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing;
- nMaxAddnode = connOptions.nMaxAddnode;
- nMaxFeeler = connOptions.nMaxFeeler;
- m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler;
- nBestHeight = connOptions.nBestHeight;
- clientInterface = connOptions.uiInterface;
- m_banman = connOptions.m_banman;
- m_msgproc = connOptions.m_msgproc;
- nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
- nReceiveFloodSize = connOptions.nReceiveFloodSize;
- m_peer_connect_timeout = connOptions.m_peer_connect_timeout;
- {
- LOCK(cs_totalBytesSent);
- nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
- }
- vWhitelistedRange = connOptions.vWhitelistedRange;
- {
- LOCK(cs_vAddedNodes);
- vAddedNodes = connOptions.m_added_nodes;
- }
- m_onion_binds = connOptions.onion_binds;
- }
-
- CConnman(uint64_t seed0, uint64_t seed1, bool network_active = true);
- ~CConnman();
- bool Start(CScheduler& scheduler, const Options& options);
-
- void StopThreads();
- void StopNodes();
- void Stop()
- {
- StopThreads();
- StopNodes();
- };
-
- void Interrupt();
- bool GetNetworkActive() const { return fNetworkActive; };
- bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
- void SetNetworkActive(bool active);
- void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type);
- bool CheckIncomingNonce(uint64_t nonce);
-
- bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
-
- void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
-
- using NodeFn = std::function<void(CNode*)>;
- void ForEachNode(const NodeFn& func)
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
- if (NodeFullyConnected(node))
- func(node);
- }
- };
-
- void ForEachNode(const NodeFn& func) const
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
- if (NodeFullyConnected(node))
- func(node);
- }
- };
-
- template<typename Callable, typename CallableAfter>
- void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
- if (NodeFullyConnected(node))
- pre(node);
- }
- post();
- };
-
- template<typename Callable, typename CallableAfter>
- void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
- {
- LOCK(cs_vNodes);
- for (auto&& node : vNodes) {
- if (NodeFullyConnected(node))
- pre(node);
- }
- post();
- };
-
- // Addrman functions
- void SetServices(const CService &addr, ServiceFlags nServices);
- void MarkAddressGood(const CAddress& addr);
- bool AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
- std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct);
- /**
- * Cache is used to minimize topology leaks, so it should
- * be used for all non-trusted calls, for example, p2p.
- * A non-malicious call (from RPC or a peer with addr permission) should
- * call the function without a parameter to avoid using the cache.
- */
- std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct);
-
- // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
- // a peer that is better than all our current peers.
- void SetTryNewOutboundPeer(bool flag);
- bool GetTryNewOutboundPeer();
-
- void StartExtraBlockRelayPeers() {
- LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n");
- m_start_extra_block_relay_peers = true;
- }
-
- // 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 GetExtraFullOutboundCount();
- // Count the number of block-relay-only peers we have over our limit.
- int GetExtraBlockRelayCount();
-
- bool AddNode(const std::string& node);
- bool RemoveAddedNode(const std::string& node);
- std::vector<AddedNodeInfo> GetAddedNodeInfo();
-
- size_t GetNodeCount(NumConnections num);
- void GetNodeStats(std::vector<CNodeStats>& vstats);
- bool DisconnectNode(const std::string& node);
- bool DisconnectNode(const CSubNet& subnet);
- bool DisconnectNode(const CNetAddr& addr);
- bool DisconnectNode(NodeId id);
-
- //! Used to convey which local services we are offering peers during node
- //! connection.
- //!
- //! The data returned by this is used in CNode construction,
- //! which is used to advertise which services we are offering
- //! that peer during `net_processing.cpp:PushNodeVersion()`.
- ServiceFlags GetLocalServices() const;
-
- uint64_t GetMaxOutboundTarget();
- std::chrono::seconds GetMaxOutboundTimeframe();
-
- //! check if the outbound target is reached
- //! if param historicalBlockServingLimit is set true, the function will
- //! response true if the limit for serving historical blocks has been reached
- bool OutboundTargetReached(bool historicalBlockServingLimit);
-
- //! response the bytes left in the current max outbound cycle
- //! in case of no limit, it will always response 0
- uint64_t GetOutboundTargetBytesLeft();
-
- //! returns the time left in the current max outbound cycle
- //! in case of no limit, it will always return 0
- std::chrono::seconds GetMaxOutboundTimeLeftInCycle();
-
- uint64_t GetTotalBytesRecv();
- uint64_t GetTotalBytesSent();
-
- void SetBestHeight(int height);
- int GetBestHeight() const;
-
- /** Get a unique deterministic randomizer. */
- CSipHasher GetDeterministicRandomizer(uint64_t id) const;
-
- unsigned int GetReceiveFloodSize() const;
-
- void WakeMessageHandler();
-
- /** Attempts to obfuscate tx time through exponentially distributed emitting.
- Works assuming that a single interval is used.
- Variable intervals will result in privacy decrease.
- */
- int64_t PoissonNextSendInbound(int64_t now, int average_interval_seconds);
-
- void SetAsmap(std::vector<bool> asmap) { addrman.m_asmap = std::move(asmap); }
-
-private:
- struct ListenSocket {
- public:
- SOCKET socket;
- inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); }
- ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {}
- private:
- NetPermissionFlags m_permissions;
- };
-
- bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
- bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
- bool InitBinds(
- const std::vector<CService>& binds,
- const std::vector<NetWhitebindPermissions>& whiteBinds,
- const std::vector<CService>& onion_binds);
-
- void ThreadOpenAddedConnections();
- void AddAddrFetch(const std::string& strDest);
- void ProcessAddrFetch();
- void ThreadOpenConnections(std::vector<std::string> connect);
- void ThreadMessageHandler();
- void AcceptConnection(const ListenSocket& hListenSocket);
- void DisconnectNodes();
- void NotifyNumConnectionsChanged();
- void InactivityCheck(CNode *pnode);
- bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
- void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
- void SocketHandler();
- void ThreadSocketHandler();
- void ThreadDNSAddressSeed();
-
- uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
-
- CNode* FindNode(const CNetAddr& ip);
- CNode* FindNode(const CSubNet& subNet);
- CNode* FindNode(const std::string& addrName);
- CNode* FindNode(const CService& addr);
-
- /**
- * Determine whether we're already connected to a given address, in order to
- * avoid initiating duplicate connections.
- */
- bool AlreadyConnectedToAddress(const CAddress& addr);
-
- bool AttemptToEvictConnection();
- CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
- void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
-
- void DeleteNode(CNode* pnode);
-
- NodeId GetNewNodeId();
-
- size_t SocketSendData(CNode *pnode) const;
- void DumpAddresses();
-
- // Network stats
- void RecordBytesRecv(uint64_t bytes);
- void RecordBytesSent(uint64_t bytes);
-
- /**
- * Return vector of current BLOCK_RELAY peers.
- */
- std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const;
-
- // Whether the node should be passed out in ForEach* callbacks
- static bool NodeFullyConnected(const CNode* pnode);
-
- // Network usage totals
- RecursiveMutex cs_totalBytesRecv;
- RecursiveMutex cs_totalBytesSent;
- uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0};
- uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
-
- // outbound limit & stats
- uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent) {0};
- std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent) {0};
- uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
-
- // P2P timeout in seconds
- int64_t m_peer_connect_timeout;
-
- // Whitelisted ranges. Any node connecting from these is automatically
- // whitelisted (as well as those connecting to whitelisted binds).
- std::vector<NetWhitelistPermissions> vWhitelistedRange;
-
- unsigned int nSendBufferMaxSize{0};
- unsigned int nReceiveFloodSize{0};
-
- std::vector<ListenSocket> vhListenSocket;
- std::atomic<bool> fNetworkActive{true};
- bool fAddressesInitialized{false};
- CAddrMan addrman;
- std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
- RecursiveMutex m_addr_fetches_mutex;
- std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
- RecursiveMutex cs_vAddedNodes;
- std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
- std::list<CNode*> vNodesDisconnected;
- mutable RecursiveMutex cs_vNodes;
- std::atomic<NodeId> nLastNodeId{0};
- unsigned int nPrevNodeCount{0};
-
- /**
- * Cache responses to addr requests to minimize privacy leak.
- * Attack example: scraping addrs in real-time may allow an attacker
- * to infer new connections of the victim by detecting new records
- * with fresh timestamps (per self-announcement).
- */
- struct CachedAddrResponse {
- std::vector<CAddress> m_addrs_response_cache;
- std::chrono::microseconds m_cache_entry_expiration{0};
- };
-
- /**
- * Addr responses stored in different caches
- * per (network, local socket) prevent cross-network node identification.
- * If a node for example is multi-homed under Tor and IPv6,
- * a single cache (or no cache at all) would let an attacker
- * to easily detect that it is the same node by comparing responses.
- * Indexing by local socket prevents leakage when a node has multiple
- * listening addresses on the same network.
- *
- * The used memory equals to 1000 CAddress records (or around 40 bytes) per
- * distinct Network (up to 5) we have/had an inbound peer from,
- * resulting in at most ~196 KB. Every separate local socket may
- * add up to ~196 KB extra.
- */
- std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
-
- /**
- * Services this instance offers.
- *
- * This data is replicated in each CNode instance we create during peer
- * connection (in ConnectNode()) under a member also called
- * nLocalServices.
- *
- * This data is not marked const, but after being set it should not
- * change. See the note in CNode::nLocalServices documentation.
- *
- * \sa CNode::nLocalServices
- */
- ServiceFlags nLocalServices;
-
- std::unique_ptr<CSemaphore> semOutbound;
- std::unique_ptr<CSemaphore> semAddnode;
- int nMaxConnections;
-
- // How many full-relay (tx, block, addr) outbound peers we want
- int m_max_outbound_full_relay;
-
- // How many block-relay only outbound peers we want
- // We do not relay tx or addr messages with these peers
- int m_max_outbound_block_relay;
-
- int nMaxAddnode;
- int nMaxFeeler;
- int m_max_outbound;
- bool m_use_addrman_outgoing;
- std::atomic<int> nBestHeight;
- CClientUIInterface* clientInterface;
- NetEventsInterface* m_msgproc;
- /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
- BanMan* m_banman;
-
- /**
- * Addresses that were saved during the previous clean shutdown. We'll
- * attempt to make block-relay-only connections to them.
- */
- std::vector<CAddress> m_anchors;
-
- /** SipHasher seeds for deterministic randomness */
- const uint64_t nSeed0, nSeed1;
-
- /** flag for waking the message processor. */
- bool fMsgProcWake GUARDED_BY(mutexMsgProc);
-
- std::condition_variable condMsgProc;
- Mutex mutexMsgProc;
- std::atomic<bool> flagInterruptMsgProc{false};
-
- CThreadInterrupt interruptNet;
-
- std::thread threadDNSAddressSeed;
- std::thread threadSocketHandler;
- std::thread threadOpenAddedConnections;
- std::thread threadOpenConnections;
- std::thread threadMessageHandler;
-
- /** flag for deciding to connect to an extra outbound peer,
- * in excess of m_max_outbound_full_relay
- * This takes the place of a feeler connection */
- std::atomic_bool m_try_another_outbound_peer;
-
- /** flag for initiating extra block-relay-only peer connections.
- * this should only be enabled after initial chain sync has occurred,
- * as these connections are intended to be short-lived and low-bandwidth.
- */
- std::atomic_bool m_start_extra_block_relay_peers{false};
-
- std::atomic<int64_t> m_next_send_inv_to_incoming{0};
-
- /**
- * A vector of -bind=<address>:<port>=onion arguments each of which is
- * an address and port that are designated for incoming Tor connections.
- */
- std::vector<CService> m_onion_binds;
-
- friend struct CConnmanTest;
- friend struct ConnmanTestMsg;
-};
+/** Convert ConnectionType enum to a string value */
+std::string ConnectionTypeAsString(ConnectionType conn_type);
void Discover();
-void StartMapPort();
-void InterruptMapPort();
-void StopMapPort();
uint16_t GetListenPort();
-/**
- * Interface for message handling
- */
-class NetEventsInterface
-{
-public:
- virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
- virtual bool SendMessages(CNode* pnode) = 0;
- virtual void InitializeNode(CNode* pnode) = 0;
- virtual void FinalizeNode(const CNode& node, bool& update_connection_time) = 0;
-
-protected:
- /**
- * Protected destructor so that instances can only be deleted by derived classes.
- * If that restriction is no longer desired, this should be made public and virtual.
- */
- ~NetEventsInterface() = default;
-};
-
enum
{
LOCAL_NONE, // unknown
LOCAL_IF, // address a local interface listens on
LOCAL_BIND, // address explicit bound to
- LOCAL_UPNP, // address reported by UPnP
+ LOCAL_MAPPED, // address reported by UPnP or NAT-PMP
LOCAL_MANUAL, // address explicitly specified (-externalip=)
LOCAL_MAX
@@ -702,16 +246,14 @@ public:
int nVersion;
std::string cleanSubVer;
bool fInbound;
- bool m_manual_connection;
bool m_bip152_highbandwidth_to;
bool m_bip152_highbandwidth_from;
- int nStartingHeight;
+ int m_starting_height;
uint64_t nSendBytes;
mapMsgCmdSize mapSendBytesPerMsgCmd;
uint64_t nRecvBytes;
mapMsgCmdSize mapRecvBytesPerMsgCmd;
NetPermissionFlags m_permissionFlags;
- bool m_legacyWhitelisted;
int64_t m_ping_usec;
int64_t m_ping_wait_usec;
int64_t m_min_ping_usec;
@@ -722,14 +264,13 @@ public:
CAddress addr;
// Bind address of our side of the connection
CAddress addrBind;
- // Name of the network the peer connected through
- std::string m_network;
+ // Network the peer connected through
+ Network m_network;
uint32_t m_mapped_as;
- std::string m_conn_type_string;
+ ConnectionType m_conn_type;
};
-
/** Transport protocol agnostic message container.
* Ideally it should only contain receive time, payload,
* command and size.
@@ -854,16 +395,18 @@ public:
std::unique_ptr<TransportDeserializer> m_deserializer;
std::unique_ptr<TransportSerializer> m_serializer;
- // socket
+ NetPermissionFlags m_permissionFlags{PF_NONE};
std::atomic<ServiceFlags> nServices{NODE_NONE};
SOCKET hSocket GUARDED_BY(cs_hSocket);
- size_t nSendSize{0}; // total size of all vSendMsg entries
- size_t nSendOffset{0}; // offset inside the first vSendMsg already sent
+ /** Total size of all vSendMsg entries */
+ size_t nSendSize GUARDED_BY(cs_vSend){0};
+ /** Offset inside the first vSendMsg already sent */
+ size_t nSendOffset GUARDED_BY(cs_vSend){0};
uint64_t nSendBytes GUARDED_BY(cs_vSend){0};
std::deque<std::vector<unsigned char>> vSendMsg GUARDED_BY(cs_vSend);
- RecursiveMutex cs_vSend;
- RecursiveMutex cs_hSocket;
- RecursiveMutex cs_vRecv;
+ Mutex cs_vSend;
+ Mutex cs_hSocket;
+ Mutex cs_vRecv;
RecursiveMutex cs_vProcessMsg;
std::list<CNetMessage> vProcessMsg GUARDED_BY(cs_vProcessMsg);
@@ -892,8 +435,6 @@ public:
bool HasPermission(NetPermissionFlags permission) const {
return NetPermissions::HasFlag(m_permissionFlags, permission);
}
- // This boolean is unusued in actual processing, only present for backward compatibility at RPC/QT level
- bool m_legacyWhitelisted{false};
bool fClient{false}; // set by version message
bool m_limited_node{false}; //after BIP159, set by version message
/**
@@ -988,13 +529,6 @@ public:
*/
Network ConnectedThroughNetwork() const;
-protected:
- mapMsgCmdSize mapSendBytesPerMsgCmd;
- mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
-
-public:
- uint256 hashContinue;
- std::atomic<int> nStartingHeight{-1};
// We selected peer as (compact blocks) high-bandwidth peer (BIP152)
std::atomic<bool> m_bip152_highbandwidth_to{false};
// Peer selected us as (compact blocks) high-bandwidth peer (BIP152)
@@ -1007,12 +541,6 @@ public:
std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0};
std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0};
- // List of block ids we still have announce.
- // There is no final sorting before sending, as they are always sent immediately
- // and in the order requested.
- std::vector<uint256> vInventoryBlockToSend GUARDED_BY(cs_inventory);
- Mutex cs_inventory;
-
struct TxRelay {
mutable RecursiveMutex cs_filter;
// We use fRelayTxes for two purposes -
@@ -1033,9 +561,8 @@ public:
std::atomic<std::chrono::seconds> m_last_mempool_req{0s};
std::chrono::microseconds nNextInvSend{0};
- RecursiveMutex cs_feeFilter;
- // Minimum fee rate with which to filter inv's to this node
- CAmount minFeeFilter GUARDED_BY(cs_feeFilter){0};
+ /** Minimum fee rate with which to filter inv's to this node */
+ std::atomic<CAmount> minFeeFilter{0};
CAmount lastSentFeeFilter{0};
int64_t nextSendTimeFeeFilter{0};
};
@@ -1043,9 +570,6 @@ public:
// m_tx_relay == nullptr if we're not relaying transactions with this peer
std::unique_ptr<TxRelay> m_tx_relay;
- // Used for headers announcements - unfiltered blocks to relay
- std::vector<uint256> vBlockHashesToAnnounce GUARDED_BY(cs_inventory);
-
/** UNIX epoch time of the last block received from this peer that we had
* not yet seen (e.g. not already received from another peer), that passed
* preliminary validity checks and was saved to disk, even if we don't
@@ -1071,50 +595,11 @@ public:
// Whether a ping is requested.
std::atomic<bool> fPingQueued{false};
- CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn, ConnectionType conn_type_in, bool inbound_onion = false);
+ CNode(NodeId id, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion = false);
~CNode();
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
-private:
- const NodeId id;
- const uint64_t nLocalHostNonce;
- const ConnectionType m_conn_type;
- std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
-
- //! Services offered to this peer.
- //!
- //! This is supplied by the parent CConnman during peer connection
- //! (CConnman::ConnectNode()) from its attribute of the same name.
- //!
- //! This is const because there is no protocol defined for renegotiating
- //! services initially offered to a peer. The set of local services we
- //! offer should not change after initialization.
- //!
- //! An interesting example of this is NODE_NETWORK and initial block
- //! download: a node which starts up from scratch doesn't have any blocks
- //! to serve, but still advertises NODE_NETWORK because it will eventually
- //! fulfill this role after IBD completes. P2P code is written in such a
- //! way that it can gracefully handle peers who don't make good on their
- //! service advertisements.
- const ServiceFlags nLocalServices;
-
- const int nMyStartingHeight;
- NetPermissionFlags m_permissionFlags{ PF_NONE };
- std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
-
- mutable RecursiveMutex cs_addrName;
- std::string addrName GUARDED_BY(cs_addrName);
-
- // Our address, as reported by the peer
- CService addrLocal GUARDED_BY(cs_addrLocal);
- mutable RecursiveMutex cs_addrLocal;
-
- //! Whether this peer connected via our Tor onion service.
- const bool m_inbound_onion{false};
-
-public:
-
NodeId GetId() const {
return id;
}
@@ -1123,10 +608,6 @@ public:
return nLocalHostNonce;
}
- int GetMyStartingHeight() const {
- return nMyStartingHeight;
- }
-
int GetRefCount() const
{
assert(nRefCount >= 0);
@@ -1169,8 +650,6 @@ public:
nRefCount--;
}
-
-
void AddAddressKnown(const CAddress& _addr)
{
assert(m_addr_known);
@@ -1202,7 +681,6 @@ public:
}
}
-
void AddKnownTx(const uint256& hash)
{
if (m_tx_relay != nullptr) {
@@ -1233,7 +711,525 @@ public:
//! Sets the addrName only if it was not previously set
void MaybeSetAddrName(const std::string& addrNameIn);
- std::string ConnectionTypeAsString() const;
+ std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
+
+ /** Whether this peer is an inbound onion, e.g. connected via our Tor onion service. */
+ bool IsInboundOnion() const { return m_inbound_onion; }
+
+private:
+ const NodeId id;
+ const uint64_t nLocalHostNonce;
+ const ConnectionType m_conn_type;
+ std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
+
+ //! Services offered to this peer.
+ //!
+ //! This is supplied by the parent CConnman during peer connection
+ //! (CConnman::ConnectNode()) from its attribute of the same name.
+ //!
+ //! This is const because there is no protocol defined for renegotiating
+ //! services initially offered to a peer. The set of local services we
+ //! offer should not change after initialization.
+ //!
+ //! An interesting example of this is NODE_NETWORK and initial block
+ //! download: a node which starts up from scratch doesn't have any blocks
+ //! to serve, but still advertises NODE_NETWORK because it will eventually
+ //! fulfill this role after IBD completes. P2P code is written in such a
+ //! way that it can gracefully handle peers who don't make good on their
+ //! service advertisements.
+ const ServiceFlags nLocalServices;
+
+ std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
+
+ mutable RecursiveMutex cs_addrName;
+ std::string addrName GUARDED_BY(cs_addrName);
+
+ // Our address, as reported by the peer
+ CService addrLocal GUARDED_BY(cs_addrLocal);
+ mutable RecursiveMutex cs_addrLocal;
+
+ //! Whether this peer is an inbound onion, e.g. connected via our Tor onion service.
+ const bool m_inbound_onion{false};
+
+ mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend);
+ mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
+};
+
+/**
+ * Interface for message handling
+ */
+class NetEventsInterface
+{
+public:
+ /** Initialize a peer (setup state, queue any initial messages) */
+ virtual void InitializeNode(CNode* pnode) = 0;
+
+ /** Handle removal of a peer (clear state) */
+ virtual void FinalizeNode(const CNode& node, bool& update_connection_time) = 0;
+
+ /**
+ * Process protocol messages received from a given node
+ *
+ * @param[in] pnode The node which we have received messages from.
+ * @param[in] interrupt Interrupt condition for processing threads
+ * @return True if there is more work to be done
+ */
+ virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
+
+ /**
+ * Send queued protocol messages to a given node.
+ *
+ * @param[in] pnode The node which we are sending messages to.
+ * @return True if there is more work to be done
+ */
+ virtual bool SendMessages(CNode* pnode) EXCLUSIVE_LOCKS_REQUIRED(pnode->cs_sendProcessing) = 0;
+
+
+protected:
+ /**
+ * Protected destructor so that instances can only be deleted by derived classes.
+ * If that restriction is no longer desired, this should be made public and virtual.
+ */
+ ~NetEventsInterface() = default;
+};
+
+class CConnman
+{
+public:
+
+ enum NumConnections {
+ CONNECTIONS_NONE = 0,
+ CONNECTIONS_IN = (1U << 0),
+ CONNECTIONS_OUT = (1U << 1),
+ CONNECTIONS_ALL = (CONNECTIONS_IN | CONNECTIONS_OUT),
+ };
+
+ struct Options
+ {
+ ServiceFlags nLocalServices = NODE_NONE;
+ int nMaxConnections = 0;
+ int m_max_outbound_full_relay = 0;
+ int m_max_outbound_block_relay = 0;
+ int nMaxAddnode = 0;
+ int nMaxFeeler = 0;
+ CClientUIInterface* uiInterface = nullptr;
+ NetEventsInterface* m_msgproc = nullptr;
+ BanMan* m_banman = nullptr;
+ unsigned int nSendBufferMaxSize = 0;
+ unsigned int nReceiveFloodSize = 0;
+ uint64_t nMaxOutboundLimit = 0;
+ int64_t m_peer_connect_timeout = DEFAULT_PEER_CONNECT_TIMEOUT;
+ std::vector<std::string> vSeedNodes;
+ std::vector<NetWhitelistPermissions> vWhitelistedRange;
+ std::vector<NetWhitebindPermissions> vWhiteBinds;
+ std::vector<CService> vBinds;
+ std::vector<CService> onion_binds;
+ bool m_use_addrman_outgoing = true;
+ std::vector<std::string> m_specified_outgoing;
+ std::vector<std::string> m_added_nodes;
+ std::vector<bool> m_asmap;
+ };
+
+ void Init(const Options& connOptions) {
+ nLocalServices = connOptions.nLocalServices;
+ nMaxConnections = connOptions.nMaxConnections;
+ m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
+ m_max_outbound_block_relay = connOptions.m_max_outbound_block_relay;
+ m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing;
+ nMaxAddnode = connOptions.nMaxAddnode;
+ nMaxFeeler = connOptions.nMaxFeeler;
+ m_max_outbound = m_max_outbound_full_relay + m_max_outbound_block_relay + nMaxFeeler;
+ clientInterface = connOptions.uiInterface;
+ m_banman = connOptions.m_banman;
+ m_msgproc = connOptions.m_msgproc;
+ nSendBufferMaxSize = connOptions.nSendBufferMaxSize;
+ nReceiveFloodSize = connOptions.nReceiveFloodSize;
+ m_peer_connect_timeout = connOptions.m_peer_connect_timeout;
+ {
+ LOCK(cs_totalBytesSent);
+ nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
+ }
+ vWhitelistedRange = connOptions.vWhitelistedRange;
+ {
+ LOCK(cs_vAddedNodes);
+ vAddedNodes = connOptions.m_added_nodes;
+ }
+ m_onion_binds = connOptions.onion_binds;
+ }
+
+ CConnman(uint64_t seed0, uint64_t seed1, bool network_active = true);
+ ~CConnman();
+ bool Start(CScheduler& scheduler, const Options& options);
+
+ void StopThreads();
+ void StopNodes();
+ void Stop()
+ {
+ StopThreads();
+ StopNodes();
+ };
+
+ void Interrupt();
+ bool GetNetworkActive() const { return fNetworkActive; };
+ bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
+ void SetNetworkActive(bool active);
+ void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant* grantOutbound, const char* strDest, ConnectionType conn_type);
+ bool CheckIncomingNonce(uint64_t nonce);
+
+ bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
+
+ void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
+
+ using NodeFn = std::function<void(CNode*)>;
+ void ForEachNode(const NodeFn& func)
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ func(node);
+ }
+ };
+
+ void ForEachNode(const NodeFn& func) const
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ func(node);
+ }
+ };
+
+ template<typename Callable, typename CallableAfter>
+ void ForEachNodeThen(Callable&& pre, CallableAfter&& post)
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ pre(node);
+ }
+ post();
+ };
+
+ template<typename Callable, typename CallableAfter>
+ void ForEachNodeThen(Callable&& pre, CallableAfter&& post) const
+ {
+ LOCK(cs_vNodes);
+ for (auto&& node : vNodes) {
+ if (NodeFullyConnected(node))
+ pre(node);
+ }
+ post();
+ };
+
+ // Addrman functions
+ void SetServices(const CService &addr, ServiceFlags nServices);
+ void MarkAddressGood(const CAddress& addr);
+ bool AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
+ std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct);
+ /**
+ * Cache is used to minimize topology leaks, so it should
+ * be used for all non-trusted calls, for example, p2p.
+ * A non-malicious call (from RPC or a peer with addr permission) should
+ * call the function without a parameter to avoid using the cache.
+ */
+ std::vector<CAddress> GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct);
+
+ // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
+ // a peer that is better than all our current peers.
+ void SetTryNewOutboundPeer(bool flag);
+ bool GetTryNewOutboundPeer();
+
+ void StartExtraBlockRelayPeers() {
+ LogPrint(BCLog::NET, "net: enabling extra block-relay-only peers\n");
+ m_start_extra_block_relay_peers = true;
+ }
+
+ // 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 GetExtraFullOutboundCount();
+ // Count the number of block-relay-only peers we have over our limit.
+ int GetExtraBlockRelayCount();
+
+ bool AddNode(const std::string& node);
+ bool RemoveAddedNode(const std::string& node);
+ std::vector<AddedNodeInfo> GetAddedNodeInfo();
+
+ /**
+ * Attempts to open a connection. Currently only used from tests.
+ *
+ * @param[in] address Address of node to try connecting to
+ * @param[in] conn_type ConnectionType::OUTBOUND or ConnectionType::BLOCK_RELAY
+ * @return bool Returns false if there are no available
+ * slots for this connection:
+ * - conn_type not a supported ConnectionType
+ * - Max total outbound connection capacity filled
+ * - Max connection capacity for type is filled
+ */
+ bool AddConnection(const std::string& address, ConnectionType conn_type);
+
+ size_t GetNodeCount(NumConnections num);
+ void GetNodeStats(std::vector<CNodeStats>& vstats);
+ bool DisconnectNode(const std::string& node);
+ bool DisconnectNode(const CSubNet& subnet);
+ bool DisconnectNode(const CNetAddr& addr);
+ bool DisconnectNode(NodeId id);
+
+ //! Used to convey which local services we are offering peers during node
+ //! connection.
+ //!
+ //! The data returned by this is used in CNode construction,
+ //! which is used to advertise which services we are offering
+ //! that peer during `net_processing.cpp:PushNodeVersion()`.
+ ServiceFlags GetLocalServices() const;
+
+ uint64_t GetMaxOutboundTarget();
+ std::chrono::seconds GetMaxOutboundTimeframe();
+
+ //! check if the outbound target is reached
+ //! if param historicalBlockServingLimit is set true, the function will
+ //! response true if the limit for serving historical blocks has been reached
+ bool OutboundTargetReached(bool historicalBlockServingLimit);
+
+ //! response the bytes left in the current max outbound cycle
+ //! in case of no limit, it will always response 0
+ uint64_t GetOutboundTargetBytesLeft();
+
+ //! returns the time left in the current max outbound cycle
+ //! in case of no limit, it will always return 0
+ std::chrono::seconds GetMaxOutboundTimeLeftInCycle();
+
+ uint64_t GetTotalBytesRecv();
+ uint64_t GetTotalBytesSent();
+
+ /** Get a unique deterministic randomizer. */
+ CSipHasher GetDeterministicRandomizer(uint64_t id) const;
+
+ unsigned int GetReceiveFloodSize() const;
+
+ void WakeMessageHandler();
+
+ /** Attempts to obfuscate tx time through exponentially distributed emitting.
+ Works assuming that a single interval is used.
+ Variable intervals will result in privacy decrease.
+ */
+ int64_t PoissonNextSendInbound(int64_t now, int average_interval_seconds);
+
+ void SetAsmap(std::vector<bool> asmap) { addrman.m_asmap = std::move(asmap); }
+
+private:
+ struct ListenSocket {
+ public:
+ SOCKET socket;
+ inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); }
+ ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {}
+ private:
+ NetPermissionFlags m_permissions;
+ };
+
+ bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
+ bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
+ bool InitBinds(
+ const std::vector<CService>& binds,
+ const std::vector<NetWhitebindPermissions>& whiteBinds,
+ const std::vector<CService>& onion_binds);
+
+ void ThreadOpenAddedConnections();
+ void AddAddrFetch(const std::string& strDest);
+ void ProcessAddrFetch();
+ void ThreadOpenConnections(std::vector<std::string> connect);
+ void ThreadMessageHandler();
+ void AcceptConnection(const ListenSocket& hListenSocket);
+ void DisconnectNodes();
+ void NotifyNumConnectionsChanged();
+ /** Return true if the peer is inactive and should be disconnected. */
+ bool InactivityCheck(const CNode& node) const;
+ bool GenerateSelectSet(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
+ void SocketEvents(std::set<SOCKET> &recv_set, std::set<SOCKET> &send_set, std::set<SOCKET> &error_set);
+ void SocketHandler();
+ void ThreadSocketHandler();
+ void ThreadDNSAddressSeed();
+
+ uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
+
+ CNode* FindNode(const CNetAddr& ip);
+ CNode* FindNode(const CSubNet& subNet);
+ CNode* FindNode(const std::string& addrName);
+ CNode* FindNode(const CService& addr);
+
+ /**
+ * Determine whether we're already connected to a given address, in order to
+ * avoid initiating duplicate connections.
+ */
+ bool AlreadyConnectedToAddress(const CAddress& addr);
+
+ bool AttemptToEvictConnection();
+ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
+ void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
+
+ void DeleteNode(CNode* pnode);
+
+ NodeId GetNewNodeId();
+
+ size_t SocketSendData(CNode& node) const EXCLUSIVE_LOCKS_REQUIRED(node.cs_vSend);
+ void DumpAddresses();
+
+ // Network stats
+ void RecordBytesRecv(uint64_t bytes);
+ void RecordBytesSent(uint64_t bytes);
+
+ /**
+ * Return vector of current BLOCK_RELAY peers.
+ */
+ std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const;
+
+ // Whether the node should be passed out in ForEach* callbacks
+ static bool NodeFullyConnected(const CNode* pnode);
+
+ // Network usage totals
+ RecursiveMutex cs_totalBytesRecv;
+ RecursiveMutex cs_totalBytesSent;
+ uint64_t nTotalBytesRecv GUARDED_BY(cs_totalBytesRecv) {0};
+ uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
+
+ // outbound limit & stats
+ uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent) {0};
+ std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent) {0};
+ uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
+
+ // P2P timeout in seconds
+ int64_t m_peer_connect_timeout;
+
+ // Whitelisted ranges. Any node connecting from these is automatically
+ // whitelisted (as well as those connecting to whitelisted binds).
+ std::vector<NetWhitelistPermissions> vWhitelistedRange;
+
+ unsigned int nSendBufferMaxSize{0};
+ unsigned int nReceiveFloodSize{0};
+
+ std::vector<ListenSocket> vhListenSocket;
+ std::atomic<bool> fNetworkActive{true};
+ bool fAddressesInitialized{false};
+ CAddrMan addrman;
+ std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
+ RecursiveMutex m_addr_fetches_mutex;
+ std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
+ RecursiveMutex cs_vAddedNodes;
+ std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
+ std::list<CNode*> vNodesDisconnected;
+ mutable RecursiveMutex cs_vNodes;
+ std::atomic<NodeId> nLastNodeId{0};
+ unsigned int nPrevNodeCount{0};
+
+ /**
+ * Cache responses to addr requests to minimize privacy leak.
+ * Attack example: scraping addrs in real-time may allow an attacker
+ * to infer new connections of the victim by detecting new records
+ * with fresh timestamps (per self-announcement).
+ */
+ struct CachedAddrResponse {
+ std::vector<CAddress> m_addrs_response_cache;
+ std::chrono::microseconds m_cache_entry_expiration{0};
+ };
+
+ /**
+ * Addr responses stored in different caches
+ * per (network, local socket) prevent cross-network node identification.
+ * If a node for example is multi-homed under Tor and IPv6,
+ * a single cache (or no cache at all) would let an attacker
+ * to easily detect that it is the same node by comparing responses.
+ * Indexing by local socket prevents leakage when a node has multiple
+ * listening addresses on the same network.
+ *
+ * The used memory equals to 1000 CAddress records (or around 40 bytes) per
+ * distinct Network (up to 5) we have/had an inbound peer from,
+ * resulting in at most ~196 KB. Every separate local socket may
+ * add up to ~196 KB extra.
+ */
+ std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
+
+ /**
+ * Services this instance offers.
+ *
+ * This data is replicated in each CNode instance we create during peer
+ * connection (in ConnectNode()) under a member also called
+ * nLocalServices.
+ *
+ * This data is not marked const, but after being set it should not
+ * change. See the note in CNode::nLocalServices documentation.
+ *
+ * \sa CNode::nLocalServices
+ */
+ ServiceFlags nLocalServices;
+
+ std::unique_ptr<CSemaphore> semOutbound;
+ std::unique_ptr<CSemaphore> semAddnode;
+ int nMaxConnections;
+
+ // How many full-relay (tx, block, addr) outbound peers we want
+ int m_max_outbound_full_relay;
+
+ // How many block-relay only outbound peers we want
+ // We do not relay tx or addr messages with these peers
+ int m_max_outbound_block_relay;
+
+ int nMaxAddnode;
+ int nMaxFeeler;
+ int m_max_outbound;
+ bool m_use_addrman_outgoing;
+ CClientUIInterface* clientInterface;
+ NetEventsInterface* m_msgproc;
+ /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
+ BanMan* m_banman;
+
+ /**
+ * Addresses that were saved during the previous clean shutdown. We'll
+ * attempt to make block-relay-only connections to them.
+ */
+ std::vector<CAddress> m_anchors;
+
+ /** SipHasher seeds for deterministic randomness */
+ const uint64_t nSeed0, nSeed1;
+
+ /** flag for waking the message processor. */
+ bool fMsgProcWake GUARDED_BY(mutexMsgProc);
+
+ std::condition_variable condMsgProc;
+ Mutex mutexMsgProc;
+ std::atomic<bool> flagInterruptMsgProc{false};
+
+ CThreadInterrupt interruptNet;
+
+ std::thread threadDNSAddressSeed;
+ std::thread threadSocketHandler;
+ std::thread threadOpenAddedConnections;
+ std::thread threadOpenConnections;
+ std::thread threadMessageHandler;
+
+ /** flag for deciding to connect to an extra outbound peer,
+ * in excess of m_max_outbound_full_relay
+ * This takes the place of a feeler connection */
+ std::atomic_bool m_try_another_outbound_peer;
+
+ /** flag for initiating extra block-relay-only peer connections.
+ * this should only be enabled after initial chain sync has occurred,
+ * as these connections are intended to be short-lived and low-bandwidth.
+ */
+ std::atomic_bool m_start_extra_block_relay_peers{false};
+
+ std::atomic<int64_t> m_next_send_inv_to_incoming{0};
+
+ /**
+ * A vector of -bind=<address>:<port>=onion arguments each of which is
+ * an address and port that are designated for incoming Tor connections.
+ */
+ std::vector<CService> m_onion_binds;
+
+ friend struct CConnmanTest;
+ friend struct ConnmanTestMsg;
};
/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */
diff --git a/src/net_permissions.cpp b/src/net_permissions.cpp
index d40fdfb113..1fdcd97593 100644
--- a/src/net_permissions.cpp
+++ b/src/net_permissions.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 17aa889ab0..a4070f5b63 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -26,6 +26,7 @@
#include <streams.h>
#include <tinyformat.h>
#include <txmempool.h>
+#include <txrequest.h>
#include <util/check.h> // For NDEBUG compile time check
#include <util/strencodings.h>
#include <util/system.h>
@@ -168,6 +169,186 @@ void EraseOrphansFor(NodeId peer);
// Internal stuff
namespace {
+/**
+ * Data structure for an individual peer. This struct is not protected by
+ * cs_main since it does not contain validation-critical data.
+ *
+ * Memory is owned by shared pointers and this object is destructed when
+ * the refcount drops to zero.
+ *
+ * Mutexes inside this struct must not be held when locking m_peer_mutex.
+ *
+ * TODO: move most members from CNodeState to this structure.
+ * TODO: move remaining application-layer data members from CNode to this structure.
+ */
+struct Peer {
+ /** Same id as the CNode object for this peer */
+ const NodeId m_id{0};
+
+ /** Protects misbehavior data members */
+ Mutex m_misbehavior_mutex;
+ /** Accumulated misbehavior score for this peer */
+ int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0};
+ /** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
+ bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
+
+ /** Protects block inventory data members */
+ Mutex m_block_inv_mutex;
+ /** List of blocks that we'll announce via an `inv` message.
+ * There is no final sorting before sending, as they are always sent
+ * immediately and in the order requested. */
+ std::vector<uint256> m_blocks_for_inv_relay GUARDED_BY(m_block_inv_mutex);
+ /** Unfiltered list of blocks that we'd like to announce via a `headers`
+ * message. If we can't announce via a `headers` message, we'll fall back to
+ * announcing via `inv`. */
+ std::vector<uint256> m_blocks_for_headers_relay GUARDED_BY(m_block_inv_mutex);
+ /** The final block hash that we sent in an `inv` message to this peer.
+ * When the peer requests this block, we send an `inv` message to trigger
+ * the peer to request the next sequence of block hashes.
+ * Most peers use headers-first syncing, which doesn't use this mechanism */
+ uint256 m_continuation_block GUARDED_BY(m_block_inv_mutex) {};
+
+ /** This peer's reported block height when we connected */
+ std::atomic<int> m_starting_height{-1};
+
+ /** Set of txids to reconsider once their parent transactions have been accepted **/
+ std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
+
+ /** Protects m_getdata_requests **/
+ Mutex m_getdata_requests_mutex;
+ /** Work queue of items requested by this peer **/
+ std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
+
+ explicit Peer(NodeId id) : m_id(id) {}
+};
+
+using PeerRef = std::shared_ptr<Peer>;
+
+class PeerManagerImpl final : public PeerManager
+{
+public:
+ PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
+ CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
+ bool ignore_incoming_txs);
+
+ /** Overridden from CValidationInterface. */
+ void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override;
+ void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override;
+ void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
+ void BlockChecked(const CBlock& block, const BlockValidationState& state) override;
+ void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override;
+
+ /** Implement NetEventsInterface */
+ void InitializeNode(CNode* pnode) override;
+ void FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) override;
+ bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
+ bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
+
+ /** Implement PeerManager */
+ void CheckForStaleTipAndEvictPeers() override;
+ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) override;
+ bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
+ void SetBestHeight(int height) override { m_best_height = height; };
+ void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) override;
+ void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
+ const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override;
+
+private:
+ /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
+ void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */
+ void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ /** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */
+ void ReattemptInitialBroadcast(CScheduler& scheduler) const;
+
+ /** Get a shared pointer to the Peer object.
+ * May return an empty shared_ptr if the Peer object can't be found. */
+ PeerRef GetPeerRef(NodeId id) const;
+
+ /** Get a shared pointer to the Peer object and remove it from m_peer_map.
+ * May return an empty shared_ptr if the Peer object can't be found. */
+ PeerRef RemovePeer(NodeId id);
+
+ /**
+ * Potentially mark a node discouraged based on the contents of a BlockValidationState object
+ *
+ * @param[in] via_compact_block this bool is passed in because net_processing should
+ * punish peers differently depending on whether the data was provided in a compact
+ * block message or not. If the compact block had a valid header, but contained invalid
+ * txs, the peer should not be punished. See BIP 152.
+ *
+ * @return Returns true if the peer was punished (probably disconnected)
+ */
+ bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
+ bool via_compact_block, const std::string& message = "");
+
+ /**
+ * Potentially disconnect and discourage a node based on the contents of a TxValidationState object
+ *
+ * @return Returns true if the peer was punished (probably disconnected)
+ */
+ bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "");
+
+ /** Maybe disconnect a peer and discourage future connections from its address.
+ *
+ * @param[in] pnode The node to check.
+ * @return True if the peer was marked for disconnection in this function
+ */
+ bool MaybeDiscourageAndDisconnect(CNode& pnode);
+
+ void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans);
+ /** Process a single headers message from a peer. */
+ void ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
+ const std::vector<CBlockHeader>& headers,
+ bool via_compact_block);
+
+ void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req);
+
+ /** Register with TxRequestTracker that an INV has been received from a
+ * peer. The announcement parameters are decided in PeerManager and then
+ * passed to TxRequestTracker. */
+ void AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
+ /** Send a version message to a peer */
+ void PushNodeVersion(CNode& pnode, int64_t nTime);
+
+ const CChainParams& m_chainparams;
+ CConnman& m_connman;
+ /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
+ BanMan* const m_banman;
+ ChainstateManager& m_chainman;
+ CTxMemPool& m_mempool;
+ TxRequestTracker m_txrequest GUARDED_BY(::cs_main);
+
+ /** The height of the best chain */
+ std::atomic<int> m_best_height{-1};
+
+ int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
+
+ /** Whether this node is running in blocks only mode */
+ const bool m_ignore_incoming_txs;
+
+ /** Whether we've completed initial sync yet, for determining when to turn
+ * on extra block-relay-only peers. */
+ bool m_initial_sync_finished{false};
+
+ /** Protects m_peer_map. This mutex must not be locked while holding a lock
+ * on any of the mutexes inside a Peer object. */
+ mutable Mutex m_peer_mutex;
+ /**
+ * Map of all Peer objects, keyed by peer id. This map is protected
+ * by the m_peer_mutex. Once a shared pointer reference is
+ * taken, the lock may be released. Individual fields are protected by
+ * their own locks.
+ */
+ std::map<NodeId, PeerRef> m_peer_map GUARDED_BY(m_peer_mutex);
+};
+} // namespace
+
+namespace {
/** Number of nodes with fSyncStarted. */
int nSyncStarted GUARDED_BY(cs_main) = 0;
@@ -683,14 +864,14 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
} // namespace
-void PeerManager::PushNodeVersion(CNode& pnode, int64_t nTime)
+void PeerManagerImpl::PushNodeVersion(CNode& pnode, int64_t nTime)
{
// Note that pnode->GetLocalServices() is a reflection of the local
// services we were offering when the CNode object was created for this
// peer.
ServiceFlags nLocalNodeServices = pnode.GetLocalServices();
uint64_t nonce = pnode.GetLocalNonce();
- int nNodeStartingHeight = pnode.GetMyStartingHeight();
+ const int nNodeStartingHeight{m_best_height};
NodeId nodeid = pnode.GetId();
CAddress addr = pnode.addr;
@@ -699,17 +880,18 @@ void PeerManager::PushNodeVersion(CNode& pnode, int64_t nTime)
CAddress(CService(), addr.nServices);
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
+ const bool tx_relay = !m_ignore_incoming_txs && pnode.m_tx_relay != nullptr;
m_connman.PushMessage(&pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
- nonce, strSubVersion, nNodeStartingHeight, !m_ignore_incoming_txs && pnode.m_tx_relay != nullptr));
+ nonce, strSubVersion, nNodeStartingHeight, tx_relay));
if (fLogIPs) {
- LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
+ LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), tx_relay, nodeid);
} else {
- LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid);
+ LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), tx_relay, nodeid);
}
}
-void PeerManager::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time)
+void PeerManagerImpl::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time)
{
AssertLockHeld(::cs_main); // For m_txrequest
NodeId nodeid = node.GetId();
@@ -745,7 +927,8 @@ void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
if (state) state->m_last_block_announcement = time_in_seconds;
}
-void PeerManager::InitializeNode(CNode *pnode) {
+void PeerManagerImpl::InitializeNode(CNode *pnode)
+{
CAddress addr = pnode->addr;
std::string addrName = pnode->GetAddrName();
NodeId nodeid = pnode->GetId();
@@ -764,7 +947,7 @@ void PeerManager::InitializeNode(CNode *pnode) {
}
}
-void PeerManager::ReattemptInitialBroadcast(CScheduler& scheduler) const
+void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) const
{
std::set<uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();
@@ -785,12 +968,18 @@ void PeerManager::ReattemptInitialBroadcast(CScheduler& scheduler) const
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
}
-void PeerManager::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) {
+void PeerManagerImpl::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime)
+{
NodeId nodeid = node.GetId();
fUpdateConnectionTime = false;
LOCK(cs_main);
int misbehavior{0};
{
+ // We remove the PeerRef from g_peer_map here, but we don't always
+ // destruct the Peer. Sometimes another thread is still holding a
+ // PeerRef, so the refcount is >= 1. Be careful not to do any
+ // processing here that assumes Peer won't be changed before it's
+ // destructed.
PeerRef peer = RemovePeer(nodeid);
assert(peer != nullptr);
misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
@@ -834,14 +1023,14 @@ void PeerManager::FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) {
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
}
-PeerRef PeerManager::GetPeerRef(NodeId id) const
+PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const
{
LOCK(m_peer_mutex);
auto it = m_peer_map.find(id);
return it != m_peer_map.end() ? it->second : nullptr;
}
-PeerRef PeerManager::RemovePeer(NodeId id)
+PeerRef PeerManagerImpl::RemovePeer(NodeId id)
{
PeerRef ret;
LOCK(m_peer_mutex);
@@ -853,7 +1042,8 @@ PeerRef PeerManager::RemovePeer(NodeId id)
return ret;
}
-bool PeerManager::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
+bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats)
+{
{
LOCK(cs_main);
CNodeState* state = State(nodeid);
@@ -869,7 +1059,7 @@ bool PeerManager::GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
PeerRef peer = GetPeerRef(nodeid);
if (peer == nullptr) return false;
- stats.m_misbehavior_score = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_misbehavior_score);
+ stats.m_starting_height = peer->m_starting_height;
return true;
}
@@ -1010,7 +1200,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
return nEvicted;
}
-void PeerManager::Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
+void PeerManagerImpl::Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
{
assert(howmuch > 0);
@@ -1028,8 +1218,8 @@ void PeerManager::Misbehaving(const NodeId pnode, const int howmuch, const std::
}
}
-bool PeerManager::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
- bool via_compact_block, const std::string& message)
+bool PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
+ bool via_compact_block, const std::string& message)
{
switch (state.GetResult()) {
case BlockValidationResult::BLOCK_RESULT_UNSET:
@@ -1078,7 +1268,7 @@ bool PeerManager::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationSt
return false;
}
-bool PeerManager::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
+bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message)
{
switch (state.GetResult()) {
case TxValidationResult::TX_RESULT_UNSET:
@@ -1124,9 +1314,16 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
}
-PeerManager::PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
- CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
- bool ignore_incoming_txs)
+std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
+ CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
+ bool ignore_incoming_txs)
+{
+ return std::make_unique<PeerManagerImpl>(chainparams, connman, banman, scheduler, chainman, pool, ignore_incoming_txs);
+}
+
+PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
+ CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
+ bool ignore_incoming_txs)
: m_chainparams(chainparams),
m_connman(connman),
m_banman(banman),
@@ -1166,7 +1363,7 @@ PeerManager::PeerManager(const CChainParams& chainparams, CConnman& connman, Ban
* block, remember the recently confirmed transactions, and delete tracked
* announcements for them. Also save the time of the last tip update.
*/
-void PeerManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
+void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
{
{
LOCK(g_cs_orphans);
@@ -1217,7 +1414,7 @@ void PeerManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock, co
}
}
-void PeerManager::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)
+void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)
{
// To avoid relay problems with transactions that were previously
// confirmed, clear our filter of recently confirmed transactions whenever
@@ -1242,7 +1439,8 @@ static bool fWitnessesPresentInMostRecentCompactBlock GUARDED_BY(cs_most_recent_
* Maintain state about the best-seen block and fast-announce a compact block
* to compatible peers.
*/
-void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) {
+void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock)
+{
std::shared_ptr<const CBlockHeaderAndShortTxIDs> pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs> (*pblock, true);
const CNetMsgMaker msgMaker(PROTOCOL_VERSION);
@@ -1289,8 +1487,9 @@ void PeerManager::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_
* Update our best height and announce any block hashes which weren't previously
* in ::ChainActive() to our peers.
*/
-void PeerManager::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
- m_connman.SetBestHeight(pindexNew->nHeight);
+void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
+{
+ SetBestHeight(pindexNew->nHeight);
SetServiceFlagsIBDCache(!fInitialDownload);
// Don't relay inventory during initial block download.
@@ -1309,13 +1508,17 @@ void PeerManager::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInde
}
}
- // Relay to all peers
- m_connman.ForEachNode([&vHashes](CNode* pnode) {
- LOCK(pnode->cs_inventory);
- for (const uint256& hash : reverse_iterate(vHashes)) {
- pnode->vBlockHashesToAnnounce.push_back(hash);
+ {
+ LOCK(m_peer_mutex);
+ for (auto& it : m_peer_map) {
+ Peer& peer = *it.second;
+ LOCK(peer.m_block_inv_mutex);
+ for (const uint256& hash : reverse_iterate(vHashes)) {
+ peer.m_blocks_for_headers_relay.push_back(hash);
+ }
}
- });
+ }
+
m_connman.WakeMessageHandler();
}
@@ -1323,7 +1526,8 @@ void PeerManager::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInde
* Handle invalid block rejection and consequent peer discouragement, maintain which
* peers announce compact blocks.
*/
-void PeerManager::BlockChecked(const CBlock& block, const BlockValidationState& state) {
+void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationState& state)
+{
LOCK(cs_main);
const uint256 hash(block.GetHash());
@@ -1465,7 +1669,7 @@ static void RelayAddress(const CNode& originator,
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
-void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
+void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
{
bool send = false;
std::shared_ptr<const CBlock> a_recent_block;
@@ -1605,16 +1809,18 @@ void static ProcessGetBlockData(CNode& pfrom, const CChainParams& chainparams, c
}
}
- // Trigger the peer node to send a getblocks request for the next batch of inventory
- if (inv.hash == pfrom.hashContinue)
{
- // Send immediately. This must send even if redundant,
- // and we want it right after the last block so they don't
- // wait for other stuff first.
- std::vector<CInv> vInv;
- vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash()));
- connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
- pfrom.hashContinue.SetNull();
+ LOCK(peer.m_block_inv_mutex);
+ // Trigger the peer node to send a getblocks request for the next batch of inventory
+ if (inv.hash == peer.m_continuation_block) {
+ // Send immediately. This must send even if redundant,
+ // and we want it right after the last block so they don't
+ // wait for other stuff first.
+ std::vector<CInv> vInv;
+ vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash()));
+ connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
+ peer.m_continuation_block.SetNull();
+ }
}
}
}
@@ -1714,7 +1920,7 @@ void static ProcessGetData(CNode& pfrom, Peer& peer, const CChainParams& chainpa
if (it != peer.m_getdata_requests.end() && !pfrom.fPauseSend) {
const CInv &inv = *it++;
if (inv.IsGenBlkMsg()) {
- ProcessGetBlockData(pfrom, chainparams, inv, connman);
+ ProcessGetBlockData(pfrom, peer, chainparams, inv, connman);
}
// else: If the first item on the queue is an unknown type, we erase it
// and continue processing the queue on the next call.
@@ -1749,7 +1955,8 @@ static uint32_t GetFetchFlags(const CNode& pfrom) EXCLUSIVE_LOCKS_REQUIRED(cs_ma
return nFetchFlags;
}
-void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req) {
+void PeerManagerImpl::SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req)
+{
BlockTransactions resp(req);
for (size_t i = 0; i < req.indexes.size(); i++) {
if (req.indexes[i] >= block.vtx.size()) {
@@ -1764,7 +1971,9 @@ void PeerManager::SendBlockTransactions(CNode& pfrom, const CBlock& block, const
m_connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
-void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block)
+void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
+ const std::vector<CBlockHeader>& headers,
+ bool via_compact_block)
{
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
size_t nCount = headers.size();
@@ -1854,7 +2063,8 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe
// 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);
+ LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
+ pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256()));
}
@@ -1955,7 +2165,7 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe
* may be added to if accepting an orphan causes its children to be
* reconsidered.
*/
-void PeerManager::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
+void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
{
AssertLockHeld(cs_main);
AssertLockHeld(g_cs_orphans);
@@ -2252,16 +2462,11 @@ static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainPar
connman.PushMessage(&peer, std::move(msg));
}
-void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
- const std::chrono::microseconds time_received,
- const std::atomic<bool>& interruptMsgProc)
+void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
+ const std::chrono::microseconds time_received,
+ const std::atomic<bool>& interruptMsgProc)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom.GetId());
- if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
- {
- LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
- return;
- }
PeerRef peer = GetPeerRef(pfrom.GetId());
if (peer == nullptr) return;
@@ -2280,7 +2485,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
ServiceFlags nServices;
int nVersion;
std::string cleanSubVer;
- int nStartingHeight = -1;
+ int starting_height = -1;
bool fRelay = true;
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
@@ -2311,7 +2516,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
cleanSubVer = SanitizeString(strSubVer);
}
if (!vRecv.empty()) {
- vRecv >> nStartingHeight;
+ vRecv >> starting_height;
}
if (!vRecv.empty())
vRecv >> fRelay;
@@ -2360,7 +2565,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
LOCK(pfrom.cs_SubVer);
pfrom.cleanSubVer = cleanSubVer;
}
- pfrom.nStartingHeight = nStartingHeight;
+ peer->m_starting_height = starting_height;
// set nodes not relaying blocks and tx and not serving (parts) of the historical blockchain as "clients"
pfrom.fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED));
@@ -2438,9 +2643,9 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (fLogIPs)
remoteAddr = ", peeraddr=" + pfrom.addr.ToString();
- LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n",
+ LogPrint(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s\n",
cleanSubVer, pfrom.nVersion,
- pfrom.nStartingHeight, addrMe.ToString(), pfrom.GetId(),
+ peer->m_starting_height, addrMe.ToString(), fRelay, pfrom.GetId(),
remoteAddr);
int64_t nTimeOffset = nTime - GetTime();
@@ -2455,6 +2660,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
// Feeler connections exist only to verify if address is online.
if (pfrom.IsFeelerConn()) {
+ LogPrint(BCLog::NET, "feeler connection completed peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
}
return;
@@ -2470,13 +2676,16 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
if (msg_type == NetMsgType::VERACK) {
- if (pfrom.fSuccessfullyConnected) return;
+ if (pfrom.fSuccessfullyConnected) {
+ LogPrint(BCLog::NET, "ignoring redundant verack message from peer=%d\n", pfrom.GetId());
+ return;
+ }
if (!pfrom.IsInboundConn()) {
LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
- pfrom.nVersion.load(), pfrom.nStartingHeight,
+ pfrom.nVersion.load(), peer->m_starting_height,
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""),
- pfrom.IsBlockOnlyConn() ? "block-relay" : "full-relay");
+ pfrom.ConnectionTypeAsString());
}
if (pfrom.GetCommonVersion() >= SENDHEADERS_VERSION) {
@@ -2542,6 +2751,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (pfrom.fSuccessfullyConnected) {
// Disconnect peers that send wtxidrelay message after VERACK; this
// must be negotiated between VERSION and VERACK.
+ LogPrint(BCLog::NET, "wtxidrelay received after verack from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
@@ -2550,7 +2760,11 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (!State(pfrom.GetId())->m_wtxid_relay) {
State(pfrom.GetId())->m_wtxid_relay = true;
g_wtxid_relay_peers++;
+ } else {
+ LogPrint(BCLog::NET, "ignoring duplicate wtxidrelay from peer=%d\n", pfrom.GetId());
}
+ } else {
+ LogPrint(BCLog::NET, "ignoring wtxidrelay due to old common version=%d from peer=%d\n", pfrom.GetCommonVersion(), pfrom.GetId());
}
return;
}
@@ -2559,6 +2773,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (pfrom.fSuccessfullyConnected) {
// Disconnect peers that send SENDADDRV2 message after VERACK; this
// must be negotiated between VERSION and VERACK.
+ LogPrint(BCLog::NET, "sendaddrv2 received after verack from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
@@ -2585,6 +2800,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
s >> vAddr;
if (!pfrom.RelayAddrsWithConn()) {
+ LogPrint(BCLog::NET, "ignoring %s message from %s peer=%d\n", msg_type, pfrom.ConnectionTypeAsString(), pfrom.GetId());
return;
}
if (vAddr.size() > MAX_ADDR_TO_SEND)
@@ -2628,8 +2844,10 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
m_connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000)
pfrom.fGetAddr = false;
- if (pfrom.IsAddrFetchConn())
+ if (pfrom.IsAddrFetchConn()) {
+ LogPrint(BCLog::NET, "addrfetch connection completed peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
+ }
return;
}
@@ -2786,13 +3004,12 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
}
- WITH_LOCK(pfrom.cs_inventory, pfrom.vInventoryBlockToSend.push_back(pindex->GetBlockHash()));
- if (--nLimit <= 0)
- {
+ WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash()));
+ if (--nLimit <= 0) {
// When this block is requested, we'll send an inv that'll
// trigger the peer to getblocks the next batch of inventory.
LogPrint(BCLog::NET, " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
- pfrom.hashContinue = pindex->GetBlockHash();
+ WITH_LOCK(peer->m_block_inv_mutex, {peer->m_continuation_block = pindex->GetBlockHash();});
break;
}
}
@@ -3316,7 +3533,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
// 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 disconnected/discouraged.
- return ProcessHeadersMessage(pfrom, {cmpctblock.header}, /*via_compact_block=*/true);
+ return ProcessHeadersMessage(pfrom, *peer, {cmpctblock.header}, /*via_compact_block=*/true);
}
if (fBlockReconstructed) {
@@ -3459,7 +3676,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- return ProcessHeadersMessage(pfrom, headers, /*via_compact_block=*/false);
+ return ProcessHeadersMessage(pfrom, *peer, headers, /*via_compact_block=*/false);
}
if (msg_type == NetMsgType::BLOCK)
@@ -3637,6 +3854,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (msg_type == NetMsgType::FILTERLOAD) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
+ LogPrint(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
@@ -3659,6 +3877,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (msg_type == NetMsgType::FILTERADD) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
+ LogPrint(BCLog::NET, "filteradd received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
@@ -3686,6 +3905,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
if (msg_type == NetMsgType::FILTERCLEAR) {
if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
+ LogPrint(BCLog::NET, "filterclear received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
}
@@ -3703,7 +3923,6 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
if (pfrom.m_tx_relay != nullptr) {
- LOCK(pfrom.m_tx_relay->cs_feeFilter);
pfrom.m_tx_relay->minFeeFilter = newFeeFilter;
}
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId());
@@ -3747,7 +3966,7 @@ void PeerManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDat
return;
}
-bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode)
+bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode)
{
const NodeId peer_id{pnode.GetId()};
PeerRef peer = GetPeerRef(peer_id);
@@ -3789,7 +4008,7 @@ bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode)
return true;
}
-bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
+bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
{
bool fMoreWork = false;
@@ -3864,7 +4083,7 @@ bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgP
return fMoreWork;
}
-void PeerManager::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
+void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
{
AssertLockHeld(cs_main);
@@ -3917,7 +4136,7 @@ void PeerManager::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
}
}
-void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds)
+void PeerManagerImpl::EvictExtraOutboundPeers(int64_t time_in_seconds)
{
// If we have any extra block-relay-only peers, disconnect the youngest unless
// it's given us a block -- in which case, compare with the second-youngest, and
@@ -4018,7 +4237,7 @@ void PeerManager::EvictExtraOutboundPeers(int64_t time_in_seconds)
}
}
-void PeerManager::CheckForStaleTipAndEvictPeers()
+void PeerManagerImpl::CheckForStaleTipAndEvictPeers()
{
LOCK(cs_main);
@@ -4065,8 +4284,9 @@ public:
};
}
-bool PeerManager::SendMessages(CNode* pto)
+bool PeerManagerImpl::SendMessages(CNode* pto)
{
+ PeerRef peer = GetPeerRef(pto->GetId());
const Consensus::Params& consensusParams = m_chainparams.GetConsensus();
// We must call MaybeDiscourageAndDisconnect first, to ensure that we'll
@@ -4192,7 +4412,7 @@ bool PeerManager::SendMessages(CNode* pto)
got back an empty response. */
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
- LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight);
+ LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height);
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256()));
}
}
@@ -4208,11 +4428,11 @@ bool PeerManager::SendMessages(CNode* pto)
// If no header would connect, or if we have too many
// blocks, or if the peer doesn't want headers, just
// add all to the inv queue.
- LOCK(pto->cs_inventory);
+ LOCK(peer->m_block_inv_mutex);
std::vector<CBlock> vHeaders;
bool fRevertToInv = ((!state.fPreferHeaders &&
- (!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||
- pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
+ (!state.fPreferHeaderAndIDs || peer->m_blocks_for_headers_relay.size() > 1)) ||
+ peer->m_blocks_for_headers_relay.size() > MAX_BLOCKS_TO_ANNOUNCE);
const CBlockIndex *pBestIndex = nullptr; // last header queued for delivery
ProcessBlockAvailability(pto->GetId()); // ensure pindexBestKnownBlock is up-to-date
@@ -4221,7 +4441,7 @@ bool PeerManager::SendMessages(CNode* pto)
// Try to find first header that our peer doesn't have, and
// then send all headers past that one. If we come across any
// headers that aren't on ::ChainActive(), give up.
- for (const uint256 &hash : pto->vBlockHashesToAnnounce) {
+ for (const uint256& hash : peer->m_blocks_for_headers_relay) {
const CBlockIndex* pindex = LookupBlockIndex(hash);
assert(pindex);
if (::ChainActive()[pindex->nHeight] != pindex) {
@@ -4238,7 +4458,7 @@ bool PeerManager::SendMessages(CNode* pto)
// which should be caught by the prior check), but one
// way this could happen is by using invalidateblock /
// reconsiderblock repeatedly on the tip, causing it to
- // be added multiple times to vBlockHashesToAnnounce.
+ // be added multiple times to m_blocks_for_headers_relay.
// Robustly deal with this rare situation by reverting
// to an inv.
fRevertToInv = true;
@@ -4310,10 +4530,10 @@ bool PeerManager::SendMessages(CNode* pto)
}
if (fRevertToInv) {
// If falling back to using an inv, just try to inv the tip.
- // The last entry in vBlockHashesToAnnounce was our tip at some point
+ // The last entry in m_blocks_for_headers_relay was our tip at some point
// in the past.
- if (!pto->vBlockHashesToAnnounce.empty()) {
- const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back();
+ if (!peer->m_blocks_for_headers_relay.empty()) {
+ const uint256& hashToAnnounce = peer->m_blocks_for_headers_relay.back();
const CBlockIndex* pindex = LookupBlockIndex(hashToAnnounce);
assert(pindex);
@@ -4327,13 +4547,13 @@ bool PeerManager::SendMessages(CNode* pto)
// If the peer's chain has this block, don't inv it back.
if (!PeerHasHeader(&state, pindex)) {
- pto->vInventoryBlockToSend.push_back(hashToAnnounce);
+ peer->m_blocks_for_inv_relay.push_back(hashToAnnounce);
LogPrint(BCLog::NET, "%s: sending inv peer=%d hash=%s\n", __func__,
pto->GetId(), hashToAnnounce.ToString());
}
}
}
- pto->vBlockHashesToAnnounce.clear();
+ peer->m_blocks_for_headers_relay.clear();
}
//
@@ -4341,18 +4561,18 @@ bool PeerManager::SendMessages(CNode* pto)
//
std::vector<CInv> vInv;
{
- LOCK(pto->cs_inventory);
- vInv.reserve(std::max<size_t>(pto->vInventoryBlockToSend.size(), INVENTORY_BROADCAST_MAX));
+ LOCK(peer->m_block_inv_mutex);
+ vInv.reserve(std::max<size_t>(peer->m_blocks_for_inv_relay.size(), INVENTORY_BROADCAST_MAX));
// Add blocks
- for (const uint256& hash : pto->vInventoryBlockToSend) {
+ for (const uint256& hash : peer->m_blocks_for_inv_relay) {
vInv.push_back(CInv(MSG_BLOCK, hash));
if (vInv.size() == MAX_INV_SZ) {
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
vInv.clear();
}
}
- pto->vInventoryBlockToSend.clear();
+ peer->m_blocks_for_inv_relay.clear();
if (pto->m_tx_relay != nullptr) {
LOCK(pto->m_tx_relay->cs_tx_inventory);
@@ -4378,11 +4598,7 @@ bool PeerManager::SendMessages(CNode* pto)
if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
auto vtxinfo = m_mempool.infoAll();
pto->m_tx_relay->fSendMempool = false;
- CFeeRate filterrate;
- {
- LOCK(pto->m_tx_relay->cs_feeFilter);
- filterrate = CFeeRate(pto->m_tx_relay->minFeeFilter);
- }
+ const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
LOCK(pto->m_tx_relay->cs_filter);
@@ -4416,11 +4632,7 @@ bool PeerManager::SendMessages(CNode* pto)
for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
vInvTx.push_back(it);
}
- CFeeRate filterrate;
- {
- LOCK(pto->m_tx_relay->cs_feeFilter);
- filterrate = CFeeRate(pto->m_tx_relay->minFeeFilter);
- }
+ const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
// A heap is used so that not all items need sorting if only a few are being sent.
CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, state.m_wtxid_relay);
@@ -4581,7 +4793,7 @@ bool PeerManager::SendMessages(CNode* pto)
}
//
- // Message: getdata (non-blocks)
+ // Message: getdata (transactions)
//
std::vector<std::pair<NodeId, GenTxid>> expired;
auto requestable = m_txrequest.GetRequestable(pto->GetId(), current_time, &expired);
diff --git a/src/net_processing.h b/src/net_processing.h
index 12a4e9c38f..eaa3b142a8 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -6,19 +6,13 @@
#ifndef BITCOIN_NET_PROCESSING_H
#define BITCOIN_NET_PROCESSING_H
-#include <consensus/params.h>
#include <net.h>
#include <sync.h>
-#include <txrequest.h>
#include <validationinterface.h>
-class BlockTransactionsRequest;
-class BlockValidationState;
-class CBlockHeader;
class CChainParams;
class CTxMemPool;
class ChainstateManager;
-class TxValidationState;
extern RecursiveMutex cs_main;
extern RecursiveMutex g_cs_orphans;
@@ -33,192 +27,45 @@ static const bool DEFAULT_PEERBLOCKFILTERS = false;
static const int DISCOURAGEMENT_THRESHOLD{100};
struct CNodeStateStats {
- int m_misbehavior_score = 0;
int nSyncHeight = -1;
int nCommonHeight = -1;
+ int m_starting_height = -1;
std::vector<int> vHeightInFlight;
};
-/**
- * Data structure for an individual peer. This struct is not protected by
- * cs_main since it does not contain validation-critical data.
- *
- * Memory is owned by shared pointers and this object is destructed when
- * the refcount drops to zero.
- *
- * TODO: move most members from CNodeState to this structure.
- * TODO: move remaining application-layer data members from CNode to this structure.
- */
-struct Peer {
- /** Same id as the CNode object for this peer */
- const NodeId m_id{0};
-
- /** Protects misbehavior data members */
- Mutex m_misbehavior_mutex;
- /** Accumulated misbehavior score for this peer */
- int m_misbehavior_score GUARDED_BY(m_misbehavior_mutex){0};
- /** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
- bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
-
- /** Set of txids to reconsider once their parent transactions have been accepted **/
- std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
-
- /** Protects m_getdata_requests **/
- Mutex m_getdata_requests_mutex;
- /** Work queue of items requested by this peer **/
- std::deque<CInv> m_getdata_requests GUARDED_BY(m_getdata_requests_mutex);
-
- explicit Peer(NodeId id) : m_id(id) {}
-};
-
-using PeerRef = std::shared_ptr<Peer>;
-
-class PeerManager final : public CValidationInterface, public NetEventsInterface {
+class PeerManager : public CValidationInterface, public NetEventsInterface
+{
public:
- PeerManager(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
- CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
- bool ignore_incoming_txs);
-
- /**
- * Overridden from CValidationInterface.
- */
- void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected) override;
- void BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex) override;
- /**
- * Overridden from CValidationInterface.
- */
- void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
- /**
- * Overridden from CValidationInterface.
- */
- void BlockChecked(const CBlock& block, const BlockValidationState& state) override;
- /**
- * Overridden from CValidationInterface.
- */
- void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override;
+ static std::unique_ptr<PeerManager> make(const CChainParams& chainparams, CConnman& connman, BanMan* banman,
+ CScheduler& scheduler, ChainstateManager& chainman, CTxMemPool& pool,
+ bool ignore_incoming_txs);
+ virtual ~PeerManager() { }
- /** Initialize a peer by adding it to mapNodeState and pushing a message requesting its version */
- void InitializeNode(CNode* pnode) override;
- /** Handle removal of a peer by updating various state and removing it from mapNodeState */
- void FinalizeNode(const CNode& node, bool& fUpdateConnectionTime) override;
- /**
- * Process protocol messages received from a given node
- *
- * @param[in] pfrom The node which we have received messages from.
- * @param[in] interrupt Interrupt condition for processing threads
- */
- bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override;
- /**
- * Send queued protocol messages to be sent to a give node.
- *
- * @param[in] pto The node which we are sending messages to.
- * @return True if there is more work to be done
- */
- bool SendMessages(CNode* pto) override EXCLUSIVE_LOCKS_REQUIRED(pto->cs_sendProcessing);
+ /** Get statistics from node state */
+ virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) = 0;
- /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
- void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */
- void CheckForStaleTipAndEvictPeers();
- /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */
- void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /** Retrieve unbroadcast transactions from the mempool and reattempt sending to peers */
- void ReattemptInitialBroadcast(CScheduler& scheduler) const;
+ /** Whether this node ignores txs received over p2p. */
+ virtual bool IgnoresIncomingTxs() = 0;
- /** Process a single message from a peer. Public for fuzz testing */
- void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
- const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc);
+ /** Set the best height */
+ virtual void SetBestHeight(int height) = 0;
/**
* Increment peer's misbehavior score. If the new value >= DISCOURAGEMENT_THRESHOLD, mark the node
* to be discouraged, meaning the peer might be disconnected and added to the discouragement filter.
* Public for unit testing.
*/
- void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message);
-
- /** Get statistics from node state */
- bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats);
-
- /** Whether this node ignores txs received over p2p. */
- bool IgnoresIncomingTxs() {return m_ignore_incoming_txs;};
-
-private:
- /** Get a shared pointer to the Peer object.
- * May return an empty shared_ptr if the Peer object can't be found. */
- PeerRef GetPeerRef(NodeId id) const;
-
- /** Get a shared pointer to the Peer object and remove it from m_peer_map.
- * May return an empty shared_ptr if the Peer object can't be found. */
- PeerRef RemovePeer(NodeId id);
-
- /**
- * Potentially mark a node discouraged based on the contents of a BlockValidationState object
- *
- * @param[in] via_compact_block this bool is passed in because net_processing should
- * punish peers differently depending on whether the data was provided in a compact
- * block message or not. If the compact block had a valid header, but contained invalid
- * txs, the peer should not be punished. See BIP 152.
- *
- * @return Returns true if the peer was punished (probably disconnected)
- */
- bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
- bool via_compact_block, const std::string& message = "");
+ virtual void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) = 0;
/**
- * Potentially disconnect and discourage a node based on the contents of a TxValidationState object
- *
- * @return Returns true if the peer was punished (probably disconnected)
- */
- bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "");
-
- /** Maybe disconnect a peer and discourage future connections from its address.
- *
- * @param[in] pnode The node to check.
- * @return True if the peer was marked for disconnection in this function
+ * Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound.
+ * Public for unit testing.
*/
- bool MaybeDiscourageAndDisconnect(CNode& pnode);
+ virtual void CheckForStaleTipAndEvictPeers() = 0;
- void ProcessOrphanTx(std::set<uint256>& orphan_work_set) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans);
- /** Process a single headers message from a peer. */
- void ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHeader>& headers, bool via_compact_block);
-
- void SendBlockTransactions(CNode& pfrom, const CBlock& block, const BlockTransactionsRequest& req);
-
- /** Register with TxRequestTracker that an INV has been received from a
- * peer. The announcement parameters are decided in PeerManager and then
- * passed to TxRequestTracker. */
- void AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, std::chrono::microseconds current_time)
- EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
-
- /** Send a version message to a peer */
- void PushNodeVersion(CNode& pnode, int64_t nTime);
-
- const CChainParams& m_chainparams;
- CConnman& m_connman;
- /** Pointer to this node's banman. May be nullptr - check existence before dereferencing. */
- BanMan* const m_banman;
- ChainstateManager& m_chainman;
- CTxMemPool& m_mempool;
- TxRequestTracker m_txrequest GUARDED_BY(::cs_main);
-
- int64_t m_stale_tip_check_time; //!< Next time to check for stale tip
-
- //* Whether this node is running in blocks only mode */
- const bool m_ignore_incoming_txs;
-
- /** Whether we've completed initial sync yet, for determining when to turn
- * on extra block-relay-only peers. */
- bool m_initial_sync_finished{false};
-
- /** Protects m_peer_map */
- mutable Mutex m_peer_mutex;
- /**
- * Map of all Peer objects, keyed by peer id. This map is protected
- * by the m_peer_mutex. Once a shared pointer reference is
- * taken, the lock may be released. Individual fields are protected by
- * their own locks.
- */
- std::map<NodeId, PeerRef> m_peer_map GUARDED_BY(m_peer_mutex);
+ /** Process a single message from a peer. Public for fuzz testing */
+ virtual void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv,
+ const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) = 0;
};
/** Relay transaction to every node */
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index b1f9d32d34..85e46fd373 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -1068,15 +1068,24 @@ CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()
CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()
{
- valid = addr.IsIPv4() || addr.IsIPv6();
- if (!valid) {
+ switch (addr.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ valid = true;
+ assert(addr.m_addr.size() <= sizeof(netmask));
+ memset(netmask, 0xFF, addr.m_addr.size());
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ valid = true;
+ break;
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
return;
}
- assert(addr.m_addr.size() <= sizeof(netmask));
-
- memset(netmask, 0xFF, addr.m_addr.size());
-
network = addr;
}
@@ -1088,6 +1097,21 @@ bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid() || network.m_net != addr.m_net)
return false;
+
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ case NET_INTERNAL:
+ return addr == network;
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ return false;
+ }
+
assert(network.m_addr.size() == addr.m_addr.size());
for (size_t x = 0; x < addr.m_addr.size(); ++x) {
if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) {
@@ -1099,18 +1123,35 @@ bool CSubNet::Match(const CNetAddr &addr) const
std::string CSubNet::ToString() const
{
- assert(network.m_addr.size() <= sizeof(netmask));
+ std::string suffix;
- uint8_t cidr = 0;
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6: {
+ assert(network.m_addr.size() <= sizeof(netmask));
- for (size_t i = 0; i < network.m_addr.size(); ++i) {
- if (netmask[i] == 0x00) {
- break;
+ uint8_t cidr = 0;
+
+ for (size_t i = 0; i < network.m_addr.size(); ++i) {
+ if (netmask[i] == 0x00) {
+ break;
+ }
+ cidr += NetmaskBits(netmask[i]);
}
- cidr += NetmaskBits(netmask[i]);
+
+ suffix = strprintf("/%u", cidr);
+ break;
+ }
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ break;
}
- return network.ToString() + strprintf("/%u", cidr);
+ return network.ToString() + suffix;
}
bool CSubNet::IsValid() const
@@ -1120,7 +1161,19 @@ bool CSubNet::IsValid() const
bool CSubNet::SanityCheck() const
{
- if (!(network.IsIPv4() || network.IsIPv6())) return false;
+ switch (network.m_net) {
+ case NET_IPV4:
+ case NET_IPV6:
+ break;
+ case NET_ONION:
+ case NET_I2P:
+ case NET_CJDNS:
+ return true;
+ case NET_INTERNAL:
+ case NET_UNROUTABLE:
+ case NET_MAX:
+ return false;
+ }
for (size_t x = 0; x < network.m_addr.size(); ++x) {
if (network.m_addr[x] & ~netmask[x]) return false;
diff --git a/src/netaddress.h b/src/netaddress.h
index 29b2eaafeb..b9eade7fd5 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -462,11 +462,33 @@ class CSubNet
bool SanityCheck() const;
public:
+ /**
+ * Construct an invalid subnet (empty, `Match()` always returns false).
+ */
CSubNet();
+
+ /**
+ * Construct from a given network start and number of bits (CIDR mask).
+ * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is
+ * created.
+ * @param[in] mask CIDR mask, must be in [0, 32] for IPv4 addresses and in [0, 128] for
+ * IPv6 addresses. Otherwise an invalid subnet is created.
+ */
CSubNet(const CNetAddr& addr, uint8_t mask);
+
+ /**
+ * Construct from a given network start and mask.
+ * @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is
+ * created.
+ * @param[in] mask Network mask, must be of the same type as `addr` and not contain 0-bits
+ * followed by 1-bits. Otherwise an invalid subnet is created.
+ */
CSubNet(const CNetAddr& addr, const CNetAddr& mask);
- //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
+ /**
+ * Construct a single-host subnet.
+ * @param[in] addr The sole address to be contained in the subnet, can also be non-IPv[46].
+ */
explicit CSubNet(const CNetAddr& addr);
bool Match(const CNetAddr &addr) const;
@@ -483,7 +505,7 @@ class CSubNet
READWRITE(obj.network);
if (obj.network.IsIPv4()) {
// Before commit 102867c587f5f7954232fb8ed8e85cda78bb4d32, CSubNet used the last 4 bytes of netmask
- // to store the relevant bytes for an IPv4 mask. For compatiblity reasons, keep doing so in
+ // to store the relevant bytes for an IPv4 mask. For compatibility reasons, keep doing so in
// serialized form.
unsigned char dummy[12] = {0};
READWRITE(dummy);
diff --git a/src/netmessagemaker.h b/src/netmessagemaker.h
index ffb3fe2f29..89fb4758f9 100644
--- a/src/netmessagemaker.h
+++ b/src/netmessagemaker.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/coinstats.h b/src/node/coinstats.h
index 2a7441c10e..7c56bfc2ad 100644
--- a/src/node/coinstats.h
+++ b/src/node/coinstats.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 317a5c7cbe..e07eaa33d8 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -12,6 +12,7 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <interfaces/wallet.h>
+#include <mapport.h>
#include <net.h>
#include <net_processing.h>
#include <netaddress.h>
@@ -93,15 +94,7 @@ public:
}
}
bool shutdownRequested() override { return ShutdownRequested(); }
- void mapPort(bool use_upnp) override
- {
- if (use_upnp) {
- StartMapPort();
- } else {
- InterruptMapPort();
- StopMapPort();
- }
- }
+ void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); }
bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); }
size_t getNodeCount(CConnman::NumConnections flags) override
{
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 97d5aad8e4..d3bb9687a8 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h
index c8b4d60fd0..fe78cb46bd 100644
--- a/src/node/utxo_snapshot.h
+++ b/src/node/utxo_snapshot.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/noui.cpp b/src/noui.cpp
index 3c82512fac..6fe5c5638c 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/noui.h b/src/noui.h
index 8ec5708328..cf273ffb33 100644
--- a/src/noui.h
+++ b/src/noui.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2019 The Bitcoin Core developers
+// Copyright (c) 2013-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/optional.h b/src/optional.h
index a382cd7b77..583c56eabd 100644
--- a/src/optional.h
+++ b/src/optional.h
@@ -1,26 +1,20 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_OPTIONAL_H
#define BITCOIN_OPTIONAL_H
+#include <optional>
#include <utility>
-#include <boost/optional.hpp>
-
//! Substitute for C++17 std::optional
+//! DEPRECATED use std::optional in new code.
template <typename T>
-using Optional = boost::optional<T>;
-
-//! Substitute for C++17 std::make_optional
-template <typename T>
-Optional<T> MakeOptional(bool condition, T&& value)
-{
- return boost::make_optional(condition, std::forward<T>(value));
-}
+using Optional = std::optional<T>;
//! Substitute for C++17 std::nullopt
-static auto& nullopt = boost::none;
+//! DEPRECATED use std::nullopt in new code.
+static auto& nullopt = std::nullopt;
#endif // BITCOIN_OPTIONAL_H
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index e978852826..d96fb282c5 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -19,8 +19,6 @@ static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
-const std::array<OutputType, 3> OUTPUT_TYPES = {OutputType::LEGACY, OutputType::P2SH_SEGWIT, OutputType::BECH32};
-
bool ParseOutputType(const std::string& type, OutputType& output_type)
{
if (type == OUTPUT_TYPE_STRING_LEGACY) {
diff --git a/src/outputtype.h b/src/outputtype.h
index bb7f39323b..88422e5824 100644
--- a/src/outputtype.h
+++ b/src/outputtype.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,7 +20,11 @@ enum class OutputType {
BECH32,
};
-extern const std::array<OutputType, 3> OUTPUT_TYPES;
+static constexpr auto OUTPUT_TYPES = std::array{
+ OutputType::LEGACY,
+ OutputType::P2SH_SEGWIT,
+ OutputType::BECH32,
+};
[[nodiscard]] bool ParseOutputType(const std::string& str, OutputType& output_type);
const std::string& FormatOutputType(OutputType type);
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index 04e0e117a5..3da85fedf9 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 7c5660ac8a..86ae507957 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index cfa4cf8421..7da171d2e1 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,21 +12,18 @@
#include <txmempool.h>
#include <util/system.h>
-static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
+static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
static constexpr double INF_FEERATE = 1e99;
-std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
- static const std::map<FeeEstimateHorizon, std::string> horizon_strings = {
- {FeeEstimateHorizon::SHORT_HALFLIFE, "short"},
- {FeeEstimateHorizon::MED_HALFLIFE, "medium"},
- {FeeEstimateHorizon::LONG_HALFLIFE, "long"},
- };
- auto horizon_string = horizon_strings.find(horizon);
-
- if (horizon_string == horizon_strings.end()) return "unknown";
-
- return horizon_string->second;
+std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
+{
+ switch (horizon) {
+ case FeeEstimateHorizon::SHORT_HALFLIFE: return "short";
+ case FeeEstimateHorizon::MED_HALFLIFE: return "medium";
+ case FeeEstimateHorizon::LONG_HALFLIFE: return "long";
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
/**
@@ -644,7 +641,7 @@ CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
{
- TxConfirmStats* stats;
+ TxConfirmStats* stats = nullptr;
double sufficientTxs = SUFFICIENT_FEETXS;
switch (horizon) {
case FeeEstimateHorizon::SHORT_HALFLIFE: {
@@ -660,10 +657,8 @@ CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThr
stats = longStats.get();
break;
}
- default: {
- throw std::out_of_range("CBlockPolicyEstimator::estimateRawFee unknown FeeEstimateHorizon");
- }
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(stats);
LOCK(m_cs_fee_estimator);
// Return failure if trying to analyze a target we're not tracking
@@ -693,10 +688,8 @@ unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon hori
case FeeEstimateHorizon::LONG_HALFLIFE: {
return longStats->GetMaxConfirms();
}
- default: {
- throw std::out_of_range("CBlockPolicyEstimator::HighestTargetTracked unknown FeeEstimateHorizon");
- }
- }
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
}
unsigned int CBlockPolicyEstimator::BlockSpan() const
diff --git a/src/policy/fees.h b/src/policy/fees.h
index dd9f530c99..c444d71a31 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -11,6 +11,7 @@
#include <random.h>
#include <sync.h>
+#include <array>
#include <map>
#include <memory>
#include <string>
@@ -25,9 +26,15 @@ class TxConfirmStats;
/* Identifier for each of the 3 different TxConfirmStats which will track
* history over different time horizons. */
enum class FeeEstimateHorizon {
- SHORT_HALFLIFE = 0,
- MED_HALFLIFE = 1,
- LONG_HALFLIFE = 2
+ SHORT_HALFLIFE,
+ MED_HALFLIFE,
+ LONG_HALFLIFE,
+};
+
+static constexpr auto ALL_FEE_ESTIMATE_HORIZONS = std::array{
+ FeeEstimateHorizon::SHORT_HALFLIFE,
+ FeeEstimateHorizon::MED_HALFLIFE,
+ FeeEstimateHorizon::LONG_HALFLIFE,
};
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon);
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 8e367d31d0..2b5fd4179d 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/policy.h b/src/policy/policy.h
index fc163e958b..f2a3f35546 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 4b55934891..8125b41c41 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index f84e6e5286..e078070c1c 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/primitives/block.h b/src/primitives/block.h
index fd8fc8b868..2d10853607 100644
--- a/src/primitives/block.h
+++ b/src/primitives/block.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index ec09668e7a..6bf36ee854 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/protocol.cpp b/src/protocol.cpp
index d7b73dfa40..56e738eaa8 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/protocol.h b/src/protocol.h
index 8af34f58bd..f183db0501 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 3fb743e5db..4db57d3cd0 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <psbt.h>
+
+#include <util/check.h>
#include <util/strencodings.h>
@@ -207,7 +209,8 @@ size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index)
{
- const CTxOut& out = psbt.tx->vout.at(index);
+ CMutableTransaction& tx = *Assert(psbt.tx);
+ const CTxOut& out = tx.vout.at(index);
PSBTOutput& psbt_out = psbt.outputs.at(index);
// Fill a SignatureData with output info
@@ -217,7 +220,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio
// Construct a would-be spend of this output, to update sigdata with.
// Note that ProduceSignature is used to fill in metadata (not actual signatures),
// so provider does not need to provide any private keys (it can be a HidingSigningProvider).
- MutableTransactionSignatureCreator creator(psbt.tx.get_ptr(), /* index */ 0, out.nValue, SIGHASH_ALL);
+ MutableTransactionSignatureCreator creator(&tx, /* index */ 0, out.nValue, SIGHASH_ALL);
ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
// Put redeem_script, witness_script, key paths, into PSBTOutput.
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 4d734fc891..fc1624af25 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/pubkey.h b/src/pubkey.h
index d60520ac44..12514fc3c9 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/README.md b/src/qt/README.md
index 30c68db15b..20c712c98d 100644
--- a/src/qt/README.md
+++ b/src/qt/README.md
@@ -1,10 +1,12 @@
-This directory contains the BitcoinQT graphical user interface (GUI). It uses the cross-platform framework [Qt](https://www1.qt.io/developers/).
+This directory contains the source code for the Bitcoin Core graphical user interface (GUI). It uses the [Qt](https://www1.qt.io/developers/) cross-platform framework.
The current precise version for Qt 5 is specified in [qt.mk](/depends/packages/qt.mk).
## Compile and run
-See build instructions ([macOS](/doc/build-osx.md), [Windows](/doc/build-windows.md), [Unix](/doc/build-unix.md), etc).
+See build instructions: [Unix](/doc/build-unix.md), [macOS](/doc/build-osx.md), [Windows](/doc/build-windows.md), [FreeBSD](/doc/build-freebsd.md), [NetBSD](/doc/build-netbsd.md), [OpenBSD](/doc/build-openbsd.md)
+
+When following your systems build instructions, make sure to install the `Qt` dependencies.
To run:
@@ -12,84 +14,111 @@ To run:
./src/qt/bitcoin-qt
```
-## Files and directories
-
-### forms
+## Files and Directories
-Contains [Designer UI](https://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. They are created with [Qt Creator](#using-qt-creator-as-ide), but can be edited using any text editor.
+#### forms/
-### locale
+- A directory that contains [Designer UI](https://doc.qt.io/qt-5.9/designer-using-a-ui-file.html) files. These files specify the characteristics of form elements in XML. Qt UI files can be edited with [Qt Creator](#using-qt-creator-as-ide) or using any text editor.
-Contains translations. They are periodically updated. The process is described [here](/doc/translation_process.md).
+#### locale/
-### res
+- Contains translations. They are periodically updated and an effort is made to support as many languages as possible. The process of contributing translations is described in [doc/translation_process.md](/doc/translation_process.md).
-Resources such as the icon.
+#### res/
-### test
+ - Contains graphical resources used to enhance the UI experience.
-Tests.
+#### test/
-### bitcoingui.(h/cpp)
+- Functional tests used to ensure proper functionality of the GUI. Significant changes to the GUI code normally require new or updated tests.
-Represents the main window of the Bitcoin UI.
+#### bitcoingui.(h/cpp)
-### \*model.(h/cpp)
+- Represents the main window of the Bitcoin UI.
-The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](https://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](https://doc.qt.io/qt-5/qvalidator.html).
+#### \*model.(h/cpp)
-ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`.
+- The model. When it has a corresponding controller, it generally inherits from [QAbstractTableModel](https://doc.qt.io/qt-5/qabstracttablemodel.html). Models that are used by controllers as helpers inherit from other Qt classes like [QValidator](https://doc.qt.io/qt-5/qvalidator.html).
+- ClientModel is used by the main application `bitcoingui` and several models like `peertablemodel`.
-### \*page.(h/cpp)
+#### \*page.(h/cpp)
-A controller. `:NAMEpage.cpp` generally includes `:NAMEmodel.h` and `forms/:NAME.page.ui` with a similar `:NAME`.
+- A controller. `:NAMEpage.cpp` generally includes `:NAMEmodel.h` and `forms/:NAME.page.ui` with a similar `:NAME`.
-### \*dialog.(h/cpp)
+#### \*dialog.(h/cpp)
-Various dialogs, e.g. to open a URL. Inherit from [QDialog](https://doc.qt.io/qt-5/qdialog.html).
+- Various dialogs, e.g. to open a URL. Inherit from [QDialog](https://doc.qt.io/qt-5/qdialog.html).
-### paymentserver.(h/cpp)
+#### paymentserver.(h/cpp)
-Used to process BIP21 payment URI requests. Also handles URI based application switching (e.g. when following a bitcoin:... link from a browser).
+- (Deprecated) Used to process BIP21 payment URI requests. Also handles URI-based application switching (e.g. when following a bitcoin:... link from a browser).
-### walletview.(h/cpp)
+#### walletview.(h/cpp)
-Represents the view to a single wallet.
+- Represents the view to a single wallet.
-### Other .h/cpp files
+#### Other .h/cpp files
* UI elements like BitcoinAmountField, which inherit from QWidget.
* `bitcoinstrings.cpp`: automatically generated
-* `bitcoinunits.(h/cpp)`: BTC / mBTC / etc handling
+* `bitcoinunits.(h/cpp)`: BTC / mBTC / etc. handling
* `callback.h`
-* `guiconstants.h`: UI colors, app name, etc
+* `guiconstants.h`: UI colors, app name, etc.
* `guiutil.h`: several helper functions
* `macdockiconhandler.(h/mm)`: macOS dock icon handler
* `macnotificationhandler.(h/mm)`: display notifications in macOS
## Contribute
-See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines. Specifically for Qt:
+See [CONTRIBUTING.md](/CONTRIBUTING.md) for general guidelines.
+
+**Note:** Do not change `local/bitcoin_en.ts`. It is updated [automatically](/doc/translation_process.md#writing-code-with-translations).
+
+## Using Qt Creator as an IDE
+
+[Qt Creator](https://www.qt.io/product/development-tools) is a powerful tool which packages a UI designer tool (Qt Designer) and a C++ IDE into one application. This is especially useful if you want to change the UI layout.
+
+#### Download Qt Creator
+
+On Unix and macOS, Qt Creator can be installed through your package manager. Alternatively, you can download a binary from the [Qt Website](https://www.qt.io/download/).
+
+**Note:** If installing from a binary grabbed from the Qt Website: During the installation process, uncheck everything except for `Qt Creator`.
+
+##### macOS
+
+```sh
+brew install qt-creator
+```
+
+##### Ubuntu & Debian
+
+```sh
+sudo apt-get install qtcreator
+```
+
+#### Setup Qt Creator
-* don't change `local/bitcoin_en.ts`; this happens [automatically](/doc/translation_process.md#writing-code-with-translations)
+1. Make sure you've installed all dependencies specified in your systems build instructions
+2. Follow the compile instructions for your system, run `./configure` with the `--enable-debug` flag
+3. Start Qt Creator. At the start page, do: `New` -> `Import Project` -> `Import Existing Project`
+4. Enter `bitcoin-qt` as the Project Name and enter the absolute path to `src/qt` as Location
+5. Check over the file selection, you may need to select the `forms` directory (necessary if you intend to edit *.ui files)
+6. Confirm the `Summary` page
+7. In the `Projects` tab, select `Manage Kits...`
-## Using Qt Creator as IDE
+ **macOS**
+ - Under `Kits`: select the default "Desktop" kit
+ - Under `Compilers`: select `"Clang (x86 64bit in /usr/bin)"`
+ - Under `Debuggers`: select `"LLDB"` as debugger (you might need to set the path to your LLDB installation)
-You can use Qt Creator as an IDE. This is especially useful if you want to change
-the UI layout.
+ **Ubuntu & Debian**
-Download and install the community edition of [Qt Creator](https://www.qt.io/download/).
-Uncheck everything except Qt Creator during the installation process.
+ Note: Some of these options may already be set
-Instructions for macOS:
+ - Under `Kits`: select the default "Desktop" kit
+ - Under `Compilers`: select `"GCC (x86 64bit in /usr/bin)"`
+ - Under `Debuggers`: select `"GDB"` as debugger
-1. Make sure you installed everything through Homebrew mentioned in the [macOS build instructions](/doc/build-osx.md)
-2. Use `./configure` with the `--enable-debug` flag
-3. In Qt Creator do "New Project" -> Import Project -> Import Existing Project
-4. Enter "bitcoin-qt" as project name, enter src/qt as location
-5. Leave the file selection as it is
-6. Confirm the "summary page"
-7. In the "Projects" tab select "Manage Kits..."
-8. Select the default "Desktop" kit and select "Clang (x86 64bit in /usr/bin)" as compiler
-9. Select LLDB as debugger (you might need to set the path to your installation)
-10. Start debugging with Qt Creator (you might need to the executable to "bitcoin-qt" under "Run", which is where you can also add command line arguments)
+8. While in the `Projects` tab, ensure that you have the `bitcoin-qt` executable specified under `Run`
+ - If the executable is not specified: click `"Choose..."`, navigate to `src/qt`, and select `bitcoin-qt`
+9. You're all set! Start developing, building, and debugging the Bitcoin Core GUI
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index aa4ec04497..ab6168a541 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -56,7 +56,7 @@ protected:
};
AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode, Tabs _tab, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::AddressBookPage),
model(nullptr),
mode(_mode),
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index 3d303a6f68..c6a364ccbd 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 665c8e6053..bb444f22b3 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -11,7 +11,6 @@
#include <wallet/wallet.h>
#include <algorithm>
-#include <typeinfo>
#include <QFont>
#include <QDebug>
@@ -82,8 +81,9 @@ public:
{
for (const auto& address : wallet.getAddresses())
{
- if (pk_hash_only && address.dest.type() != typeid(PKHash))
+ if (pk_hash_only && !std::holds_alternative<PKHash>(address.dest)) {
continue;
+ }
AddressTableEntry::Type addressType = translateTransactionType(
QString::fromStdString(address.purpose), address.is_mine);
cachedAddressTable.append(AddressTableEntry(addressType,
@@ -177,13 +177,17 @@ AddressTableModel::~AddressTableModel()
int AddressTableModel::rowCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return priv->size();
}
int AddressTableModel::columnCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return columns.length();
}
@@ -257,7 +261,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
} else if(index.column() == Address) {
CTxDestination newAddress = DecodeDestination(value.toString().toStdString());
// Refuse to set invalid address, set error status and return false
- if(boost::get<CNoDestination>(&newAddress))
+ if(std::get_if<CNoDestination>(&newAddress))
{
editStatus = INVALID_ADDRESS;
return false;
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 73316cadc4..6cc14654ef 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp
index 3be8b664dd..5b1330b81b 100644
--- a/src/qt/askpassphrasedialog.cpp
+++ b/src/qt/askpassphrasedialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -20,7 +20,7 @@
#include <QPushButton>
AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureString* passphrase_out) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::AskPassphraseDialog),
mode(_mode),
model(nullptr),
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index f3ba882277..66031b08d3 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 2676de96d7..a01a7bc386 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -98,13 +98,17 @@ BanTableModel::~BanTableModel()
int BanTableModel::rowCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return priv->size();
}
int BanTableModel::columnCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return columns.length();
}
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 4e1b239bc7..d6d5ba6968 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -51,6 +51,7 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
+#include <QtGlobal>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -77,7 +78,7 @@ static void RegisterMetaTypes()
#ifdef ENABLE_WALLET
qRegisterMetaType<WalletModel*>();
#endif
- // Register typedefs (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
+ // Register typedefs (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType)
// IMPORTANT: if CAmount is no longer a typedef use the normal variant above (see https://doc.qt.io/qt-5/qmetatype.html#qRegisterMetaType-1)
qRegisterMetaType<CAmount>("CAmount");
qRegisterMetaType<size_t>("size_t");
@@ -466,6 +467,13 @@ int GuiMain(int argc, char* argv[])
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
+#if (QT_VERSION <= QT_VERSION_CHECK(5, 9, 8)) && defined(Q_OS_MACOS)
+ const auto os_name = QSysInfo::prettyProductName();
+ if (os_name.startsWith("macOS 11") || os_name.startsWith("macOS 10.16")) {
+ QApplication::setStyle("fusion");
+ }
+#endif
+
BitcoinApplication app;
/// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these
diff --git a/src/qt/bitcoinaddressvalidator.h b/src/qt/bitcoinaddressvalidator.h
index 52c06828a3..ae698c72a6 100644
--- a/src/qt/bitcoinaddressvalidator.h
+++ b/src/qt/bitcoinaddressvalidator.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index a953c991bc..2af3502be3 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index d3e61aac29..c60d9a2c90 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index f2a49e5a76..ccc0a6828c 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -30,6 +30,7 @@
#include <qt/macdockiconhandler.h>
#endif
+#include <functional>
#include <chain.h>
#include <chainparams.h>
#include <interfaces/handler.h>
@@ -845,7 +846,7 @@ void BitcoinGUI::showDebugWindowActivateConsole()
void BitcoinGUI::showHelpMessageClicked()
{
- helpMessageDialog->show();
+ GUIUtil::bringToFront(helpMessageDialog);
}
#ifdef ENABLE_WALLET
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 5402ed371d..9660ba99f7 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index a2f46c339b..56813b2d19 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -19,6 +19,7 @@
#include <validation.h>
#include <stdint.h>
+#include <functional>
#include <QDebug>
#include <QThread>
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 7f12cce1d9..7ac4cc040b 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 7c72858501..ca78c96d70 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -42,7 +42,7 @@ bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const {
}
CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _model, const PlatformStyle *_platformStyle, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::CoinControlDialog),
m_coin_control(coin_control),
model(_model),
@@ -455,7 +455,7 @@ void CoinControlDialog::updateLabels(CCoinControl& m_coin_control, WalletModel *
else if(ExtractDestination(out.txout.scriptPubKey, address))
{
CPubKey pubkey;
- PKHash *pkhash = boost::get<PKHash>(&address);
+ PKHash* pkhash = std::get_if<PKHash>(&address);
if (pkhash && model->wallet().getPubKey(out.txout.scriptPubKey, ToKeyID(*pkhash), pubkey))
{
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 3de7fd6d54..6ceb3de61d 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp
index 3945159c26..1467801522 100644
--- a/src/qt/createwalletdialog.cpp
+++ b/src/qt/createwalletdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -9,10 +9,12 @@
#include <qt/createwalletdialog.h>
#include <qt/forms/ui_createwalletdialog.h>
+#include <qt/guiutil.h>
+
#include <QPushButton>
CreateWalletDialog::CreateWalletDialog(QWidget* parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::CreateWalletDialog)
{
ui->setupUi(this);
diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp
index e0af9a20a8..e51ed9e656 100644
--- a/src/qt/editaddressdialog.cpp
+++ b/src/qt/editaddressdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -13,7 +13,7 @@
EditAddressDialog::EditAddressDialog(Mode _mode, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::EditAddressDialog),
mapper(nullptr),
mode(_mode),
diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h
index 3be63156fd..f7ad80bb2d 100644
--- a/src/qt/editaddressdialog.h
+++ b/src/qt/editaddressdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui
index ea713e1abd..881869a46c 100644
--- a/src/qt/forms/createwalletdialog.ui
+++ b/src/qt/forms/createwalletdialog.ui
@@ -7,140 +7,135 @@
<x>0</x>
<y>0</y>
<width>364</width>
- <height>213</height>
+ <height>249</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Wallet</string>
</property>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>170</y>
- <width>341</width>
- <height>32</height>
- </rect>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- <widget class="QLineEdit" name="wallet_name_line_edit">
- <property name="geometry">
- <rect>
- <x>120</x>
- <y>20</y>
- <width>231</width>
- <height>24</height>
- </rect>
- </property>
- <property name="placeholderText">
- <string>Wallet</string>
- </property>
- </widget>
- <widget class="QLabel" name="label">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>20</y>
- <width>101</width>
- <height>21</height>
- </rect>
- </property>
- <property name="text">
- <string>Wallet Name</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="encrypt_wallet_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>50</y>
- <width>171</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string>
- </property>
- <property name="text">
- <string>Encrypt Wallet</string>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLabel" name="advanced_options_label">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>90</y>
- <width>130</width>
- <height>21</height>
- </rect>
- </property>
- <property name="styleSheet">
- <string notr="true">font-weight:bold;</string>
- </property>
- <property name="text">
- <string>Advanced options</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="disable_privkeys_checkbox">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>115</y>
- <width>171</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string>
- </property>
- <property name="text">
- <string>Disable Private Keys</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="blank_wallet_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>135</y>
- <width>220</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string>
- </property>
- <property name="text">
- <string>Make Blank Wallet</string>
- </property>
- </widget>
- <widget class="QCheckBox" name="descriptor_checkbox">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>155</y>
- <width>171</width>
- <height>22</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Use descriptors for scriptPubKey management</string>
- </property>
- <property name="text">
- <string>Descriptor Wallet</string>
- </property>
- </widget>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="wallet_name_label">
+ <property name="text">
+ <string>Wallet Name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="wallet_name_line_edit">
+ <property name="minimumSize">
+ <size>
+ <width>262</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="placeholderText">
+ <string>Wallet</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="encrypt_wallet_checkbox">
+ <property name="toolTip">
+ <string>Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</string>
+ </property>
+ <property name="text">
+ <string>Encrypt Wallet</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_1">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>8</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Advanced Options</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_groupbox">
+ <item>
+ <widget class="QCheckBox" name="disable_privkeys_checkbox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="toolTip">
+ <string>Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</string>
+ </property>
+ <property name="text">
+ <string>Disable Private Keys</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="blank_wallet_checkbox">
+ <property name="toolTip">
+ <string>Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</string>
+ </property>
+ <property name="text">
+ <string>Make Blank Wallet</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="descriptor_checkbox">
+ <property name="toolTip">
+ <string>Use descriptors for scriptPubKey management</string>
+ </property>
+ <property name="text">
+ <string>Descriptor Wallet</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
</widget>
<tabstops>
<tabstop>wallet_name_line_edit</tabstop>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 139c8e161e..3831852185 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1077,14 +1077,17 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLabel" name="label_23">
+ <widget class="QLabel" name="peerConnectionTypeLabel">
+ <property name="toolTip">
+ <string>The type of peer connection: %1</string>
+ </property>
<property name="text">
- <string>Direction</string>
+ <string>Connection Type</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QLabel" name="peerDirection">
+ <widget class="QLabel" name="peerConnectionType">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
@@ -1100,13 +1103,39 @@
</widget>
</item>
<item row="2" column="0">
+ <widget class="QLabel" name="peerNetworkLabel">
+ <property name="toolTip">
+ <string>The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</string>
+ </property>
+ <property name="text">
+ <string>Network</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="peerNetwork">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QLabel" name="peerVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1122,14 +1151,14 @@
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>User Agent</string>
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="4" column="1">
<widget class="QLabel" name="peerSubversion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1145,14 +1174,14 @@
</property>
</widget>
</item>
- <item row="4" column="0">
+ <item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Services</string>
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="5" column="1">
<widget class="QLabel" name="peerServices">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1168,14 +1197,14 @@
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
<string>Starting Block</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QLabel" name="peerHeight">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1191,14 +1220,14 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
<string>Synced Headers</string>
</property>
</widget>
</item>
- <item row="6" column="1">
+ <item row="7" column="1">
<widget class="QLabel" name="peerSyncHeight">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1214,14 +1243,14 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="label_25">
<property name="text">
<string>Synced Blocks</string>
</property>
</widget>
</item>
- <item row="7" column="1">
+ <item row="8" column="1">
<widget class="QLabel" name="peerCommonHeight">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1237,14 +1266,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Connection Time</string>
</property>
</widget>
</item>
- <item row="8" column="1">
+ <item row="9" column="1">
<widget class="QLabel" name="peerConnTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1260,14 +1289,14 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Last Send</string>
</property>
</widget>
</item>
- <item row="9" column="1">
+ <item row="10" column="1">
<widget class="QLabel" name="peerLastSend">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1283,14 +1312,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Last Receive</string>
</property>
</widget>
</item>
- <item row="10" column="1">
+ <item row="11" column="1">
<widget class="QLabel" name="peerLastRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1306,14 +1335,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Sent</string>
</property>
</widget>
</item>
- <item row="11" column="1">
+ <item row="12" column="1">
<widget class="QLabel" name="peerBytesSent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1329,14 +1358,14 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Received</string>
</property>
</widget>
</item>
- <item row="12" column="1">
+ <item row="13" column="1">
<widget class="QLabel" name="peerBytesRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1352,14 +1381,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Ping Time</string>
</property>
</widget>
</item>
- <item row="13" column="1">
+ <item row="14" column="1">
<widget class="QLabel" name="peerPingTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1375,7 +1404,7 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
<widget class="QLabel" name="peerPingWaitLabel">
<property name="toolTip">
<string>The duration of a currently outstanding ping.</string>
@@ -1385,7 +1414,7 @@
</property>
</widget>
</item>
- <item row="14" column="1">
+ <item row="15" column="1">
<widget class="QLabel" name="peerPingWait">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1401,14 +1430,14 @@
</property>
</widget>
</item>
- <item row="15" column="0">
+ <item row="16" column="0">
<widget class="QLabel" name="peerMinPingLabel">
<property name="text">
<string>Min Ping</string>
</property>
</widget>
</item>
- <item row="15" column="1">
+ <item row="16" column="1">
<widget class="QLabel" name="peerMinPing">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1424,14 +1453,14 @@
</property>
</widget>
</item>
- <item row="16" column="0">
+ <item row="17" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="16" column="1">
+ <item row="17" column="1">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1447,7 +1476,7 @@
</property>
</widget>
</item>
- <item row="17" column="0">
+ <item row="18" column="0">
<widget class="QLabel" name="peerMappedASLabel">
<property name="toolTip">
<string>The mapped Autonomous System used for diversifying peer selection.</string>
@@ -1457,7 +1486,7 @@
</property>
</widget>
</item>
- <item row="17" column="1">
+ <item row="18" column="1">
<widget class="QLabel" name="peerMappedAS">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1473,7 +1502,7 @@
</property>
</widget>
</item>
- <item row="18" column="0">
+ <item row="19" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 88944a58a6..8181cc47e2 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -260,6 +260,16 @@
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="mapPortNatpmp">
+ <property name="toolTip">
+ <string>Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</string>
+ </property>
+ <property name="text">
+ <string>Map port using NA&amp;T-PMP</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QCheckBox" name="allowIncoming">
<property name="toolTip">
<string>Accept connections from outside.</string>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 4d3f90c484..ee9d4a113c 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -504,7 +504,7 @@
</layout>
</item>
<item>
- <widget class="QListView" name="listTransactions">
+ <widget class="TransactionOverviewWidget" name="listTransactions">
<property name="styleSheet">
<string notr="true">QListView { background: transparent; }</string>
</property>
@@ -517,9 +517,15 @@
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
+ <property name="sizeAdjustPolicy">
+ <enum>QAbstractScrollArea::AdjustToContents</enum>
+ </property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
+ <property name="uniformItemSizes">
+ <bool>true</bool>
+ </property>
</widget>
</item>
</layout>
@@ -544,6 +550,13 @@
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>TransactionOverviewWidget</class>
+ <extends>QListView</extends>
+ <header>qt/transactionoverviewwidget.h</header>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 53ffb27f50..376acf0963 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -40,12 +40,14 @@
#include <QFontDatabase>
#include <QFontMetrics>
#include <QGuiApplication>
+#include <QJsonObject>
#include <QKeyEvent>
#include <QLineEdit>
#include <QList>
#include <QLocale>
#include <QMenu>
#include <QMouseEvent>
+#include <QPluginLoader>
#include <QProgressDialog>
#include <QScreen>
#include <QSettings>
@@ -655,7 +657,7 @@ bool SetStartOnSystemStartup(bool fAutoStart)
#elif defined(Q_OS_LINUX)
// Follow the Desktop Application Autostart Spec:
-// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
+// https://specifications.freedesktop.org/autostart-spec/autostart-spec-latest.html
fs::path static GetAutostartDir()
{
@@ -749,6 +751,34 @@ QString boostPathToQString(const fs::path &path)
return QString::fromStdString(path.string());
}
+QString NetworkToQString(Network net)
+{
+ switch (net) {
+ case NET_UNROUTABLE: return QObject::tr("Unroutable");
+ case NET_IPV4: return "IPv4";
+ case NET_IPV6: return "IPv6";
+ case NET_ONION: return "Onion";
+ case NET_I2P: return "I2P";
+ case NET_CJDNS: return "CJDNS";
+ case NET_INTERNAL: return QObject::tr("Internal");
+ case NET_MAX: assert(false);
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+}
+
+QString ConnectionTypeToQString(ConnectionType conn_type, bool relay_txes)
+{
+ switch (conn_type) {
+ case ConnectionType::INBOUND: return relay_txes ? QObject::tr("Inbound Full Relay") : QObject::tr("Inbound Block Relay");
+ case ConnectionType::OUTBOUND_FULL_RELAY: return QObject::tr("Outbound Full Relay");
+ case ConnectionType::BLOCK_RELAY: return QObject::tr("Outbound Block Relay");
+ case ConnectionType::MANUAL: return QObject::tr("Outbound Manual");
+ case ConnectionType::FEELER: return QObject::tr("Outbound Feeler");
+ case ConnectionType::ADDR_FETCH: return QObject::tr("Outbound Address Fetch");
+ } // no default case, so the compiler can warn about missing cases
+ assert(false);
+}
+
QString formatDurationStr(int secs)
{
QStringList strList;
@@ -908,6 +938,20 @@ void LogQtInfo()
const std::string plugin_link{"dynamic"};
#endif
LogPrintf("Qt %s (%s), plugin=%s (%s)\n", qVersion(), qt_link, QGuiApplication::platformName().toStdString(), plugin_link);
+ const auto static_plugins = QPluginLoader::staticPlugins();
+ if (static_plugins.empty()) {
+ LogPrintf("No static plugins.\n");
+ } else {
+ LogPrintf("Static plugins:\n");
+ for (const QStaticPlugin& p : static_plugins) {
+ QJsonObject meta_data = p.metaData();
+ const std::string plugin_class = meta_data.take(QString("className")).toString().toStdString();
+ const int plugin_version = meta_data.take(QString("version")).toInt();
+ LogPrintf(" %s, version %d\n", plugin_class, plugin_version);
+ }
+ }
+
+ LogPrintf("Style: %s / %s\n", QApplication::style()->objectName().toStdString(), QApplication::style()->metaObject()->className());
LogPrintf("System: %s, %s\n", QSysInfo::prettyProductName().toStdString(), QSysInfo::buildAbi().toStdString());
for (const QScreen* s : QGuiApplication::screens()) {
LogPrintf("Screen: %s %dx%d, pixel ratio=%.1f\n", s->name().toStdString(), s->size().width(), s->size().height(), s->devicePixelRatio());
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index d7bd124884..edfb5b13a2 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -7,16 +7,18 @@
#include <amount.h>
#include <fs.h>
+#include <net.h>
+#include <netaddress.h>
#include <QEvent>
#include <QHeaderView>
#include <QItemDelegate>
+#include <QLabel>
#include <QMessageBox>
#include <QObject>
#include <QProgressBar>
#include <QString>
#include <QTableView>
-#include <QLabel>
class QValidatedLineEdit;
class SendCoinsRecipient;
@@ -43,6 +45,9 @@ QT_END_NAMESPACE
*/
namespace GUIUtil
{
+ // Use this flags to prevent a "What's This" button in the title bar of the dialog on Windows.
+ constexpr auto dialog_flags = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
+
// Create human-readable string from date
QString dateTimeStr(const QDateTime &datetime);
QString dateTimeStr(qint64 nTime);
@@ -218,22 +223,28 @@ namespace GUIUtil
bool GetStartOnSystemStartup();
bool SetStartOnSystemStartup(bool fAutoStart);
- /* Convert QString to OS specific boost path through UTF-8 */
+ /** Convert QString to OS specific boost path through UTF-8 */
fs::path qstringToBoostPath(const QString &path);
- /* Convert OS specific boost path to QString through UTF-8 */
+ /** Convert OS specific boost path to QString through UTF-8 */
QString boostPathToQString(const fs::path &path);
- /* Convert seconds into a QString with days, hours, mins, secs */
+ /** Convert enum Network to QString */
+ QString NetworkToQString(Network net);
+
+ /** Convert enum ConnectionType to QString */
+ QString ConnectionTypeToQString(ConnectionType conn_type, bool relay_txes);
+
+ /** Convert seconds into a QString with days, hours, mins, secs */
QString formatDurationStr(int secs);
- /* Format CNodeStats.nServices bitmask into a user-readable string */
+ /** Format CNodeStats.nServices bitmask into a user-readable string */
QString formatServicesStr(quint64 mask);
- /* Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0*/
+ /** Format a CNodeStats.m_ping_usec into a user-readable string or display N/A, if 0 */
QString formatPingTime(int64_t ping_usec);
- /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */
+ /** Format a CNodeCombinedStats.nTimeOffset into a user-readable string */
QString formatTimeOffset(int64_t nTimeOffset);
QString formatNiceTimeOffset(qint64 secs);
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 235722d091..aa6b2665fa 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -119,7 +119,7 @@ int GetPruneTargetGB()
} // namespace
Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_size_gb) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::Intro),
thread(nullptr),
signalled(false),
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 7b07777641..1d8af5cbf6 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/notificator.cpp b/src/qt/notificator.cpp
index d518a2065c..b097ef080c 100644
--- a/src/qt/notificator.cpp
+++ b/src/qt/notificator.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -66,7 +66,7 @@ Notificator::~Notificator()
#ifdef USE_DBUS
-// Loosely based on http://www.qtcentre.org/archive/index.php/t-25879.html
+// Loosely based on https://www.qtcentre.org/archive/index.php/t-25879.html
class FreedesktopImage
{
public:
diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp
index 9a3d43c2a6..10bf82d532 100644
--- a/src/qt/openuridialog.cpp
+++ b/src/qt/openuridialog.cpp
@@ -11,7 +11,7 @@
#include <QUrl>
OpenURIDialog::OpenURIDialog(QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::OpenURIDialog)
{
ui->setupUi(this);
diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h
index 667af2ec75..efe4b86f37 100644
--- a/src/qt/openuridialog.h
+++ b/src/qt/openuridialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 78d4dd5557..7b8d7871ec 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -24,11 +24,12 @@
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>
+#include <QSettings>
#include <QSystemTrayIcon>
#include <QTimer>
OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::OptionsDialog),
model(nullptr),
mapper(nullptr)
@@ -50,6 +51,13 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
#ifndef USE_UPNP
ui->mapPortUpnp->setEnabled(false);
#endif
+#ifndef USE_NATPMP
+ ui->mapPortNatpmp->setEnabled(false);
+#endif
+ connect(this, &QDialog::accepted, [this](){
+ QSettings settings;
+ model->node().mapPort(settings.value("fUseUPnP").toBool(), settings.value("fUseNatpmp").toBool());
+ });
ui->proxyIp->setEnabled(false);
ui->proxyPort->setEnabled(false);
@@ -214,6 +222,7 @@ void OptionsDialog::setMapper()
/* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
+ mapper->addMapping(ui->mapPortNatpmp, OptionsModel::MapPortNatpmp);
mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index 3a7b9192a1..1cc96035c6 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 152de6decb..1e0391a35c 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -13,11 +13,12 @@
#include <qt/guiutil.h>
#include <interfaces/node.h>
-#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
+#include <mapport.h>
#include <net.h>
#include <netbase.h>
-#include <txdb.h> // for -dbcache defaults
+#include <txdb.h> // for -dbcache defaults
#include <util/string.h>
+#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
#include <QDebug>
#include <QSettings>
@@ -123,6 +124,13 @@ void OptionsModel::Init(bool resetSettings)
if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
addOverriddenOption("-upnp");
+ if (!settings.contains("fUseNatpmp")) {
+ settings.setValue("fUseNatpmp", DEFAULT_NATPMP);
+ }
+ if (!gArgs.SoftSetBoolArg("-natpmp", settings.value("fUseNatpmp").toBool())) {
+ addOverriddenOption("-natpmp");
+ }
+
if (!settings.contains("fListen"))
settings.setValue("fListen", DEFAULT_LISTEN);
if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
@@ -282,7 +290,13 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return settings.value("fUseUPnP");
#else
return false;
-#endif
+#endif // USE_UPNP
+ case MapPortNatpmp:
+#ifdef USE_NATPMP
+ return settings.value("fUseNatpmp");
+#else
+ return false;
+#endif // USE_NATPMP
case MinimizeOnClose:
return fMinimizeOnClose;
@@ -354,7 +368,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
break;
case MapPortUPnP: // core option - can be changed on-the-fly
settings.setValue("fUseUPnP", value.toBool());
- node().mapPort(value.toBool());
+ break;
+ case MapPortNatpmp: // core option - can be changed on-the-fly
+ settings.setValue("fUseNatpmp", value.toBool());
break;
case MinimizeOnClose:
fMinimizeOnClose = value.toBool();
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index f1929a5e06..f7171951a1 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -48,6 +48,7 @@ public:
ShowTrayIcon, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
+ MapPortNatpmp, // bool
MinimizeOnClose, // bool
ProxyUse, // bool
ProxyIP, // QString
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 1297eb8b75..bc542a0833 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -12,6 +12,7 @@
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/transactionfilterproxy.h>
+#include <qt/transactionoverviewwidget.h>
#include <qt/transactiontablemodel.h>
#include <qt/walletmodel.h>
@@ -21,6 +22,9 @@
#include <QPainter>
#include <QStatusTipEvent>
+#include <algorithm>
+#include <map>
+
#define DECORATION_SIZE 54
#define NUM_ITEMS 5
@@ -34,7 +38,7 @@ public:
QAbstractItemDelegate(parent), unit(BitcoinUnits::BTC),
platformStyle(_platformStyle)
{
-
+ connect(this, &TxViewDelegate::width_changed, this, &TxViewDelegate::sizeHintChanged);
}
inline void paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -67,13 +71,15 @@ public:
painter->setPen(foreground);
QRect boundingRect;
- painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect);
+ painter->drawText(addressRect, Qt::AlignLeft | Qt::AlignVCenter, address, &boundingRect);
+ int address_rect_min_width = boundingRect.width();
if (index.data(TransactionTableModel::WatchonlyRole).toBool())
{
QIcon iconWatchonly = qvariant_cast<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
iconWatchonly.paint(painter, watchonlyRect);
+ address_rect_min_width += 5 + watchonlyRect.width();
}
if(amount < 0)
@@ -94,23 +100,42 @@ public:
{
amountText = QString("[") + amountText + QString("]");
}
- painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText);
+
+ QRect amount_bounding_rect;
+ painter->drawText(amountRect, Qt::AlignRight | Qt::AlignVCenter, amountText, &amount_bounding_rect);
painter->setPen(option.palette.color(QPalette::Text));
- painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date));
+ QRect date_bounding_rect;
+ painter->drawText(amountRect, Qt::AlignLeft | Qt::AlignVCenter, GUIUtil::dateTimeStr(date), &date_bounding_rect);
+
+ const int minimum_width = std::max(address_rect_min_width, amount_bounding_rect.width() + date_bounding_rect.width());
+ const auto search = m_minimum_width.find(index.row());
+ if (search == m_minimum_width.end() || search->second != minimum_width) {
+ m_minimum_width[index.row()] = minimum_width;
+ Q_EMIT width_changed(index);
+ }
painter->restore();
}
inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
- return QSize(DECORATION_SIZE, DECORATION_SIZE);
+ const auto search = m_minimum_width.find(index.row());
+ const int minimum_text_width = search == m_minimum_width.end() ? 0 : search->second;
+ return {DECORATION_SIZE + 8 + minimum_text_width, DECORATION_SIZE};
}
int unit;
- const PlatformStyle *platformStyle;
+Q_SIGNALS:
+ //! An intermediate signal for emitting from the `paint() const` member function.
+ void width_changed(const QModelIndex& index) const;
+
+private:
+ const PlatformStyle* platformStyle;
+ mutable std::map<int, int> m_minimum_width;
};
+
#include <qt/overviewpage.moc>
OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
@@ -126,7 +151,6 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
// use a SingleColorIcon for the "out of sync warning" icon
QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
- icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
ui->labelTransactionsStatus->setIcon(icon);
ui->labelWalletStatus->setIcon(icon);
@@ -136,7 +160,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
- connect(ui->listTransactions, &QListView::clicked, this, &OverviewPage::handleTransactionClicked);
+ connect(ui->listTransactions, &TransactionOverviewWidget::clicked, this, &OverviewPage::handleTransactionClicked);
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 4cf673b6a6..578ef601fb 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 86d681aa6f..96f6202874 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index eaf2bafe59..08b83244ab 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 5220f8e138..bad81d894c 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -29,14 +29,16 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
return pLeft->nodeid < pRight->nodeid;
case PeerTableModel::Address:
return pLeft->addrName.compare(pRight->addrName) < 0;
- case PeerTableModel::Subversion:
- return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
+ case PeerTableModel::Network:
+ return pLeft->m_network < pRight->m_network;
case PeerTableModel::Ping:
return pLeft->m_min_ping_usec < pRight->m_min_ping_usec;
case PeerTableModel::Sent:
return pLeft->nSendBytes < pRight->nSendBytes;
case PeerTableModel::Received:
return pLeft->nRecvBytes < pRight->nRecvBytes;
+ case PeerTableModel::Subversion:
+ return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
}
return false;
@@ -104,7 +106,6 @@ PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
m_node(node),
timer(nullptr)
{
- columns << tr("NodeId") << tr("Node/Service") << tr("Ping") << tr("Sent") << tr("Received") << tr("User Agent");
priv.reset(new PeerTablePriv());
// set up timer for auto refresh
@@ -133,13 +134,17 @@ void PeerTableModel::stopAutoRefresh()
int PeerTableModel::rowCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return priv->size();
}
int PeerTableModel::columnCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return columns.length();
}
@@ -158,17 +163,21 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
case Address:
// prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
return QString(rec->nodeStats.fInbound ? "↓ " : "↑ ") + QString::fromStdString(rec->nodeStats.addrName);
- case Subversion:
- return QString::fromStdString(rec->nodeStats.cleanSubVer);
+ case Network:
+ return GUIUtil::NetworkToQString(rec->nodeStats.m_network);
case Ping:
return GUIUtil::formatPingTime(rec->nodeStats.m_min_ping_usec);
case Sent:
return GUIUtil::formatBytes(rec->nodeStats.nSendBytes);
case Received:
return GUIUtil::formatBytes(rec->nodeStats.nRecvBytes);
+ case Subversion:
+ return QString::fromStdString(rec->nodeStats.cleanSubVer);
}
} else if (role == Qt::TextAlignmentRole) {
switch (index.column()) {
+ case Network:
+ return QVariant(Qt::AlignCenter);
case Ping:
case Sent:
case Received:
@@ -176,6 +185,11 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
default:
return QVariant();
}
+ } else if (role == StatsRole) {
+ switch (index.column()) {
+ case NetNodeId: return QVariant::fromValue(rec);
+ default: return QVariant();
+ }
}
return QVariant();
@@ -211,11 +225,6 @@ QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent
return QModelIndex();
}
-const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
-{
- return priv->index(idx);
-}
-
void PeerTableModel::refresh()
{
Q_EMIT layoutAboutToBeChanged();
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index 99de772ac0..7bff239507 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -28,6 +28,7 @@ struct CNodeCombinedStats {
CNodeStateStats nodeStateStats;
bool fNodeStateStatsAvailable;
};
+Q_DECLARE_METATYPE(CNodeCombinedStats*)
class NodeLessThan
{
@@ -52,7 +53,6 @@ class PeerTableModel : public QAbstractTableModel
public:
explicit PeerTableModel(interfaces::Node& node, QObject* parent);
~PeerTableModel();
- const CNodeCombinedStats *getNodeStats(int idx);
int getRowByNodeId(NodeId nodeid);
void startAutoRefresh();
void stopAutoRefresh();
@@ -60,10 +60,15 @@ public:
enum ColumnIndex {
NetNodeId = 0,
Address = 1,
- Ping = 2,
- Sent = 3,
- Received = 4,
- Subversion = 5
+ Network = 2,
+ Ping = 3,
+ Sent = 4,
+ Received = 5,
+ Subversion = 6
+ };
+
+ enum {
+ StatsRole = Qt::UserRole,
};
/** @name Methods overridden from QAbstractTableModel
@@ -82,7 +87,7 @@ public Q_SLOTS:
private:
interfaces::Node& m_node;
- QStringList columns;
+ const QStringList columns{tr("Peer Id"), tr("Address"), tr("Network"), tr("Ping"), tr("Sent"), tr("Received"), tr("User Agent")};
std::unique_ptr<PeerTablePriv> priv;
QTimer *timer;
};
diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp
index 58167d4bb4..55ab6046cf 100644
--- a/src/qt/psbtoperationsdialog.cpp
+++ b/src/qt/psbtoperationsdialog.cpp
@@ -19,7 +19,7 @@
PSBTOperationsDialog::PSBTOperationsDialog(
- QWidget* parent, WalletModel* wallet_model, ClientModel* client_model) : QDialog(parent),
+ QWidget* parent, WalletModel* wallet_model, ClientModel* client_model) : QDialog(parent, GUIUtil::dialog_flags),
m_ui(new Ui::PSBTOperationsDialog),
m_wallet_model(wallet_model),
m_client_model(client_model)
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index 141f4abb3b..490826cbbb 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h
index a031bd7632..5dbba074a1 100644
--- a/src/qt/qrimagewidget.h
+++ b/src/qt/qrimagewidget.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h
index 2c72b2ecda..b32305f5e1 100644
--- a/src/qt/qvalidatedlineedit.h
+++ b/src/qt/qvalidatedlineedit.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index d374d610ee..0aea920c86 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <qt/forms/ui_receivecoinsdialog.h>
#include <qt/addresstablemodel.h>
+#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
@@ -21,7 +22,7 @@
#include <QTextDocument>
ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::ReceiveCoinsDialog),
columnResizingFixer(nullptr),
model(nullptr),
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 27455e2906..9b89bd6a8b 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index d385c42821..78ae5c07da 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,7 +19,7 @@
#endif
ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::ReceiveRequestDialog),
model(nullptr)
{
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 846478643d..c861680761 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 3e20368a36..18b913774b 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -36,15 +36,17 @@ RecentRequestsTableModel::~RecentRequestsTableModel()
int RecentRequestsTableModel::rowCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
-
+ if (parent.isValid()) {
+ return 0;
+ }
return list.length();
}
int RecentRequestsTableModel::columnCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
-
+ if (parent.isValid()) {
+ return 0;
+ }
return columns.length();
}
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index c0bd3461bb..b817b64e77 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/res/animation/makespinner.sh b/src/qt/res/animation/makespinner.sh
index 4fa8dadf86..83142f5034 100755
--- a/src/qt/res/animation/makespinner.sh
+++ b/src/qt/res/animation/makespinner.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 236c6e13d5..a252685d2f 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -16,9 +16,10 @@
#include <chainparams.h>
#include <interfaces/node.h>
#include <netbase.h>
-#include <rpc/server.h>
#include <rpc/client.h>
+#include <rpc/server.h>
#include <util/strencodings.h>
+#include <util/string.h>
#include <util/system.h>
#include <util/threadnames.h>
@@ -457,7 +458,21 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
move(QGuiApplication::primaryScreen()->availableGeometry().center() - frameGeometry().center());
}
- QChar nonbreaking_hyphen(8209);
+ ui->splitter->restoreState(settings.value("PeersTabSplitterSizes").toByteArray());
+
+ constexpr QChar nonbreaking_hyphen(8209);
+ const std::vector<QString> CONNECTION_TYPE_DOC{
+ tr("Inbound Full/Block Relay: initiated by peer"),
+ tr("Outbound Full Relay: default"),
+ tr("Outbound Block Relay: does not relay transactions or addresses"),
+ tr("Outbound Manual: added using RPC %1 or %2/%3 configuration options")
+ .arg("addnode")
+ .arg(QString(nonbreaking_hyphen) + "addnode")
+ .arg(QString(nonbreaking_hyphen) + "connect"),
+ tr("Outbound Feeler: short-lived, for testing addresses"),
+ tr("Outbound Address Fetch: short-lived, for soliciting addresses")};
+ const QString list{"<ul><li>" + Join(CONNECTION_TYPE_DOC, QString("</li><li>")) + "</li></ul>"};
+ ui->peerConnectionTypeLabel->setToolTip(ui->peerConnectionTypeLabel->toolTip().arg(list));
ui->dataDir->setToolTip(ui->dataDir->toolTip().arg(QString(nonbreaking_hyphen) + "datadir"));
ui->blocksDir->setToolTip(ui->blocksDir->toolTip().arg(QString(nonbreaking_hyphen) + "blocksdir"));
ui->openDebugLogfileButton->setToolTip(ui->openDebugLogfileButton->toolTip().arg(PACKAGE_NAME));
@@ -502,6 +517,7 @@ RPCConsole::~RPCConsole()
{
QSettings settings;
settings.setValue("RPCConsoleWindowGeometry", saveGeometry());
+ settings.setValue("PeersTabSplitterSizes", ui->splitter->saveState());
m_node.rpcUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
@@ -1018,11 +1034,9 @@ void RPCConsole::updateTrafficStats(quint64 totalBytesIn, quint64 totalBytesOut)
void RPCConsole::peerLayoutAboutToChange()
{
- QModelIndexList selected = ui->peerWidget->selectionModel()->selectedIndexes();
cachedNodeids.clear();
- for(int i = 0; i < selected.size(); i++)
- {
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.at(i).row());
+ for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) {
+ const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
cachedNodeids.append(stats->nodeStats.nodeid);
}
}
@@ -1081,18 +1095,16 @@ void RPCConsole::peerLayoutChanged()
void RPCConsole::updateDetailWidget()
{
- QModelIndexList selected_rows;
- auto selection_model = ui->peerWidget->selectionModel();
- if (selection_model) selected_rows = selection_model->selectedRows();
- if (!clientModel || !clientModel->getPeerTableModel() || selected_rows.size() != 1) {
+ const QList<QModelIndex> selected_peers = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
+ if (!clientModel || !clientModel->getPeerTableModel() || selected_peers.size() != 1) {
ui->detailWidget->hide();
ui->peerHeading->setText(tr("Select a peer to view detailed information."));
return;
}
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected_rows.first().row());
+ const auto stats = selected_peers.first().data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
// update the detail ui with latest node information
QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
- peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
+ peerAddrDetails += tr("(peer id: %1)").arg(QString::number(stats->nodeStats.nodeid));
if (!stats->nodeStats.addrLocal.empty())
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
@@ -1108,8 +1120,8 @@ void RPCConsole::updateDetailWidget()
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
- ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
- ui->peerHeight->setText(QString::number(stats->nodeStats.nStartingHeight));
+ ui->peerConnectionType->setText(GUIUtil::ConnectionTypeToQString(stats->nodeStats.m_conn_type, stats->nodeStats.fRelayTxes));
+ ui->peerNetwork->setText(GUIUtil::NetworkToQString(stats->nodeStats.m_network));
if (stats->nodeStats.m_permissionFlags == PF_NONE) {
ui->peerPermissions->setText(tr("N/A"));
} else {
@@ -1135,6 +1147,8 @@ void RPCConsole::updateDetailWidget()
ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
else
ui->peerCommonHeight->setText(tr("Unknown"));
+
+ ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height));
}
ui->detailWidget->show();
@@ -1200,19 +1214,9 @@ void RPCConsole::banSelectedNode(int bantime)
if (!clientModel)
return;
- // Get selected peer addresses
- QList<QModelIndex> nodes = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
- for(int i = 0; i < nodes.count(); i++)
- {
- // Get currently selected peer address
- NodeId id = nodes.at(i).data().toLongLong();
-
- // Get currently selected peer address
- int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(id);
- if (detailNodeRow < 0) return;
-
+ for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) {
// Find possible nodes, ban it and clear the selected node
- const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
+ const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
if (stats) {
m_node.ban(stats->nodeStats.addr, bantime);
m_node.disconnectByAddress(stats->nodeStats.addr);
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 8fea08ab5c..5f308dc36d 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index e765e643a3..611f3584c3 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -55,7 +55,7 @@ int getIndexForConfTarget(int target) {
}
SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::SendCoinsDialog),
clientModel(nullptr),
model(nullptr),
@@ -973,6 +973,9 @@ SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QStri
setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
setDefaultButton(QMessageBox::Cancel);
yesButton = button(QMessageBox::Yes);
+ if (confirmButtonText.isEmpty()) {
+ confirmButtonText = yesButton->text();
+ }
updateYesButton();
connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown);
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 8519f1f65b..4fc2f57cd6 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -115,7 +115,7 @@ class SendConfirmationDialog : public QMessageBox
Q_OBJECT
public:
- SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "Send", QWidget* parent = nullptr);
+ SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "", QWidget* parent = nullptr);
int exec() override;
private Q_SLOTS:
diff --git a/src/qt/sendcoinsrecipient.h b/src/qt/sendcoinsrecipient.h
index 6619faf417..01135cdfef 100644
--- a/src/qt/sendcoinsrecipient.h
+++ b/src/qt/sendcoinsrecipient.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 4835dd7954..2e7df60574 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -19,7 +19,7 @@
#include <QClipboard>
SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *_platformStyle, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::SignVerifyMessageDialog),
model(nullptr),
platformStyle(_platformStyle)
@@ -120,7 +120,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- const PKHash* pkhash = boost::get<PKHash>(&destination);
+ const PKHash* pkhash = std::get_if<PKHash>(&destination);
if (!pkhash) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h
index d33a2d038d..d98cb290a1 100644
--- a/src/qt/signverifymessagedialog.h
+++ b/src/qt/signverifymessagedialog.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 5796a6ef56..2292c01d6a 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -18,6 +18,8 @@
#include <util/system.h>
#include <util/translation.h>
+#include <functional>
+
#include <QApplication>
#include <QCloseEvent>
#include <QPainter>
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index d49fd87055..386039291c 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/addressbooktests.h b/src/qt/test/addressbooktests.h
index e6d24f202f..ab52206466 100644
--- a/src/qt/test/addressbooktests.h
+++ b/src/qt/test/addressbooktests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index a5c9138798..0d9928d363 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -33,7 +33,7 @@ static RPCHelpMan rpcNestedTest_rpc()
}
static const CRPCCommand vRPCCommands[] = {
- {"test", "rpcNestedTest", &rpcNestedTest_rpc, {"arg1", "arg2", "arg3"}},
+ {"test", &rpcNestedTest_rpc},
};
void RPCNestedTests::rpcNestedTests()
@@ -127,10 +127,10 @@ void RPCNestedTests::rpcNestedTests()
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
- (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackts
+ (RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo()()()")); //tolerate non command brackets
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "getblockchaininfo(True)"), UniValue); //invalid argument
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "a(getblockchaininfo(True))"), UniValue); //method not found
- QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
- QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
- QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tolerate empty arguments when using ,
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tolerate empty arguments when using ,
+ QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(m_node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tolerate empty arguments when using ,
}
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
index 320275129d..28dc7140e1 100644
--- a/src/qt/test/rpcnestedtests.h
+++ b/src/qt/test/rpcnestedtests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index 86356b43c8..9ef5fe8fc7 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp
index 759832381b..987d921f03 100644
--- a/src/qt/test/util.cpp
+++ b/src/qt/test/util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/util.h b/src/qt/test/util.h
index 950314da3b..df5931a032 100644
--- a/src/qt/test/util.h
+++ b/src/qt/test/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h
index dfca3370f7..6044bedb1d 100644
--- a/src/qt/test/wallettests.h
+++ b/src/qt/test/wallettests.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 6428fc4daf..dabdf9d887 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp
index 715e312b19..6f31d8463f 100644
--- a/src/qt/transactiondescdialog.cpp
+++ b/src/qt/transactiondescdialog.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,7 +11,7 @@
#include <QModelIndex>
TransactionDescDialog::TransactionDescDialog(const QModelIndex &idx, QWidget *parent) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::TransactionDescDialog)
{
ui->setupUi(this);
diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h
index d6bb84f7e6..693b363692 100644
--- a/src/qt/transactionfilterproxy.h
+++ b/src/qt/transactionfilterproxy.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionoverviewwidget.h b/src/qt/transactionoverviewwidget.h
new file mode 100644
index 0000000000..2bdead7bc4
--- /dev/null
+++ b/src/qt/transactionoverviewwidget.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
+#define BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
+
+#include <qt/transactiontablemodel.h>
+
+#include <QListView>
+#include <QSize>
+#include <QSizePolicy>
+
+QT_BEGIN_NAMESPACE
+class QShowEvent;
+class QWidget;
+QT_END_NAMESPACE
+
+class TransactionOverviewWidget : public QListView
+{
+ Q_OBJECT
+
+public:
+ explicit TransactionOverviewWidget(QWidget* parent = nullptr) : QListView(parent) {}
+
+ QSize sizeHint() const override
+ {
+ return {sizeHintForColumn(TransactionTableModel::ToAddress), QListView::sizeHint().height()};
+ }
+
+protected:
+ void showEvent(QShowEvent* event) override
+ {
+ Q_UNUSED(event);
+ QSizePolicy sp = sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Minimum);
+ setSizePolicy(sp);
+ }
+};
+
+#endif // BITCOIN_QT_TRANSACTIONOVERVIEWWIDGET_H
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 632a18de5c..77fec93f0f 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -123,7 +123,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
continue;
}
- if (!boost::get<CNoDestination>(&wtx.txout_address[nOut]))
+ if (!std::get_if<CNoDestination>(&wtx.txout_address[nOut]))
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h
index c983c527c0..e10243a28a 100644
--- a/src/qt/transactionrecord.h
+++ b/src/qt/transactionrecord.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 3148089b52..e6d483364c 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,6 +19,7 @@
#include <uint256.h>
#include <algorithm>
+#include <functional>
#include <QColor>
#include <QDateTime>
@@ -289,13 +290,17 @@ void TransactionTableModel::updateConfirmations()
int TransactionTableModel::rowCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return priv->size();
}
int TransactionTableModel::columnCount(const QModelIndex &parent) const
{
- Q_UNUSED(parent);
+ if (parent.isValid()) {
+ return 0;
+ }
return columns.length();
}
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 4b699d4d7d..f8576edd59 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index e14e22e9de..0cf6480b82 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 9ce7f4ad97..b268823066 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index b7f85446f4..05499b2a41 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -29,7 +29,7 @@
/** "Help message" or "About" dialog box */
HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
- QDialog(parent),
+ QDialog(parent, GUIUtil::dialog_flags),
ui(new Ui::HelpMessageDialog)
{
ui->setupUi(this);
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 83f3cccbff..7a89325ddf 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -152,7 +152,7 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
connect(wallet_model, &WalletModel::unload, this, [this, wallet_model] {
// Defer removeAndDeleteWallet when no modal widget is active.
- // TODO: remove this workaround by removing usage of QDiallog::exec.
+ // TODO: remove this workaround by removing usage of QDialog::exec.
if (QApplication::activeModalWidget()) {
connect(qApp, &QApplication::focusWindowChanged, wallet_model, [this, wallet_model]() {
if (!QApplication::activeModalWidget()) {
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 2edb7eff8a..02b3c62867 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -106,9 +106,24 @@ void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
if (mapWalletViews.count(wallet_model) == 0) return;
+ // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget.
+ WalletView* view_about_to_hide = currentWalletView();
+ if (view_about_to_hide) {
+ QSizePolicy sp = view_about_to_hide->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Ignored);
+ view_about_to_hide->setSizePolicy(sp);
+ }
+
WalletView *walletView = mapWalletViews.value(wallet_model);
- walletStack->setCurrentWidget(walletView);
assert(walletView);
+
+ // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously.
+ QSizePolicy sp = walletView->sizePolicy();
+ sp.setHorizontalPolicy(QSizePolicy::Preferred);
+ walletView->setSizePolicy(sp);
+ walletView->updateGeometry();
+
+ walletStack->setCurrentWidget(walletView);
walletView->updateEncryptionStatus();
}
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 271ddfc6c2..f57f8678d6 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index cad472b43b..58427b42cc 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -29,6 +29,7 @@
#include <wallet/wallet.h> // for CRecipient
#include <stdint.h>
+#include <functional>
#include <QDebug>
#include <QMessageBox>
@@ -514,6 +515,13 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
questionString.append("</td><td>");
questionString.append(BitcoinUnits::formatHtmlWithUnit(getOptionsModel()->getDisplayUnit(), new_fee));
questionString.append("</td></tr></table>");
+
+ // Display warning in the "Confirm fee bump" window if the "Coin Control Features" option is enabled
+ if (getOptionsModel()->getCoinControlFeatures()) {
+ questionString.append("<br><br>");
+ questionString.append(tr("Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy."));
+ }
+
SendConfirmationDialog confirmationDialog(tr("Confirm fee bump"), questionString);
confirmationDialog.exec();
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
diff --git a/src/rest.cpp b/src/rest.cpp
index 949cc9d84a..678ffdb760 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 57327e6004..e41a78f917 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -66,7 +66,7 @@ NodeContext& EnsureNodeContext(const util::Ref& context)
CTxMemPool& EnsureMemPool(const util::Ref& context)
{
- NodeContext& node = EnsureNodeContext(context);
+ const NodeContext& node = EnsureNodeContext(context);
if (!node.mempool) {
throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found");
}
@@ -75,7 +75,7 @@ CTxMemPool& EnsureMemPool(const util::Ref& context)
ChainstateManager& EnsureChainman(const util::Ref& context)
{
- NodeContext& node = EnsureNodeContext(context);
+ const NodeContext& node = EnsureNodeContext(context);
if (!node.chainman) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found");
}
@@ -172,16 +172,21 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
result.pushKV("versionHex", strprintf("%08x", block.nVersion));
result.pushKV("merkleroot", block.hashMerkleRoot.GetHex());
UniValue txs(UniValue::VARR);
- for(const auto& tx : block.vtx)
- {
- if(txDetails)
- {
+ if (txDetails) {
+ CBlockUndo blockUndo;
+ const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex);
+ for (size_t i = 0; i < block.vtx.size(); ++i) {
+ const CTransactionRef& tx = block.vtx.at(i);
+ // coinbase transaction (i == 0) doesn't have undo data
+ const CTxUndo* txundo = (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
UniValue objTx(UniValue::VOBJ);
- TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags());
+ TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo);
txs.push_back(objTx);
}
- else
+ } else {
+ for (const CTransactionRef& tx : block.vtx) {
txs.push_back(tx->GetHash().GetHex());
+ }
}
result.pushKV("tx", txs);
result.pushKV("time", block.GetBlockTime());
@@ -936,6 +941,7 @@ static RPCHelpMan getblock()
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
+ {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
}},
}},
}},
@@ -1277,7 +1283,7 @@ RPCHelpMan getblockchaininfo()
RPCResult{
RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::STR, "chain", "current network name (main, test, regtest)"},
+ {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"},
{RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
{RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
{RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
@@ -2393,10 +2399,10 @@ static RPCHelpMan dumptxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- fs::path path = fs::absolute(request.params[0].get_str(), GetDataDir());
+ const fs::path path = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str());
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption.
- fs::path temppath = fs::absolute(request.params[0].get_str() + ".incomplete", GetDataDir());
+ const fs::path temppath = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str() + ".incomplete");
if (fs::exists(path)) {
throw JSONRPCError(
@@ -2474,41 +2480,41 @@ void RegisterBlockchainRPCCommands(CRPCTable &t)
{
// clang-format off
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "blockchain", "getblockchaininfo", &getblockchaininfo, {} },
- { "blockchain", "getchaintxstats", &getchaintxstats, {"nblocks", "blockhash"} },
- { "blockchain", "getblockstats", &getblockstats, {"hash_or_height", "stats"} },
- { "blockchain", "getbestblockhash", &getbestblockhash, {} },
- { "blockchain", "getblockcount", &getblockcount, {} },
- { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
- { "blockchain", "getblockhash", &getblockhash, {"height"} },
- { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} },
- { "blockchain", "getchaintips", &getchaintips, {} },
- { "blockchain", "getdifficulty", &getdifficulty, {} },
- { "blockchain", "getmempoolancestors", &getmempoolancestors, {"txid","verbose"} },
- { "blockchain", "getmempooldescendants", &getmempooldescendants, {"txid","verbose"} },
- { "blockchain", "getmempoolentry", &getmempoolentry, {"txid"} },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, {} },
- { "blockchain", "getrawmempool", &getrawmempool, {"verbose", "mempool_sequence"} },
- { "blockchain", "gettxout", &gettxout, {"txid","n","include_mempool"} },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, {"hash_type"} },
- { "blockchain", "pruneblockchain", &pruneblockchain, {"height"} },
- { "blockchain", "savemempool", &savemempool, {} },
- { "blockchain", "verifychain", &verifychain, {"checklevel","nblocks"} },
-
- { "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
- { "blockchain", "scantxoutset", &scantxoutset, {"action", "scanobjects"} },
- { "blockchain", "getblockfilter", &getblockfilter, {"blockhash", "filtertype"} },
+{ // category actor (function)
+ // --------------------- ------------------------
+ { "blockchain", &getblockchaininfo, },
+ { "blockchain", &getchaintxstats, },
+ { "blockchain", &getblockstats, },
+ { "blockchain", &getbestblockhash, },
+ { "blockchain", &getblockcount, },
+ { "blockchain", &getblock, },
+ { "blockchain", &getblockhash, },
+ { "blockchain", &getblockheader, },
+ { "blockchain", &getchaintips, },
+ { "blockchain", &getdifficulty, },
+ { "blockchain", &getmempoolancestors, },
+ { "blockchain", &getmempooldescendants, },
+ { "blockchain", &getmempoolentry, },
+ { "blockchain", &getmempoolinfo, },
+ { "blockchain", &getrawmempool, },
+ { "blockchain", &gettxout, },
+ { "blockchain", &gettxoutsetinfo, },
+ { "blockchain", &pruneblockchain, },
+ { "blockchain", &savemempool, },
+ { "blockchain", &verifychain, },
+
+ { "blockchain", &preciousblock, },
+ { "blockchain", &scantxoutset, },
+ { "blockchain", &getblockfilter, },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
- { "hidden", "reconsiderblock", &reconsiderblock, {"blockhash"} },
- { "hidden", "waitfornewblock", &waitfornewblock, {"timeout"} },
- { "hidden", "waitforblock", &waitforblock, {"blockhash","timeout"} },
- { "hidden", "waitforblockheight", &waitforblockheight, {"height","timeout"} },
- { "hidden", "syncwithvalidationinterfacequeue", &syncwithvalidationinterfacequeue, {} },
- { "hidden", "dumptxoutset", &dumptxoutset, {"path"} },
+ { "hidden", &invalidateblock, },
+ { "hidden", &reconsiderblock, },
+ { "hidden", &waitfornewblock, },
+ { "hidden", &waitforblock, },
+ { "hidden", &waitforblockheight, },
+ { "hidden", &syncwithvalidationinterfacequeue, },
+ { "hidden", &dumptxoutset, },
};
// clang-format on
for (const auto& c : commands) {
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 91766aacc9..e4ce80400e 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 042005b9a6..d1eb849b7e 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -210,14 +210,9 @@ public:
CRPCConvertTable::CRPCConvertTable()
{
- const unsigned int n_elem =
- (sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));
-
- for (unsigned int i = 0; i < n_elem; i++) {
- members.insert(std::make_pair(vRPCConvertParams[i].methodName,
- vRPCConvertParams[i].paramIdx));
- membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName,
- vRPCConvertParams[i].paramName));
+ for (const auto& cp : vRPCConvertParams) {
+ members.emplace(cp.methodName, cp.paramIdx);
+ membersByName.emplace(cp.methodName, cp.paramName);
}
}
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 965b278bfa..c723f1d7ea 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -409,7 +409,7 @@ static RPCHelpMan getmininginfo()
{RPCResult::Type::NUM, "difficulty", "The current difficulty"},
{RPCResult::Type::NUM, "networkhashps", "The network hashes per second"},
{RPCResult::Type::NUM, "pooledtx", "The size of the mempool"},
- {RPCResult::Type::STR, "chain", "current network name (main, test, regtest)"},
+ {RPCResult::Type::STR, "chain", "current network name (main, test, signet, regtest)"},
{RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
}},
RPCExamples{
@@ -658,11 +658,15 @@ static RPCHelpMan getblocktemplate()
if(!node.connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
- throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
+ if (!Params().IsTestChain()) {
+ if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) {
+ throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
+ }
- if (::ChainstateActive().IsInitialBlockDownload())
- throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
+ if (::ChainstateActive().IsInitialBlockDownload()) {
+ throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
+ }
+ }
static unsigned int nTransactionsUpdatedLast;
const CTxMemPool& mempool = EnsureMemPool(request.context);
@@ -714,6 +718,13 @@ static RPCHelpMan getblocktemplate()
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+
+ // GBT must be called with 'signet' set in the rules for signet chains
+ if (consensusParams.signet_blocks && setClientRules.count("signet") != 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the signet rule set (call with {\"rules\": [\"segwit\", \"signet\"]})");
+ }
+
// GBT must be called with 'segwit' set in the rules
if (setClientRules.count("segwit") != 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "getblocktemplate must be called with the segwit rule set (call with {\"rules\": [\"segwit\"]})");
@@ -745,7 +756,6 @@ static RPCHelpMan getblocktemplate()
}
CHECK_NONFATAL(pindexPrev);
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
- const Consensus::Params& consensusParams = Params().GetConsensus();
// Update nTime
UpdateTime(pblock, consensusParams, pindexPrev);
@@ -809,6 +819,12 @@ static RPCHelpMan getblocktemplate()
UniValue aRules(UniValue::VARR);
aRules.push_back("csv");
if (!fPreSegWit) aRules.push_back("!segwit");
+ if (consensusParams.signet_blocks) {
+ // indicate to miner that they must understand signet rules
+ // when attempting to mine with this template
+ aRules.push_back("!signet");
+ }
+
UniValue vbavailable(UniValue::VOBJ);
for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
Consensus::DeploymentPos pos = Consensus::DeploymentPos(j);
@@ -889,6 +905,10 @@ static RPCHelpMan getblocktemplate()
result.pushKV("bits", strprintf("%08x", pblock->nBits));
result.pushKV("height", (int64_t)(pindexPrev->nHeight+1));
+ if (consensusParams.signet_blocks) {
+ result.pushKV("signet_challenge", HexStr(consensusParams.signet_challenge));
+ }
+
if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment));
}
@@ -1160,7 +1180,7 @@ static RPCHelpMan estimaterawfee()
UniValue result(UniValue::VOBJ);
- for (const FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) {
+ for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) {
CFeeRate feeRate;
EstimationResult buckets;
@@ -1212,24 +1232,24 @@ void RegisterMiningRPCCommands(CRPCTable &t)
{
// clang-format off
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "mining", "getnetworkhashps", &getnetworkhashps, {"nblocks","height"} },
- { "mining", "getmininginfo", &getmininginfo, {} },
- { "mining", "prioritisetransaction", &prioritisetransaction, {"txid","dummy","fee_delta"} },
- { "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
- { "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
- { "mining", "submitheader", &submitheader, {"hexdata"} },
+{ // category actor (function)
+ // --------------------- -----------------------
+ { "mining", &getnetworkhashps, },
+ { "mining", &getmininginfo, },
+ { "mining", &prioritisetransaction, },
+ { "mining", &getblocktemplate, },
+ { "mining", &submitblock, },
+ { "mining", &submitheader, },
- { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
- { "generating", "generatetodescriptor", &generatetodescriptor, {"num_blocks","descriptor","maxtries"} },
- { "generating", "generateblock", &generateblock, {"output","transactions"} },
+ { "generating", &generatetoaddress, },
+ { "generating", &generatetodescriptor, },
+ { "generating", &generateblock, },
- { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} },
+ { "util", &estimatesmartfee, },
- { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} },
- { "hidden", "generate", &generate, {} },
+ { "hidden", &estimaterawfee, },
+ { "hidden", &generate, },
};
// clang-format on
for (const auto& c : commands) {
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index b3102a236d..b75a7b8d26 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -39,13 +39,14 @@ static RPCHelpMan validateaddress()
RPCResult{
RPCResult::Type::OBJ, "", "",
{
- {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not. If not, this is the only property returned."},
+ {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
{RPCResult::Type::STR, "address", "The bitcoin address validated"},
{RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address"},
{RPCResult::Type::BOOL, "isscript", "If the key is a script"},
{RPCResult::Type::BOOL, "iswitness", "If the address is a witness address"},
{RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program"},
{RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program"},
+ {RPCResult::Type::STR, "error", /* optional */ true, "Error message, if any"},
}
},
RPCExamples{
@@ -54,13 +55,14 @@ static RPCHelpMan validateaddress()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
- bool isValid = IsValidDestination(dest);
+ std::string error_msg;
+ CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
+ const bool isValid = IsValidDestination(dest);
+ CHECK_NONFATAL(isValid == error_msg.empty());
UniValue ret(UniValue::VOBJ);
ret.pushKV("isvalid", isValid);
- if (isValid)
- {
+ if (isValid) {
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
@@ -69,7 +71,10 @@ static RPCHelpMan validateaddress()
UniValue detail = DescribeAddress(dest);
ret.pushKVs(detail);
+ } else {
+ ret.pushKV("error", error_msg);
}
+
return ret;
},
};
@@ -694,23 +699,23 @@ void RegisterMiscRPCCommands(CRPCTable &t)
{
// clang-format off
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} },
- { "control", "logging", &logging, {"include", "exclude"}},
- { "util", "validateaddress", &validateaddress, {"address"} },
- { "util", "createmultisig", &createmultisig, {"nrequired","keys","address_type"} },
- { "util", "deriveaddresses", &deriveaddresses, {"descriptor", "range"} },
- { "util", "getdescriptorinfo", &getdescriptorinfo, {"descriptor"} },
- { "util", "verifymessage", &verifymessage, {"address","signature","message"} },
- { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} },
- { "util", "getindexinfo", &getindexinfo, {"index_name"} },
+{ // category actor (function)
+ // --------------------- ------------------------
+ { "control", &getmemoryinfo, },
+ { "control", &logging, },
+ { "util", &validateaddress, },
+ { "util", &createmultisig, },
+ { "util", &deriveaddresses, },
+ { "util", &getdescriptorinfo, },
+ { "util", &verifymessage, },
+ { "util", &signmessagewithprivkey, },
+ { "util", &getindexinfo, },
/* Not shown in help */
- { "hidden", "setmocktime", &setmocktime, {"timestamp"}},
- { "hidden", "mockscheduler", &mockscheduler, {"delta_time"}},
- { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
- { "hidden", "echojson", &echojson, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
+ { "hidden", &setmocktime, },
+ { "hidden", &mockscheduler, },
+ { "hidden", &echo, },
+ { "hidden", &echojson, },
};
// clang-format on
for (const auto& c : commands) {
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 6a2d1ea77f..47d77b341a 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -5,6 +5,7 @@
#include <rpc/server.h>
#include <banman.h>
+#include <chainparams.h>
#include <clientversion.h>
#include <core_io.h>
#include <net.h>
@@ -128,21 +129,17 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},
{RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"},
{RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"},
- {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
- "(DEPRECATED, returned only if the config option -deprecatedrpc=getpeerinfo_addnode is passed)"},
- {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
- "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
- "best capture connection behaviors."},
{RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"},
- {RPCResult::Type::NUM, "banscore", "The ban score (DEPRECATED, returned only if config option -deprecatedrpc=banscore is passed)"},
{RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"},
{RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"},
{RPCResult::Type::ARR, "inflight", "",
{
{RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"},
}},
- {RPCResult::Type::BOOL, "whitelisted", /* optional */ true, "Whether the peer is whitelisted with default permissions\n"
- "(DEPRECATED, returned only if config option -deprecatedrpc=whitelisted is passed)"},
+ {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer",
+ {
+ {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"},
+ }},
{RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"},
{RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "",
{
@@ -157,6 +154,9 @@ static RPCHelpMan getpeerinfo()
"Only known message types can appear as keys in the object and all bytes received\n"
"of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."}
}},
+ {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n"
+ "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n"
+ "best capture connection behaviors."},
}},
}},
},
@@ -188,7 +188,7 @@ static RPCHelpMan getpeerinfo()
if (!(stats.addrLocal.empty())) {
obj.pushKV("addrlocal", stats.addrLocal);
}
- obj.pushKV("network", stats.m_network);
+ obj.pushKV("network", GetNetworkName(stats.m_network));
if (stats.m_mapped_as != 0) {
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
}
@@ -220,16 +220,8 @@ static RPCHelpMan getpeerinfo()
obj.pushKV("inbound", stats.fInbound);
obj.pushKV("bip152_hb_to", stats.m_bip152_highbandwidth_to);
obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from);
- if (IsDeprecatedRPCEnabled("getpeerinfo_addnode")) {
- // addnode is deprecated in v0.21 for removal in v0.22
- obj.pushKV("addnode", stats.m_manual_connection);
- }
- obj.pushKV("startingheight", stats.nStartingHeight);
if (fStateStats) {
- if (IsDeprecatedRPCEnabled("banscore")) {
- // banscore is deprecated in v0.21 for removal in v0.22
- obj.pushKV("banscore", statestats.m_misbehavior_score);
- }
+ obj.pushKV("startingheight", statestats.m_starting_height);
obj.pushKV("synced_headers", statestats.nSyncHeight);
obj.pushKV("synced_blocks", statestats.nCommonHeight);
UniValue heights(UniValue::VARR);
@@ -238,10 +230,6 @@ static RPCHelpMan getpeerinfo()
}
obj.pushKV("inflight", heights);
}
- if (IsDeprecatedRPCEnabled("whitelisted")) {
- // whitelisted is deprecated in v0.21 for removal in v0.22
- obj.pushKV("whitelisted", stats.m_legacyWhitelisted);
- }
UniValue permissions(UniValue::VARR);
for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) {
permissions.push_back(permission);
@@ -262,7 +250,7 @@ static RPCHelpMan getpeerinfo()
recvPerMsgCmd.pushKV(i.first, i.second);
}
obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd);
- obj.pushKV("connection_type", stats.m_conn_type_string);
+ obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type));
ret.push_back(obj);
}
@@ -327,6 +315,61 @@ static RPCHelpMan addnode()
};
}
+static RPCHelpMan addconnection()
+{
+ return RPCHelpMan{"addconnection",
+ "\nOpen an outbound connection to a specified node. This RPC is for testing only.\n",
+ {
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."},
+ {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open, either \"outbound-full-relay\" or \"block-relay-only\"."},
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ { RPCResult::Type::STR, "address", "Address of newly added connection." },
+ { RPCResult::Type::STR, "connection_type", "Type of connection opened." },
+ }},
+ RPCExamples{
+ HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"")
+ + HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ if (Params().NetworkIDString() != CBaseChainParams::REGTEST) {
+ throw std::runtime_error("addconnection is for regression testing (-regtest mode) only.");
+ }
+
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR});
+ const std::string address = request.params[0].get_str();
+ const std::string conn_type_in{TrimString(request.params[1].get_str())};
+ ConnectionType conn_type{};
+ if (conn_type_in == "outbound-full-relay") {
+ conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
+ } else if (conn_type_in == "block-relay-only") {
+ conn_type = ConnectionType::BLOCK_RELAY;
+ } else {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());
+ }
+
+ NodeContext& node = EnsureNodeContext(request.context);
+ if (!node.connman) {
+ throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled.");
+ }
+
+ const bool success = node.connman->AddConnection(address, conn_type);
+ if (!success) {
+ throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type.");
+ }
+
+ UniValue info(UniValue::VOBJ);
+ info.pushKV("address", address);
+ info.pushKV("connection_type", conn_type_in);
+
+ return info;
+},
+ };
+}
+
static RPCHelpMan disconnectnode()
{
return RPCHelpMan{"disconnectnode",
@@ -898,22 +941,24 @@ void RegisterNetRPCCommands(CRPCTable &t)
{
// clang-format off
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "network", "getconnectioncount", &getconnectioncount, {} },
- { "network", "ping", &ping, {} },
- { "network", "getpeerinfo", &getpeerinfo, {} },
- { "network", "addnode", &addnode, {"node","command"} },
- { "network", "disconnectnode", &disconnectnode, {"address", "nodeid"} },
- { "network", "getaddednodeinfo", &getaddednodeinfo, {"node"} },
- { "network", "getnettotals", &getnettotals, {} },
- { "network", "getnetworkinfo", &getnetworkinfo, {} },
- { "network", "setban", &setban, {"subnet", "command", "bantime", "absolute"} },
- { "network", "listbanned", &listbanned, {} },
- { "network", "clearbanned", &clearbanned, {} },
- { "network", "setnetworkactive", &setnetworkactive, {"state"} },
- { "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
- { "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },
+{ // category actor
+ // --------------------- -----------------------
+ { "network", &getconnectioncount, },
+ { "network", &ping, },
+ { "network", &getpeerinfo, },
+ { "network", &addnode, },
+ { "network", &disconnectnode, },
+ { "network", &getaddednodeinfo, },
+ { "network", &getnettotals, },
+ { "network", &getnetworkinfo, },
+ { "network", &setban, },
+ { "network", &listbanned, },
+ { "network", &clearbanned, },
+ { "network", &setnetworkactive, },
+ { "network", &getnodeaddresses, },
+
+ { "hidden", &addconnection, },
+ { "hidden", &addpeeraddress, },
};
// clang-format on
for (const auto& c : commands) {
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index d1475f452d..fc00a1efad 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -62,6 +62,7 @@ enum RPCErrorCode
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
+ RPC_CLIENT_NODE_CAPACITY_REACHED= -34, //!< Max number of outbound or block-relay connections already open
//! Chain errors
RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found
@@ -78,6 +79,7 @@ enum RPCErrorCode
RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
RPC_WALLET_NOT_FOUND = -18, //!< Invalid wallet specified
RPC_WALLET_NOT_SPECIFIED = -19, //!< No wallet specified (error when there are multiple wallets loaded)
+ RPC_WALLET_ALREADY_LOADED = -35, //!< This same wallet is already loaded
//! Backwards compatible aliases
RPC_WALLET_INVALID_ACCOUNT_NAME = RPC_WALLET_INVALID_LABEL_NAME,
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index f6ddaf379b..031ed31da1 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -109,7 +109,7 @@ static RPCHelpMan getrawtransaction()
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "The transaction id"},
- {RPCResult::Type::STR, "vout", ""},
+ {RPCResult::Type::NUM, "vout", "The output number"},
{RPCResult::Type::OBJ, "scriptSig", "The script",
{
{RPCResult::Type::STR, "asm", "asm"},
@@ -894,6 +894,7 @@ static RPCHelpMan testmempoolaccept()
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
+ {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
{RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"},
{RPCResult::Type::NUM, "vsize", "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
{RPCResult::Type::OBJ, "fees", "Transaction fees (only present if 'allowed' is true)",
@@ -930,7 +931,6 @@ static RPCHelpMan testmempoolaccept()
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
}
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
- const uint256& tx_hash = tx->GetHash();
const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
DEFAULT_MAX_RAW_TX_FEE_RATE :
@@ -942,7 +942,8 @@ static RPCHelpMan testmempoolaccept()
UniValue result(UniValue::VARR);
UniValue result_0(UniValue::VOBJ);
- result_0.pushKV("txid", tx_hash.GetHex());
+ result_0.pushKV("txid", tx->GetHash().GetHex());
+ result_0.pushKV("wtxid", tx->GetWitnessHash().GetHex());
TxValidationState state;
bool test_accept_res;
@@ -1858,27 +1859,27 @@ void RegisterRawTransactionRPCCommands(CRPCTable &t)
{
// clang-format off
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} },
- { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring","iswitness"} },
- { "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","maxfeerate"} },
- { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
- { "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
- { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","maxfeerate"} },
- { "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
- { "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} },
- { "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
- { "rawtransactions", "createpsbt", &createpsbt, {"inputs","outputs","locktime","replaceable"} },
- { "rawtransactions", "converttopsbt", &converttopsbt, {"hexstring","permitsigdata","iswitness"} },
- { "rawtransactions", "utxoupdatepsbt", &utxoupdatepsbt, {"psbt", "descriptors"} },
- { "rawtransactions", "joinpsbts", &joinpsbts, {"txs"} },
- { "rawtransactions", "analyzepsbt", &analyzepsbt, {"psbt"} },
-
- { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} },
- { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} },
+{ // category actor (function)
+ // --------------------- -----------------------
+ { "rawtransactions", &getrawtransaction, },
+ { "rawtransactions", &createrawtransaction, },
+ { "rawtransactions", &decoderawtransaction, },
+ { "rawtransactions", &decodescript, },
+ { "rawtransactions", &sendrawtransaction, },
+ { "rawtransactions", &combinerawtransaction, },
+ { "rawtransactions", &signrawtransactionwithkey, },
+ { "rawtransactions", &testmempoolaccept, },
+ { "rawtransactions", &decodepsbt, },
+ { "rawtransactions", &combinepsbt, },
+ { "rawtransactions", &finalizepsbt, },
+ { "rawtransactions", &createpsbt, },
+ { "rawtransactions", &converttopsbt, },
+ { "rawtransactions", &utxoupdatepsbt, },
+ { "rawtransactions", &joinpsbts, },
+ { "rawtransactions", &analyzepsbt, },
+
+ { "blockchain", &gettxoutproof, },
+ { "blockchain", &verifytxoutproof, },
};
// clang-format on
for (const auto& c : commands) {
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index d9ad70fa37..a7866474e1 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/request.h b/src/rpc/request.h
index 1241d999a8..de3a4ae840 100644
--- a/src/rpc/request.h
+++ b/src/rpc/request.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index f32d9abac6..9a9b3713f3 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -144,8 +144,13 @@ static RPCHelpMan help()
[&](const RPCHelpMan& self, const JSONRPCRequest& jsonRequest) -> UniValue
{
std::string strCommand;
- if (jsonRequest.params.size() > 0)
+ if (jsonRequest.params.size() > 0) {
strCommand = jsonRequest.params[0].get_str();
+ }
+ if (strCommand == "dump_all_command_conversions") {
+ // Used for testing only, undocumented
+ return tableRPC.dumpArgMap();
+ }
return tableRPC.help(strCommand, jsonRequest);
},
@@ -244,13 +249,13 @@ static RPCHelpMan getrpcinfo()
// clang-format off
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
+{ // category actor (function)
+ // --------------------- -----------------------
/* Overall control/query calls */
- { "control", "getrpcinfo", &getrpcinfo, {} },
- { "control", "help", &help, {"command"} },
- { "control", "stop", &stop, {"wait"} },
- { "control", "uptime", &uptime, {} },
+ { "control", &getrpcinfo, },
+ { "control", &help, },
+ { "control", &stop, },
+ { "control", &uptime, },
};
// clang-format on
@@ -479,6 +484,18 @@ std::vector<std::string> CRPCTable::listCommands() const
return commandList;
}
+UniValue CRPCTable::dumpArgMap() const
+{
+ UniValue ret{UniValue::VARR};
+ for (const auto& cmd : mapCommands) {
+ for (const auto& c : cmd.second) {
+ const auto help = RpcMethodFnType(c->unique_id)();
+ help.AppendArgMap(ret);
+ }
+ }
+ return ret;
+}
+
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
{
if (!timerInterface)
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 7d13edb8b0..fe5a791e1e 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -103,7 +103,7 @@ public:
}
//! Simplified constructor taking plain RpcMethodFnType function pointer.
- CRPCCommand(std::string category, std::string name_in, RpcMethodFnType fn, std::vector<std::string> args_in)
+ CRPCCommand(std::string category, RpcMethodFnType fn)
: CRPCCommand(
category,
fn().m_name,
@@ -111,8 +111,6 @@ public:
fn().GetArgNames(),
intptr_t(fn))
{
- CHECK_NONFATAL(fn().m_name == name_in);
- CHECK_NONFATAL(fn().GetArgNames() == args_in);
}
std::string category;
@@ -147,6 +145,10 @@ public:
*/
std::vector<std::string> listCommands() const;
+ /**
+ * Return all named arguments that need to be converted by the client from string to another JSON type
+ */
+ UniValue dumpArgMap() const;
/**
* Appends a CRPCCommand to the dispatch table.
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 1b21587b6d..bfdba5253c 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -209,7 +209,7 @@ CTxDestination AddAndGetMultisigDestination(const int required, const std::vecto
return dest;
}
-class DescribeAddressVisitor : public boost::static_visitor<UniValue>
+class DescribeAddressVisitor
{
public:
explicit DescribeAddressVisitor() {}
@@ -267,7 +267,7 @@ public:
UniValue DescribeAddress(const CTxDestination& dest)
{
- return boost::apply_visitor(DescribeAddressVisitor(), dest);
+ return std::visit(DescribeAddressVisitor(), dest);
}
unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)
@@ -549,6 +549,24 @@ std::string RPCHelpMan::ToString() const
return ret;
}
+void RPCHelpMan::AppendArgMap(UniValue& arr) const
+{
+ for (int i{0}; i < int(m_args.size()); ++i) {
+ const auto& arg = m_args.at(i);
+ std::vector<std::string> arg_names;
+ boost::split(arg_names, arg.m_names, boost::is_any_of("|"));
+ for (const auto& arg_name : arg_names) {
+ UniValue map{UniValue::VARR};
+ map.push_back(m_name);
+ map.push_back(i);
+ map.push_back(arg_name);
+ map.push_back(arg.m_type == RPCArg::Type::STR ||
+ arg.m_type == RPCArg::Type::STR_HEX);
+ arr.push_back(map);
+ }
+ }
+}
+
std::string RPCArg::GetFirstName() const
{
return m_names.substr(0, m_names.find("|"));
@@ -562,10 +580,10 @@ std::string RPCArg::GetName() const
bool RPCArg::IsOptional() const
{
- if (m_fallback.which() == 1) {
+ if (m_fallback.index() == 1) {
return true;
} else {
- return RPCArg::Optional::NO != boost::get<RPCArg::Optional>(m_fallback);
+ return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback);
}
}
@@ -609,10 +627,10 @@ std::string RPCArg::ToDescriptionString() const
}
} // no default case, so the compiler can warn about missing cases
}
- if (m_fallback.which() == 1) {
- ret += ", optional, default=" + boost::get<std::string>(m_fallback);
+ if (m_fallback.index() == 1) {
+ ret += ", optional, default=" + std::get<std::string>(m_fallback);
} else {
- switch (boost::get<RPCArg::Optional>(m_fallback)) {
+ switch (std::get<RPCArg::Optional>(m_fallback)) {
case RPCArg::Optional::OMITTED: {
// nothing to do. Element is treated as if not present and has no default value
break;
diff --git a/src/rpc/util.h b/src/rpc/util.h
index 45b0bb0c7e..444a013ca1 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2020 The Bitcoin Core developers
+// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,10 +19,9 @@
#include <util/check.h>
#include <string>
+#include <variant>
#include <vector>
-#include <boost/variant.hpp>
-
/**
* String used to describe UNIX epoch time in documentation, factored out to a
* constant for consistency.
@@ -144,7 +143,7 @@ struct RPCArg {
*/
OMITTED,
};
- using Fallback = boost::variant<Optional, /* default value for optional args */ std::string>;
+ using Fallback = std::variant<Optional, /* default value for optional args */ std::string>;
const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
const Type m_type;
const bool m_hidden;
@@ -337,6 +336,8 @@ public:
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun);
std::string ToString() const;
+ /** Append the named args that need to be converted from string to another JSON type */
+ void AppendArgMap(UniValue& arr) const;
UniValue HandleRequest(const JSONRPCRequest& request)
{
Check(request);
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index 7c361bf26f..b3ee23f139 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -7,6 +7,7 @@
#include <random.h>
#include <assert.h>
+#include <functional>
#include <utility>
CScheduler::CScheduler()
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp
index 15e204062f..76609f01a7 100644
--- a/src/script/bitcoinconsensus.cpp
+++ b/src/script/bitcoinconsensus.cpp
@@ -16,8 +16,7 @@ namespace {
class TxInputStream
{
public:
- TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) :
- m_type(nTypeIn),
+ TxInputStream(int nVersionIn, const unsigned char *txTo, size_t txToLen) :
m_version(nVersionIn),
m_data(txTo),
m_remaining(txToLen)
@@ -47,9 +46,7 @@ public:
}
int GetVersion() const { return m_version; }
- int GetType() const { return m_type; }
private:
- const int m_type;
const int m_version;
const unsigned char* m_data;
size_t m_remaining;
@@ -84,7 +81,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
return set_error(err, bitcoinconsensus_ERR_INVALID_FLAGS);
}
try {
- TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
+ TxInputStream stream(PROTOCOL_VERSION, txTo, txToLen);
CTransaction tx(deserialize, stream);
if (nIn >= tx.vin.size())
return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index e5ba9ba6d2..9e4b8a9dd6 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -565,7 +565,7 @@ public:
Optional<OutputType> GetOutputType() const override
{
- switch (m_destination.which()) {
+ switch (m_destination.index()) {
case 1 /* PKHash */:
case 2 /* ScriptHash */: return OutputType::LEGACY;
case 3 /* WitnessV0ScriptHash */:
@@ -593,7 +593,7 @@ public:
{
CTxDestination dest;
ExtractDestination(m_script, dest);
- switch (dest.which()) {
+ switch (dest.index()) {
case 1 /* PKHash */:
case 2 /* ScriptHash */: return OutputType::LEGACY;
case 3 /* WitnessV0ScriptHash */:
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index bb5a7158a5..ecac3b9e7e 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -305,8 +305,8 @@ private:
uint32_t m_first_false_pos = NO_FALSE;
public:
- bool empty() { return m_stack_size == 0; }
- bool all_true() { return m_first_false_pos == NO_FALSE; }
+ bool empty() const { return m_stack_size == 0; }
+ bool all_true() const { return m_first_false_pos == NO_FALSE; }
void push_back(bool f)
{
if (m_first_false_pos == NO_FALSE && !f) {
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index c0c2b012c6..b4c163c841 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/keyorigin.h b/src/script/keyorigin.h
index a318ff0f9d..210395d177 100644
--- a/src/script/keyorigin.h
+++ b/src/script/keyorigin.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/script.cpp b/src/script/script.cpp
index f31472e42d..9a6419088b 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/script_error.h b/src/script/script_error.h
index b071681613..44e68fe0fa 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 582341bd3e..2bfe206597 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 00534f9758..bf0ba38c2d 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -8,6 +8,7 @@
#include <script/interpreter.h>
#include <span.h>
+#include <util/hasher.h>
#include <vector>
@@ -20,27 +21,6 @@ static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;
class CPubKey;
-/**
- * We're hashing a nonce into the entries themselves, so we don't need extra
- * blinding in the set hash computation.
- *
- * This may exhibit platform endian dependent behavior but because these are
- * nonced hashes (random) and this state is only ever used locally it is safe.
- * All that matters is local consistency.
- */
-class SignatureCacheHasher
-{
-public:
- template <uint8_t hash_select>
- uint32_t operator()(const uint256& key) const
- {
- static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
- uint32_t u;
- std::memcpy(&u, key.begin()+4*hash_select, 4);
- return u;
- }
-};
-
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
{
private:
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 0e6864d547..8afbe9ebed 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -388,7 +388,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
{
assert(nIn < txTo.vin.size());
- CTxIn& txin = txTo.vin[nIn];
+ const CTxIn& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n];
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp
index 2d8dc7d471..9781ec32af 100644
--- a/src/script/signingprovider.cpp
+++ b/src/script/signingprovider.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -179,18 +179,18 @@ CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination&
{
// Only supports destinations which map to single public keys, i.e. P2PKH,
// P2WPKH, and P2SH-P2WPKH.
- if (auto id = boost::get<PKHash>(&dest)) {
+ if (auto id = std::get_if<PKHash>(&dest)) {
return ToKeyID(*id);
}
- if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
+ if (auto witness_id = std::get_if<WitnessV0KeyHash>(&dest)) {
return ToKeyID(*witness_id);
}
- if (auto script_hash = boost::get<ScriptHash>(&dest)) {
+ if (auto script_hash = std::get_if<ScriptHash>(&dest)) {
CScript script;
CScriptID script_id(*script_hash);
CTxDestination inner_dest;
if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
- if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
+ if (auto inner_witness_id = std::get_if<WitnessV0KeyHash>(&inner_dest)) {
return ToKeyID(*inner_witness_id);
}
}
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index f2f81664f6..7967c01858 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -261,9 +261,8 @@ bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::v
return true;
}
-namespace
-{
-class CScriptVisitor : public boost::static_visitor<CScript>
+namespace {
+class CScriptVisitor
{
public:
CScript operator()(const CNoDestination& dest) const
@@ -300,7 +299,7 @@ public:
CScript GetScriptForDestination(const CTxDestination& dest)
{
- return boost::apply_visitor(CScriptVisitor(), dest);
+ return std::visit(CScriptVisitor(), dest);
}
CScript GetScriptForRawPubKey(const CPubKey& pubKey)
@@ -320,5 +319,5 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
}
bool IsValidDestination(const CTxDestination& dest) {
- return dest.which() != 0;
+ return dest.index() != 0;
}
diff --git a/src/script/standard.h b/src/script/standard.h
index 4d1ef61964..d5d87392ad 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -9,10 +9,8 @@
#include <script/interpreter.h>
#include <uint256.h>
-#include <boost/variant.hpp>
-
#include <string>
-
+#include <variant>
static const bool DEFAULT_ACCEPT_DATACARRIER = true;
@@ -211,7 +209,7 @@ struct WitnessUnknown
* (taproot outputs do not require their own type as long as no wallet support exists)
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
-typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
+using CTxDestination = std::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown>;
/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);
diff --git a/src/shutdown.cpp b/src/shutdown.cpp
index a3321a6106..df5f996022 100644
--- a/src/shutdown.cpp
+++ b/src/shutdown.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/shutdown.h b/src/shutdown.h
index 23f84179e9..b2fbdb8cfb 100644
--- a/src/shutdown.h
+++ b/src/shutdown.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/streams.h b/src/streams.h
index c22f5936fd..fce411d3df 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/support/lockedpool.cpp b/src/support/lockedpool.cpp
index 26de780f29..6965f40253 100644
--- a/src/support/lockedpool.cpp
+++ b/src/support/lockedpool.cpp
@@ -65,7 +65,7 @@ void* Arena::alloc(size_t size)
// Pick a large enough free-chunk. Returns an iterator pointing to the first element that is not less than key.
// This allocation strategy is best-fit. According to "Dynamic Storage Allocation: A Survey and Critical Review",
- // Wilson et. al. 1995, http://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
+ // Wilson et. al. 1995, https://www.scs.stanford.edu/14wi-cs140/sched/readings/wilson.pdf, best-fit and first-fit
// policies seem to work well in practice.
auto size_ptr_it = size_to_free_chunk.lower_bound(size);
if (size_ptr_it == size_to_free_chunk.end())
diff --git a/src/support/lockedpool.h b/src/support/lockedpool.h
index b9e2e99d1a..03e4e371a3 100644
--- a/src/support/lockedpool.h
+++ b/src/support/lockedpool.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/sync.cpp b/src/sync.cpp
index acfbe8fe29..a2b62c2286 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -13,8 +13,6 @@
#include <util/strencodings.h>
#include <util/threadnames.h>
-#include <boost/thread/mutex.hpp>
-
#include <map>
#include <mutex>
#include <set>
@@ -224,7 +222,6 @@ template void EnterCritical(const char*, const char*, int, Mutex*, bool);
template void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool);
template void EnterCritical(const char*, const char*, int, std::mutex*, bool);
template void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool);
-template void EnterCritical(const char*, const char*, int, boost::mutex*, bool);
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)
{
diff --git a/src/sync.h b/src/sync.h
index 749bf5575c..53213c2089 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -258,7 +258,22 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove
//!
//! int val = WITH_LOCK(cs, return shared_val);
//!
-#define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
+//! Note:
+//!
+//! Since the return type deduction follows that of decltype(auto), while the
+//! deduced type of:
+//!
+//! WITH_LOCK(cs, return {int i = 1; return i;});
+//!
+//! is int, the deduced type of:
+//!
+//! WITH_LOCK(cs, return {int j = 1; return (j);});
+//!
+//! is &int, a reference to a local variable
+//!
+//! The above is detectable at compile-time with the -Wreturn-local-addr flag in
+//! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.
+#define WITH_LOCK(cs, code) [&]() -> decltype(auto) { LOCK(cs); code; }()
class CSemaphore
{
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index c16519a6b1..1a39498899 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index e55d6b3b19..dd760fe999 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 14cf1a4a76..9dfbd7ba7c 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
index 178c261365..8eb4dbc592 100644
--- a/src/test/blockfilter_tests.cpp
+++ b/src/test/blockfilter_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 8348810ac1..76d6727044 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -26,7 +26,7 @@ static const unsigned int QUEUE_BATCH_SIZE = 128;
static const int SCRIPT_CHECK_THREADS = 3;
struct FakeCheck {
- bool operator()()
+ bool operator()() const
{
return true;
}
@@ -47,7 +47,7 @@ struct FailingCheck {
bool fails;
FailingCheck(bool _fails) : fails(_fails){};
FailingCheck() : fails(true){};
- bool operator()()
+ bool operator()() const
{
return !fails;
}
@@ -76,7 +76,7 @@ struct UniqueCheck {
struct MemoryCheck {
static std::atomic<size_t> fake_allocated_memory;
bool b {false};
- bool operator()()
+ bool operator()() const
{
return true;
}
@@ -107,7 +107,7 @@ struct FrozenCleanupCheck {
// Freezing can't be the default initialized behavior given how the queue
// swaps in default initialized Checks.
bool should_freeze {false};
- bool operator()()
+ bool operator()() const
{
return true;
}
@@ -148,10 +148,7 @@ typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;
static void Correct_Queue_range(std::vector<size_t> range)
{
auto small_queue = MakeUnique<Correct_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{small_queue->Thread();});
- }
+ small_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
// Make vChecks here to save on malloc (this test can be slow...)
std::vector<FakeCheckCheckCompletion> vChecks;
for (const size_t i : range) {
@@ -168,8 +165,7 @@ static void Correct_Queue_range(std::vector<size_t> range)
BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);
}
}
- tg.interrupt_all();
- tg.join_all();
+ small_queue->StopWorkerThreads();
}
/** Test that 0 checks is correct
@@ -212,11 +208,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)
BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
{
auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE);
-
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{fail_queue->Thread();});
- }
+ fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (size_t i = 0; i < 1001; ++i) {
CCheckQueueControl<FailingCheck> control(fail_queue.get());
@@ -237,18 +229,14 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
BOOST_REQUIRE(success);
}
}
- tg.interrupt_all();
- tg.join_all();
+ fail_queue->StopWorkerThreads();
}
// Test that a block validation which fails does not interfere with
// future blocks, ie, the bad state is cleared.
BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
{
auto fail_queue = MakeUnique<Failing_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{fail_queue->Thread();});
- }
+ fail_queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (auto times = 0; times < 10; ++times) {
for (const bool end_fails : {true, false}) {
@@ -263,8 +251,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
BOOST_REQUIRE(r != end_fails);
}
}
- tg.interrupt_all();
- tg.join_all();
+ fail_queue->StopWorkerThreads();
}
// Test that unique checks are actually all called individually, rather than
@@ -273,11 +260,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)
BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
{
auto queue = MakeUnique<Unique_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{queue->Thread();});
-
- }
+ queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
size_t COUNT = 100000;
size_t total = COUNT;
@@ -300,8 +283,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
}
BOOST_REQUIRE(r);
}
- tg.interrupt_all();
- tg.join_all();
+ queue->StopWorkerThreads();
}
@@ -313,10 +295,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
{
auto queue = MakeUnique<Memory_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{queue->Thread();});
- }
+ queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
for (size_t i = 0; i < 1000; ++i) {
size_t total = i;
{
@@ -335,8 +314,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
}
BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0U);
}
- tg.interrupt_all();
- tg.join_all();
+ queue->StopWorkerThreads();
}
// Test that a new verification cannot occur until all checks
@@ -344,11 +322,8 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
{
auto queue = MakeUnique<FrozenCleanup_Queue>(QUEUE_BATCH_SIZE);
- boost::thread_group tg;
bool fails = false;
- for (auto x = 0; x < SCRIPT_CHECK_THREADS; ++x) {
- tg.create_thread([&]{queue->Thread();});
- }
+ queue->StartWorkerThreads(SCRIPT_CHECK_THREADS);
std::thread t0([&]() {
CCheckQueueControl<FrozenCleanupCheck> control(queue.get());
std::vector<FrozenCleanupCheck> vChecks(1);
@@ -367,7 +342,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
}
// Try to get control of the queue a bunch of times
for (auto x = 0; x < 100 && !fails; ++x) {
- fails = queue->ControlMutex.try_lock();
+ fails = queue->m_control_mutex.try_lock();
}
{
// Unfreeze (we need lock n case of spurious wakeup)
@@ -378,9 +353,8 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup)
FrozenCleanupCheck::cv.notify_one();
// Wait for control to finish
t0.join();
- tg.interrupt_all();
- tg.join_all();
BOOST_REQUIRE(!fails);
+ queue->StopWorkerThreads();
}
@@ -431,7 +405,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
cv.wait(l, [&](){return has_lock;});
bool fails = false;
for (auto x = 0; x < 100 && !fails; ++x) {
- fails = queue->ControlMutex.try_lock();
+ fails = queue->m_control_mutex.try_lock();
}
has_tried = true;
cv.notify_one();
@@ -445,4 +419,3 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
}
}
BOOST_AUTO_TEST_SUITE_END()
-
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 6bfcf242d0..06db3b846e 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 0ad5066603..7358b246b6 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -14,7 +14,9 @@
#include <crypto/sha256.h>
#include <crypto/sha3.h>
#include <crypto/sha512.h>
+#include <crypto/muhash.h>
#include <random.h>
+#include <streams.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
@@ -857,4 +859,92 @@ BOOST_AUTO_TEST_CASE(sha3_256_tests)
TestSHA3_256("72c57c359e10684d0517e46653a02d18d29eff803eb009e4d5eb9e95add9ad1a4ac1f38a70296f3a369a16985ca3c957de2084cdc9bdd8994eb59b8815e0debad4ec1f001feac089820db8becdaf896aaf95721e8674e5d476b43bd2b873a7d135cd685f545b438210f9319e4dcd55986c85303c1ddf18dc746fe63a409df0a998ed376eb683e16c09e6e9018504152b3e7628ef350659fb716e058a5263a18823d2f2f6ee6a8091945a48ae1c5cb1694cf2c1fe76ef9177953afe8899cfa2b7fe0603bfa3180937dadfb66fbbdd119bbf8063338aa4a699075a3bfdbae8db7e5211d0917e9665a702fc9b0a0a901d08bea97654162d82a9f05622b060b634244779c33427eb7a29353a5f48b07cbefa72f3622ac5900bef77b71d6b314296f304c8426f451f32049b1f6af156a9dab702e8907d3cd72bb2c50493f4d593e731b285b70c803b74825b3524cda3205a8897106615260ac93c01c5ec14f5b11127783989d1824527e99e04f6a340e827b559f24db9292fcdd354838f9339a5fa1d7f6b2087f04835828b13463dd40927866f16ae33ed501ec0e6c4e63948768c5aeea3e4f6754985954bea7d61088c44430204ef491b74a64bde1358cecb2cad28ee6a3de5b752ff6a051104d88478653339457ac45ba44cbb65f54d1969d047cda746931d5e6a8b48e211416aefd5729f3d60b56b54e7f85aa2f42de3cb69419240c24e67139a11790a709edef2ac52cf35dd0a08af45926ebe9761f498ff83bfe263d6897ee97943a4b982fe3404ef0b4a45e06113c60340e0664f14799bf59cb4b3934b465fabefd87155905ee5309ba41e9e402973311831ea600b16437f71df39ee77130490c4d0227e5d1757fdc66af3ae6b9953053ed9aafca0160209858a7d4dd38fe10e0cb153672d08633ed6c54977aa0a6e67f9ff2f8c9d22dd7b21de08192960fd0e0da68d77c8d810db11dcaa61c725cd4092cbff76c8e1debd8d0361bb3f2e607911d45716f53067bdc0d89dd4889177765166a424e9fc0cb711201099dda213355e6639ac7eb86eca2ae0ab38b7f674f37ef8a6fcca1a6f52f55d9e1dcd631d2c3c82bba129172feb991d5af51afecd9d61a88b6832e4107480e392aed61a8644f551665ebff6b20953b635737a4f895e429fddcfe801f606fbda74b3bf6f5767d0fac14907fcfd0aa1d4c11b9e91b01d68052399b51a29f1ae6acd965109977c14a555cbcbd21ad8cb9f8853506d4bc21c01e62d61d7b21be1b923be54914e6b0a7ca84dd11f1159193e1184568a6134a6bbadf5b4df986edcf2019390ae841cfaa44435e28ce877d3dae4177992fa5d4e5c005876dbe3d1e63bec7dcc0942762b48b1ecc6c1a918409a8a72812a1e245c0c67be6e729c2b49bc6ee4d24a8f63e78e75db45655c26a9a78aff36fcd67117f26b8f654dca664b9f0e30681874cb749e1a692720078856286c2560b0292cc837933423147569350955c9571bf8941ba128fd339cb4268f46b94bc6ee203eb7026813706ea51c4f24c91866fc23a724bf2501327e6ae89c29f8db315dc28d2c7c719514036367e018f4835f63fdecd71f9bdced7132b6c4f8b13c69a517026fcd3622d67cb632320d5e7308f78f4b7cea11f6291b137851dc6cd6366f2785c71c3f237f81a7658b2a8d512b61e0ad5a4710b7b124151689fcb2116063fbff7e9115fed7b93de834970b838e49f8f8ba5f1f874c354078b5810a55ae289a56da563f1da6cd80a3757d6073fa55e016e45ac6cec1f69d871c92fd0ae9670c74249045e6b464787f9504128736309fed205f8df4d90e332908581298d9c75a3fa36ab0c3c9272e62de53ab290c803d67b696fd615c260a47bffad16746f18ba1a10a061bacbea9369693b3c042eec36bed289d7d12e52bca8aa1c2dff88ca7816498d25626d0f1e106ebb0b4a12138e00f3df5b1c2f49d98b1756e69b641b7c6353d99dbff050f4d76842c6cf1c2a4b062fc8e6336fa689b7c9d5c6b4ab8c15a5c20e514ff070a602d85ae52fa7810c22f8eeffd34a095b93342144f7a98d024216b3d68ed7bea047517bfcd83ec83febd1ba0e5858e2bdc1d8b1f7b0f89e90ccc432a3f930cb8209462e64556c5054c56ca2a85f16b32eb83a10459d13516faa4d23302b7607b9bd38dab2239ac9e9440c314433fdfb3ceadab4b4f87415ed6f240e017221f3b5f7ac196cdf54957bec42fe6893994b46de3d27dc7fb58ca88feb5b9e79cf20053d12530ac524337b22a3629bea52f40b06d3e2128f32060f9105847daed81d35f20e2002817434659baff64494c5b5c7f9216bfda38412a0f70511159dc73bb6bae1f8eaa0ef08d99bcb31f94f6be12c29c83df45926430b366c99fca3270c15fc4056398fdf3135b7779e3066a006961d1ac0ad1c83179ce39e87a96b722ec23aabc065badf3e188347a360772ca6a447abac7e6a44f0d4632d52926332e44a0a86bff5ce699fd063bdda3ffd4c41b53ded49fecec67f40599b934e16e3fd1bc063ad7026f8d71bfd4cbaf56599586774723194b692036f1b6bb242e2ffb9c600b5215b412764599476ce475c9e5b396fbcebd6be323dcf4d0048077400aac7500db41dc95fc7f7edbe7c9c2ec5ea89943fe13b42217eef530bbd023671509e12dfce4e1c1c82955d965e6a68aa66f6967dba48feda572db1f099d9a6dc4bc8edade852b5e824a06890dc48a6a6510ecaf8cf7620d757290e3166d431abecc624fa9ac2234d2eb783308ead45544910c633a94964b2ef5fbc409cb8835ac4147d384e12e0a5e13951f7de0ee13eafcb0ca0c04946d7804040c0a3cd088352424b097adb7aad1ca4495952f3e6c0158c02d2bcec33bfda69301434a84d9027ce02c0b9725dad118", "d894b86261436362e64241e61f6b3e6589daf64dc641f60570c4c0bf3b1f2ca3");
}
+static MuHash3072 FromInt(unsigned char i) {
+ unsigned char tmp[32] = {i, 0};
+ return MuHash3072(tmp);
+}
+
+BOOST_AUTO_TEST_CASE(muhash_tests)
+{
+ uint256 out;
+
+ for (int iter = 0; iter < 10; ++iter) {
+ uint256 res;
+ int table[4];
+ for (int i = 0; i < 4; ++i) {
+ table[i] = g_insecure_rand_ctx.randbits(3);
+ }
+ for (int order = 0; order < 4; ++order) {
+ MuHash3072 acc;
+ for (int i = 0; i < 4; ++i) {
+ int t = table[i ^ order];
+ if (t & 4) {
+ acc /= FromInt(t & 3);
+ } else {
+ acc *= FromInt(t & 3);
+ }
+ }
+ acc.Finalize(out);
+ if (order == 0) {
+ res = out;
+ } else {
+ BOOST_CHECK(res == out);
+ }
+ }
+
+ MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X
+ MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits(4)); // x=X, y=Y
+ MuHash3072 z; // x=X, y=Y, z=1
+ z *= x; // x=X, y=Y, z=X
+ z *= y; // x=X, y=Y, z=X*Y
+ y *= x; // x=X, y=Y*X, z=X*Y
+ z /= y; // x=X, y=Y*X, z=1
+ z.Finalize(out);
+
+ uint256 out2;
+ MuHash3072 a;
+ a.Finalize(out2);
+
+ BOOST_CHECK_EQUAL(out, out2);
+ }
+
+ MuHash3072 acc = FromInt(0);
+ acc *= FromInt(1);
+ acc /= FromInt(2);
+ acc.Finalize(out);
+ BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863"));
+
+ MuHash3072 acc2 = FromInt(0);
+ unsigned char tmp[32] = {1, 0};
+ acc2.Insert(tmp);
+ unsigned char tmp2[32] = {2, 0};
+ acc2.Remove(tmp2);
+ acc2.Finalize(out);
+ BOOST_CHECK_EQUAL(out, uint256S("10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863"));
+
+ // Test MuHash3072 serialization
+ MuHash3072 serchk = FromInt(1); serchk *= FromInt(2);
+ std::string ser_exp = "1fa093295ea30a6a3acdc7b3f770fa538eff537528e990e2910e40bbcfd7f6696b1256901929094694b56316de342f593303dd12ac43e06dce1be1ff8301c845beb15468fff0ef002dbf80c29f26e6452bccc91b5cb9437ad410d2a67ea847887fa3c6a6553309946880fe20db2c73fe0641adbd4e86edfee0d9f8cd0ee1230898873dc13ed8ddcaf045c80faa082774279007a2253f8922ee3ef361d378a6af3ddaf180b190ac97e556888c36b3d1fb1c85aab9ccd46e3deaeb7b7cf5db067a7e9ff86b658cf3acd6662bbcce37232daa753c48b794356c020090c831a8304416e2aa7ad633c0ddb2f11be1be316a81be7f7e472071c042cb68faef549c221ebff209273638b741aba5a81675c45a5fa92fea4ca821d7a324cb1e1a2ccd3b76c4228ec8066dad2a5df6e1bd0de45c7dd5de8070bdb46db6c554cf9aefc9b7b2bbf9f75b1864d9f95005314593905c0109b71f703d49944ae94477b51dac10a816bb6d1c700bafabc8bd86fac8df24be519a2f2836b16392e18036cb13e48c5c010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
+ CDataStream ss_chk(SER_DISK, PROTOCOL_VERSION);
+ ss_chk << serchk;
+ BOOST_CHECK_EQUAL(ser_exp, HexStr(ss_chk.str()));
+
+ // Test MuHash3072 deserialization
+ MuHash3072 deserchk;
+ ss_chk >> deserchk;
+ uint256 out3;
+ serchk.Finalize(out);
+ deserchk.Finalize(out3);
+ BOOST_CHECK_EQUAL(HexStr(out), HexStr(out3));
+
+ // Test MuHash3072 overflow, meaning the internal data is larger than the modulus.
+ CDataStream ss_max(ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), SER_DISK, PROTOCOL_VERSION);
+ MuHash3072 overflowchk;
+ ss_max >> overflowchk;
+
+ uint256 out4;
+ overflowchk.Finalize(out4);
+ BOOST_CHECK_EQUAL(HexStr(out4), "3a31e6903aff0de9f62f9a9f7f8b861de76ce2cda09822b90014319ae5dc2271");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index 8f6fdd04d0..cf6009d591 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -80,12 +80,12 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
const CChainParams& chainparams = Params();
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = std::make_unique<PeerManager>(chainparams, *connman, nullptr, *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler,
+ *m_node.chainman, *m_node.mempool, 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(), "", ConnectionType::OUTBOUND_FULL_RELAY);
+ CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY);
dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1);
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerManager &peerLogic, CConnmanTest* connman)
{
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
- vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY));
+ vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr, 0, 0, CAddress(), "", ConnectionType::OUTBOUND_FULL_RELAY));
CNode &node = *vNodes.back();
node.SetCommonVersion(PROTOCOL_VERSION);
@@ -150,8 +150,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{
const CChainParams& chainparams = Params();
auto connman = MakeUnique<CConnmanTest>(0x1337, 0x1337);
- auto peerLogic = std::make_unique<PeerManager>(chainparams, *connman, nullptr, *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto peerLogic = PeerManager::make(chainparams, *connman, nullptr, *m_node.scheduler,
+ *m_node.chainman, *m_node.mempool, false);
constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
CConnman::Options options;
@@ -224,12 +224,12 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
const CChainParams& chainparams = Params();
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = std::make_unique<PeerManager>(chainparams, *connman, banman.get(), *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler,
+ *m_node.chainman, *m_node.mempool, false);
banman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::INBOUND);
+ CNode dummyNode1(id++, NODE_NETWORK, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::INBOUND);
dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1);
dummyNode1.fSuccessfullyConnected = true;
@@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001|0x0000ff00))); // Different IP, not discouraged
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
- CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", ConnectionType::INBOUND);
+ CNode dummyNode2(id++, NODE_NETWORK, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", ConnectionType::INBOUND);
dummyNode2.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode2);
dummyNode2.fSuccessfullyConnected = true;
@@ -271,15 +271,15 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
const CChainParams& chainparams = Params();
auto banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = MakeUnique<CConnman>(0x1337, 0x1337);
- auto peerLogic = std::make_unique<PeerManager>(chainparams, *connman, banman.get(), *m_node.scheduler,
- *m_node.chainman, *m_node.mempool, false);
+ auto peerLogic = PeerManager::make(chainparams, *connman, banman.get(), *m_node.scheduler,
+ *m_node.chainman, *m_node.mempool, false);
banman->ClearBanned();
int64_t nStartTime = GetTime();
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", ConnectionType::INBOUND);
+ CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, 4, 4, CAddress(), "", ConnectionType::INBOUND);
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode);
dummyNode.fSuccessfullyConnected = true;
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index be7484cd0b..0c5c19113d 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index d02c3613ba..ec487aa3ff 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -52,6 +52,23 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream)
file >> input_buffer;
BOOST_CHECK_EQUAL(input_buffer, "bitcoin");
}
+ {
+ // Join an absolute path and a relative path.
+ fs::path p = fsbridge::AbsPathJoin(tmpfolder, "fs_tests_₿_🏃");
+ BOOST_CHECK(p.is_absolute());
+ BOOST_CHECK_EQUAL(tmpfile1, p);
+ }
+ {
+ // Join two absolute paths.
+ fs::path p = fsbridge::AbsPathJoin(tmpfile1, tmpfile2);
+ BOOST_CHECK(p.is_absolute());
+ BOOST_CHECK_EQUAL(tmpfile2, p);
+ }
+ {
+ // Ensure joining with empty paths does not add trailing path components.
+ BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, ""));
+ BOOST_CHECK_EQUAL(tmpfile1, fsbridge::AbsPathJoin(tmpfile1, {}));
+ }
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/fuzz/FuzzedDataProvider.h b/src/test/fuzz/FuzzedDataProvider.h
index 3e069eba69..744a9d78ce 100644
--- a/src/test/fuzz/FuzzedDataProvider.h
+++ b/src/test/fuzz/FuzzedDataProvider.h
@@ -14,6 +14,7 @@
#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
#include <algorithm>
+#include <array>
#include <climits>
#include <cstddef>
#include <cstdint>
@@ -34,272 +35,362 @@ class FuzzedDataProvider {
: data_ptr_(data), remaining_bytes_(size) {}
~FuzzedDataProvider() = default;
- // Returns a std::vector containing |num_bytes| of input data. If fewer than
- // |num_bytes| of data remain, returns a shorter std::vector containing all
- // of the data that's left. Can be used with any byte sized type, such as
- // char, unsigned char, uint8_t, etc.
- template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- return ConsumeBytes<T>(num_bytes, num_bytes);
- }
+ // See the implementation below (after the class definition) for more verbose
+ // comments for each of the methods.
- // Similar to |ConsumeBytes|, but also appends the terminator value at the end
- // of the resulting vector. Useful, when a mutable null-terminated C-string is
- // needed, for example. But that is a rare case. Better avoid it, if possible,
- // and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
+ // Methods returning std::vector of bytes. These are the most popular choice
+ // when splitting fuzzing input into pieces, as every piece is put into a
+ // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
+ // will be released automatically.
+ template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
template <typename T>
- std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes,
- T terminator = 0) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
- result.back() = terminator;
- return result;
- }
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
+ template <typename T> std::vector<T> ConsumeRemainingBytes();
- // Returns a std::string containing |num_bytes| of input data. Using this and
- // |.c_str()| on the resulting string is the best way to get an immutable
- // null-terminated C string. If fewer than |num_bytes| of data remain, returns
- // a shorter std::string containing all of the data that's left.
- std::string ConsumeBytesAsString(size_t num_bytes) {
- static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
- "ConsumeBytesAsString cannot convert the data to a string.");
-
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::string result(
- reinterpret_cast<const std::string::value_type *>(data_ptr_),
- num_bytes);
- Advance(num_bytes);
- return result;
- }
+ // Methods returning strings. Use only when you need a std::string or a null
+ // terminated C-string. Otherwise, prefer the methods returning std::vector.
+ std::string ConsumeBytesAsString(size_t num_bytes);
+ std::string ConsumeRandomLengthString(size_t max_length);
+ std::string ConsumeRandomLengthString();
+ std::string ConsumeRemainingBytesAsString();
- // Returns a number in the range [min, max] by consuming bytes from the
- // input data. The value might not be uniformly distributed in the given
- // range. If there's no input data left, always returns |min|. |min| must
- // be less than or equal to |max|.
- template <typename T> T ConsumeIntegralInRange(T min, T max) {
- static_assert(std::is_integral<T>::value, "An integral type is required.");
- static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+ // Methods returning integer values.
+ template <typename T> T ConsumeIntegral();
+ template <typename T> T ConsumeIntegralInRange(T min, T max);
- if (min > max)
- abort();
+ // Methods returning floating point values.
+ template <typename T> T ConsumeFloatingPoint();
+ template <typename T> T ConsumeFloatingPointInRange(T min, T max);
- // Use the biggest type possible to hold the range and the result.
- uint64_t range = static_cast<uint64_t>(max) - min;
- uint64_t result = 0;
- size_t offset = 0;
-
- while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
- remaining_bytes_ != 0) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // |ConsumeBytes|. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- --remaining_bytes_;
- result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
- offset += CHAR_BIT;
- }
+ // 0 <= return value <= 1.
+ template <typename T> T ConsumeProbability();
- // Avoid division by 0, in case |range + 1| results in overflow.
- if (range != std::numeric_limits<decltype(range)>::max())
- result = result % (range + 1);
+ bool ConsumeBool();
- return static_cast<T>(min + result);
- }
+ // Returns a value chosen from the given enum.
+ template <typename T> T ConsumeEnum();
- // Returns a std::string of length from 0 to |max_length|. When it runs out of
- // input data, returns what remains of the input. Designed to be more stable
- // with respect to a fuzzer inserting characters than just picking a random
- // length and then consuming that many bytes with |ConsumeBytes|.
- std::string ConsumeRandomLengthString(size_t max_length) {
- // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
- // followed by anything else to the end of the string. As a result of this
- // logic, a fuzzer can insert characters into the string, and the string
- // will be lengthened to include those new characters, resulting in a more
- // stable fuzzer than picking the length of a string independently from
- // picking its contents.
- std::string result;
-
- // Reserve the anticipated capaticity to prevent several reallocations.
- result.reserve(std::min(max_length, remaining_bytes_));
- for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
- char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next == '\\' && remaining_bytes_ != 0) {
- next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next != '\\')
- break;
- }
- result += next;
- }
-
- result.shrink_to_fit();
- return result;
- }
+ // Returns a value from the given array.
+ template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
+ template <typename T, size_t size>
+ T PickValueInArray(const std::array<T, size> &array);
+ template <typename T> T PickValueInArray(std::initializer_list<const T> list);
- // Returns a std::vector containing all remaining bytes of the input data.
- template <typename T> std::vector<T> ConsumeRemainingBytes() {
- return ConsumeBytes<T>(remaining_bytes_);
- }
+ // Writes data to the given destination and returns number of bytes written.
+ size_t ConsumeData(void *destination, size_t num_bytes);
- // Returns a std::string containing all remaining bytes of the input data.
- // Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
- // object.
- std::string ConsumeRemainingBytesAsString() {
- return ConsumeBytesAsString(remaining_bytes_);
- }
+ // Reports the remaining bytes available for fuzzed input.
+ size_t remaining_bytes() { return remaining_bytes_; }
- // Returns a number in the range [Type's min, Type's max]. The value might
- // not be uniformly distributed in the given range. If there's no input data
- // left, always returns |min|.
- template <typename T> T ConsumeIntegral() {
- return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
- std::numeric_limits<T>::max());
- }
+ private:
+ FuzzedDataProvider(const FuzzedDataProvider &) = delete;
+ FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
- // Reads one byte and returns a bool, or false when no data remains.
- bool ConsumeBool() { return 1 & ConsumeIntegral<uint8_t>(); }
+ void CopyAndAdvance(void *destination, size_t num_bytes);
- // Returns a copy of the value selected from the given fixed-size |array|.
- template <typename T, size_t size>
- T PickValueInArray(const T (&array)[size]) {
- static_assert(size > 0, "The array must be non empty.");
- return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
- }
+ void Advance(size_t num_bytes);
template <typename T>
- T PickValueInArray(std::initializer_list<const T> list) {
- // TODO(Dor1s): switch to static_assert once C++14 is allowed.
- if (!list.size())
- abort();
-
- return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
- }
-
- // Returns an enum value. The enum must start at 0 and be contiguous. It must
- // also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
- // enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
- template <typename T> T ConsumeEnum() {
- static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
- return static_cast<T>(ConsumeIntegralInRange<uint32_t>(
- 0, static_cast<uint32_t>(T::kMaxValue)));
- }
+ std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
- // Returns a floating point number in the range [0.0, 1.0]. If there's no
- // input data left, always returns 0.
- template <typename T> T ConsumeProbability() {
- static_assert(std::is_floating_point<T>::value,
- "A floating point type is required.");
+ template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
- // Use different integral types for different floating point types in order
- // to provide better density of the resulting values.
- using IntegralType =
- typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
- uint64_t>::type;
+ const uint8_t *data_ptr_;
+ size_t remaining_bytes_;
+};
- T result = static_cast<T>(ConsumeIntegral<IntegralType>());
- result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
- return result;
+// Returns a std::vector containing |num_bytes| of input data. If fewer than
+// |num_bytes| of data remain, returns a shorter std::vector containing all
+// of the data that's left. Can be used with any byte sized type, such as
+// char, unsigned char, uint8_t, etc.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ return ConsumeBytes<T>(num_bytes, num_bytes);
+}
+
+// Similar to |ConsumeBytes|, but also appends the terminator value at the end
+// of the resulting vector. Useful, when a mutable null-terminated C-string is
+// needed, for example. But that is a rare case. Better avoid it, if possible,
+// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
+ T terminator) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
+ result.back() = terminator;
+ return result;
+}
+
+// Returns a std::vector containing all remaining bytes of the input data.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
+ return ConsumeBytes<T>(remaining_bytes_);
+}
+
+// Returns a std::string containing |num_bytes| of input data. Using this and
+// |.c_str()| on the resulting string is the best way to get an immutable
+// null-terminated C string. If fewer than |num_bytes| of data remain, returns
+// a shorter std::string containing all of the data that's left.
+inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
+ "ConsumeBytesAsString cannot convert the data to a string.");
+
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::string result(
+ reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
+ Advance(num_bytes);
+ return result;
+}
+
+// Returns a std::string of length from 0 to |max_length|. When it runs out of
+// input data, returns what remains of the input. Designed to be more stable
+// with respect to a fuzzer inserting characters than just picking a random
+// length and then consuming that many bytes with |ConsumeBytes|.
+inline std::string
+FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
+ // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
+ // followed by anything else to the end of the string. As a result of this
+ // logic, a fuzzer can insert characters into the string, and the string
+ // will be lengthened to include those new characters, resulting in a more
+ // stable fuzzer than picking the length of a string independently from
+ // picking its contents.
+ std::string result;
+
+ // Reserve the anticipated capaticity to prevent several reallocations.
+ result.reserve(std::min(max_length, remaining_bytes_));
+ for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
+ char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next == '\\' && remaining_bytes_ != 0) {
+ next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next != '\\')
+ break;
+ }
+ result += next;
}
- // Returns a floating point value in the range [Type's lowest, Type's max] by
- // consuming bytes from the input data. If there's no input data left, always
- // returns approximately 0.
- template <typename T> T ConsumeFloatingPoint() {
- return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
- std::numeric_limits<T>::max());
+ result.shrink_to_fit();
+ return result;
+}
+
+// Returns a std::string of length from 0 to |remaining_bytes_|.
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
+ return ConsumeRandomLengthString(remaining_bytes_);
+}
+
+// Returns a std::string containing all remaining bytes of the input data.
+// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
+// object.
+inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
+ return ConsumeBytesAsString(remaining_bytes_);
+}
+
+// Returns a number in the range [Type's min, Type's max]. The value might
+// not be uniformly distributed in the given range. If there's no input data
+// left, always returns |min|.
+template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
+ return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a number in the range [min, max] by consuming bytes from the
+// input data. The value might not be uniformly distributed in the given
+// range. If there's no input data left, always returns |min|. |min| must
+// be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
+ static_assert(std::is_integral<T>::value, "An integral type is required.");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+
+ if (min > max)
+ abort();
+
+ // Use the biggest type possible to hold the range and the result.
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = 0;
+ size_t offset = 0;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
+ remaining_bytes_ != 0) {
+ // Pull bytes off the end of the seed data. Experimentally, this seems to
+ // allow the fuzzer to more easily explore the input space. This makes
+ // sense, since it works by modifying inputs that caused new code to run,
+ // and this data is often used to encode length of data read by
+ // |ConsumeBytes|. Separating out read lengths makes it easier modify the
+ // contents of the data that is actually read.
+ --remaining_bytes_;
+ result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
+ offset += CHAR_BIT;
}
- // Returns a floating point value in the given range by consuming bytes from
- // the input data. If there's no input data left, returns |min|. Note that
- // |min| must be less than or equal to |max|.
- template <typename T> T ConsumeFloatingPointInRange(T min, T max) {
- if (min > max)
- abort();
-
- T range = .0;
- T result = min;
- constexpr T zero(.0);
- if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
- // The diff |max - min| would overflow the given floating point type. Use
- // the half of the diff as the range and consume a bool to decide whether
- // the result is in the first of the second part of the diff.
- range = (max / 2.0) - (min / 2.0);
- if (ConsumeBool()) {
- result += range;
- }
- } else {
- range = max - min;
+ // Avoid division by 0, in case |range + 1| results in overflow.
+ if (range != std::numeric_limits<decltype(range)>::max())
+ result = result % (range + 1);
+
+ return static_cast<T>(min + result);
+}
+
+// Returns a floating point value in the range [Type's lowest, Type's max] by
+// consuming bytes from the input data. If there's no input data left, always
+// returns approximately 0.
+template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
+ return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a floating point value in the given range by consuming bytes from
+// the input data. If there's no input data left, returns |min|. Note that
+// |min| must be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
+ if (min > max)
+ abort();
+
+ T range = .0;
+ T result = min;
+ constexpr T zero(.0);
+ if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
+ // The diff |max - min| would overflow the given floating point type. Use
+ // the half of the diff as the range and consume a bool to decide whether
+ // the result is in the first of the second part of the diff.
+ range = (max / 2.0) - (min / 2.0);
+ if (ConsumeBool()) {
+ result += range;
}
-
- return result + range * ConsumeProbability<T>();
+ } else {
+ range = max - min;
}
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_bytes_; }
-
- private:
- FuzzedDataProvider(const FuzzedDataProvider &) = delete;
- FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
-
- void Advance(size_t num_bytes) {
- if (num_bytes > remaining_bytes_)
+ return result + range * ConsumeProbability<T>();
+}
+
+// Returns a floating point number in the range [0.0, 1.0]. If there's no
+// input data left, always returns 0.
+template <typename T> T FuzzedDataProvider::ConsumeProbability() {
+ static_assert(std::is_floating_point<T>::value,
+ "A floating point type is required.");
+
+ // Use different integral types for different floating point types in order
+ // to provide better density of the resulting values.
+ using IntegralType =
+ typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
+ uint64_t>::type;
+
+ T result = static_cast<T>(ConsumeIntegral<IntegralType>());
+ result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
+ return result;
+}
+
+// Reads one byte and returns a bool, or false when no data remains.
+inline bool FuzzedDataProvider::ConsumeBool() {
+ return 1 & ConsumeIntegral<uint8_t>();
+}
+
+// Returns an enum value. The enum must start at 0 and be contiguous. It must
+// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
+// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
+template <typename T> T FuzzedDataProvider::ConsumeEnum() {
+ static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+ return static_cast<T>(
+ ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
+}
+
+// Returns a copy of the value selected from the given fixed-size |array|.
+template <typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+}
+
+template <typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const std::array<T, size> &array) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+}
+
+template <typename T>
+T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
+ // TODO(Dor1s): switch to static_assert once C++14 is allowed.
+ if (!list.size())
+ abort();
+
+ return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
+}
+
+// Writes |num_bytes| of input data to the given destination pointer. If there
+// is not enough data left, writes all remaining bytes. Return value is the
+// number of bytes written.
+// In general, it's better to avoid using this function, but it may be useful
+// in cases when it's necessary to fill a certain buffer or object with
+// fuzzing data.
+inline size_t FuzzedDataProvider::ConsumeData(void *destination,
+ size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ CopyAndAdvance(destination, num_bytes);
+ return num_bytes;
+}
+
+// Private methods.
+inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
+ size_t num_bytes) {
+ std::memcpy(destination, data_ptr_, num_bytes);
+ Advance(num_bytes);
+}
+
+inline void FuzzedDataProvider::Advance(size_t num_bytes) {
+ if (num_bytes > remaining_bytes_)
+ abort();
+
+ data_ptr_ += num_bytes;
+ remaining_bytes_ -= num_bytes;
+}
+
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
+ static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
+
+ // The point of using the size-based constructor below is to increase the
+ // odds of having a vector object with capacity being equal to the length.
+ // That part is always implementation specific, but at least both libc++ and
+ // libstdc++ allocate the requested number of bytes in that constructor,
+ // which seems to be a natural choice for other implementations as well.
+ // To increase the odds even more, we also call |shrink_to_fit| below.
+ std::vector<T> result(size);
+ if (size == 0) {
+ if (num_bytes != 0)
abort();
-
- data_ptr_ += num_bytes;
- remaining_bytes_ -= num_bytes;
- }
-
- template <typename T>
- std::vector<T> ConsumeBytes(size_t size, size_t num_bytes_to_consume) {
- static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
-
- // The point of using the size-based constructor below is to increase the
- // odds of having a vector object with capacity being equal to the length.
- // That part is always implementation specific, but at least both libc++ and
- // libstdc++ allocate the requested number of bytes in that constructor,
- // which seems to be a natural choice for other implementations as well.
- // To increase the odds even more, we also call |shrink_to_fit| below.
- std::vector<T> result(size);
- if (size == 0) {
- if (num_bytes_to_consume != 0)
- abort();
- return result;
- }
-
- std::memcpy(result.data(), data_ptr_, num_bytes_to_consume);
- Advance(num_bytes_to_consume);
-
- // Even though |shrink_to_fit| is also implementation specific, we expect it
- // to provide an additional assurance in case vector's constructor allocated
- // a buffer which is larger than the actual amount of data we put inside it.
- result.shrink_to_fit();
return result;
}
- template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value) {
- static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
- static_assert(!std::numeric_limits<TU>::is_signed,
- "Source type must be unsigned.");
-
- // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
- if (std::numeric_limits<TS>::is_modulo)
- return static_cast<TS>(value);
-
- // Avoid using implementation-defined unsigned to signer conversions.
- // To learn more, see https://stackoverflow.com/questions/13150449.
- if (value <= std::numeric_limits<TS>::max()) {
- return static_cast<TS>(value);
- } else {
- constexpr auto TS_min = std::numeric_limits<TS>::min();
- return TS_min + static_cast<char>(value - TS_min);
- }
+ CopyAndAdvance(result.data(), num_bytes);
+
+ // Even though |shrink_to_fit| is also implementation specific, we expect it
+ // to provide an additional assurance in case vector's constructor allocated
+ // a buffer which is larger than the actual amount of data we put inside it.
+ result.shrink_to_fit();
+ return result;
+}
+
+template <typename TS, typename TU>
+TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
+ static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
+ static_assert(!std::numeric_limits<TU>::is_signed,
+ "Source type must be unsigned.");
+
+ // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
+ if (std::numeric_limits<TS>::is_modulo)
+ return static_cast<TS>(value);
+
+ // Avoid using implementation-defined unsigned to signed conversions.
+ // To learn more, see https://stackoverflow.com/questions/13150449.
+ if (value <= std::numeric_limits<TS>::max()) {
+ return static_cast<TS>(value);
+ } else {
+ constexpr auto TS_min = std::numeric_limits<TS>::min();
+ return TS_min + static_cast<char>(value - TS_min);
}
-
- const uint8_t *data_ptr_;
- size_t remaining_bytes_;
-};
+}
#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index af9080b5e9..1ea6b3d01d 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -45,83 +45,71 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
}
}
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
- case 0: {
- addr_man.Clear();
- break;
- }
- case 1: {
- addr_man.ResolveCollisions();
- break;
- }
- case 2: {
- (void)addr_man.SelectTriedCollision();
- break;
- }
- case 3: {
- (void)addr_man.Select(fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 4: {
- (void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- break;
- }
- case 5: {
- const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
- if (opt_address && opt_net_addr) {
- addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
- }
- break;
- }
- case 6: {
- std::vector<CAddress> addresses;
- while (fuzzed_data_provider.ConsumeBool()) {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ addr_man.Clear();
+ },
+ [&] {
+ addr_man.ResolveCollisions();
+ },
+ [&] {
+ (void)addr_man.SelectTriedCollision();
+ },
+ [&] {
+ (void)addr_man.Select(fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ (void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ },
+ [&] {
const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!opt_address) {
- break;
+ const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
+ if (opt_address && opt_net_addr) {
+ addr_man.Add(*opt_address, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
}
- addresses.push_back(*opt_address);
- }
- const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
- if (opt_net_addr) {
- addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
- }
- break;
- }
- case 7: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
- }
- break;
- }
- case 8: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
- }
- break;
- }
- case 9: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider));
- }
- break;
- }
- case 10: {
- const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (opt_service) {
- addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral<uint64_t>()});
- }
- break;
- }
- case 11: {
- (void)addr_man.Check();
- break;
- }
- }
+ },
+ [&] {
+ std::vector<CAddress> addresses;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!opt_address) {
+ break;
+ }
+ addresses.push_back(*opt_address);
+ }
+ const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
+ if (opt_net_addr) {
+ addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.Good(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider));
+ }
+ },
+ [&] {
+ const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (opt_service) {
+ addr_man.SetServices(*opt_service, ServiceFlags{fuzzed_data_provider.ConsumeIntegral<uint64_t>()});
+ }
+ },
+ [&] {
+ (void)addr_man.Check();
+ });
}
(void)addr_man.size();
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index eb3424ef28..9ecd172e19 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -21,43 +21,37 @@ FUZZ_TARGET(autofile)
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
CAutoFile auto_file = fuzzed_auto_file_provider.open();
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
- case 0: {
- std::array<uint8_t, 4096> arr{};
- try {
- auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 1: {
- const std::array<uint8_t, 4096> arr{};
- try {
- auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 2: {
- try {
- auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 3: {
- auto_file.fclose();
- break;
- }
- case 4: {
- ReadFromStream(fuzzed_data_provider, auto_file);
- break;
- }
- case 5: {
- WriteToStream(fuzzed_data_provider, auto_file);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ std::array<uint8_t, 4096> arr{};
+ try {
+ auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ const std::array<uint8_t, 4096> arr{};
+ try {
+ auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ try {
+ auto_file.ignore(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ auto_file.fclose();
+ },
+ [&] {
+ ReadFromStream(fuzzed_data_provider, auto_file);
+ },
+ [&] {
+ WriteToStream(fuzzed_data_provider, auto_file);
+ });
}
(void)auto_file.Get();
(void)auto_file.GetType();
diff --git a/src/test/fuzz/banman.cpp b/src/test/fuzz/banman.cpp
index cf69fa0722..e0715f3e29 100644
--- a/src/test/fuzz/banman.cpp
+++ b/src/test/fuzz/banman.cpp
@@ -26,7 +26,7 @@ int64_t ConsumeBanTimeOffset(FuzzedDataProvider& fuzzed_data_provider) noexcept
void initialize_banman()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(banman, initialize_banman)
@@ -38,51 +38,43 @@ FUZZ_TARGET_INIT(banman, initialize_banman)
{
BanMan ban_man{banlist_file, nullptr, ConsumeBanTimeOffset(fuzzed_data_provider)};
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 11)) {
- case 0: {
- ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider),
- ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 1: {
- ban_man.Ban(ConsumeSubNet(fuzzed_data_provider),
- ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 2: {
- ban_man.ClearBanned();
- break;
- }
- case 4: {
- ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
- break;
- }
- case 5: {
- ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
- break;
- }
- case 6: {
- ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
- break;
- }
- case 7: {
- ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
- break;
- }
- case 8: {
- banmap_t banmap;
- ban_man.GetBanned(banmap);
- break;
- }
- case 9: {
- ban_man.DumpBanlist();
- break;
- }
- case 11: {
- ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ ban_man.Ban(ConsumeNetAddr(fuzzed_data_provider),
+ ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ ban_man.Ban(ConsumeSubNet(fuzzed_data_provider),
+ ConsumeBanTimeOffset(fuzzed_data_provider), fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ ban_man.ClearBanned();
+ },
+ [] {},
+ [&] {
+ ban_man.IsBanned(ConsumeNetAddr(fuzzed_data_provider));
+ },
+ [&] {
+ ban_man.IsBanned(ConsumeSubNet(fuzzed_data_provider));
+ },
+ [&] {
+ ban_man.Unban(ConsumeNetAddr(fuzzed_data_provider));
+ },
+ [&] {
+ ban_man.Unban(ConsumeSubNet(fuzzed_data_provider));
+ },
+ [&] {
+ banmap_t banmap;
+ ban_man.GetBanned(banmap);
+ },
+ [&] {
+ ban_man.DumpBanlist();
+ },
+ [] {},
+ [&] {
+ ban_man.Discourage(ConsumeNetAddr(fuzzed_data_provider));
+ });
}
}
fs::remove(banlist_file);
diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp
index b1a485e12e..95cd4b413f 100644
--- a/src/test/fuzz/bech32.cpp
+++ b/src/test/fuzz/bech32.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp
index c0c66c564b..d43c182644 100644
--- a/src/test/fuzz/bloom_filter.cpp
+++ b/src/test/fuzz/bloom_filter.cpp
@@ -25,47 +25,43 @@ FUZZ_TARGET(bloom_filter)
fuzzed_data_provider.ConsumeIntegral<unsigned int>(),
static_cast<unsigned char>(fuzzed_data_provider.PickValueInArray({BLOOM_UPDATE_NONE, BLOOM_UPDATE_ALL, BLOOM_UPDATE_P2PUBKEY_ONLY, BLOOM_UPDATE_MASK}))};
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 3)) {
- case 0: {
- const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- (void)bloom_filter.contains(b);
- bloom_filter.insert(b);
- const bool present = bloom_filter.contains(b);
- assert(present);
- break;
- }
- case 1: {
- const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
- if (!out_point) {
- break;
- }
- (void)bloom_filter.contains(*out_point);
- bloom_filter.insert(*out_point);
- const bool present = bloom_filter.contains(*out_point);
- assert(present);
- break;
- }
- case 2: {
- const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
- if (!u256) {
- break;
- }
- (void)bloom_filter.contains(*u256);
- bloom_filter.insert(*u256);
- const bool present = bloom_filter.contains(*u256);
- assert(present);
- break;
- }
- case 3: {
- const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- if (!mut_tx) {
- break;
- }
- const CTransaction tx{*mut_tx};
- (void)bloom_filter.IsRelevantAndUpdate(tx);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ (void)bloom_filter.contains(b);
+ bloom_filter.insert(b);
+ const bool present = bloom_filter.contains(b);
+ assert(present);
+ },
+ [&] {
+ const std::optional<COutPoint> out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (!out_point) {
+ return;
+ }
+ (void)bloom_filter.contains(*out_point);
+ bloom_filter.insert(*out_point);
+ const bool present = bloom_filter.contains(*out_point);
+ assert(present);
+ },
+ [&] {
+ const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ if (!u256) {
+ return;
+ }
+ (void)bloom_filter.contains(*u256);
+ bloom_filter.insert(*u256);
+ const bool present = bloom_filter.contains(*u256);
+ assert(present);
+ },
+ [&] {
+ const std::optional<CMutableTransaction> mut_tx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!mut_tx) {
+ return;
+ }
+ const CTransaction tx{*mut_tx};
+ (void)bloom_filter.IsRelevantAndUpdate(tx);
+ });
(void)bloom_filter.IsWithinSizeConstraints();
}
}
diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp
index 23e197456a..3a1b2dbbe7 100644
--- a/src/test/fuzz/buffered_file.cpp
+++ b/src/test/fuzz/buffered_file.cpp
@@ -31,41 +31,36 @@ FUZZ_TARGET(buffered_file)
if (opt_buffered_file && fuzzed_file != nullptr) {
bool setpos_fail = false;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 4)) {
- case 0: {
- std::array<uint8_t, 4096> arr{};
- try {
- opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 1: {
- opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
- break;
- }
- case 2: {
- if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) {
- setpos_fail = true;
- }
- break;
- }
- case 3: {
- if (setpos_fail) {
- // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop.
- break;
- }
- try {
- opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>());
- } catch (const std::ios_base::failure&) {
- }
- break;
- }
- case 4: {
- ReadFromStream(fuzzed_data_provider, *opt_buffered_file);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ std::array<uint8_t, 4096> arr{};
+ try {
+ opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ opt_buffered_file->SetLimit(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096));
+ },
+ [&] {
+ if (!opt_buffered_file->SetPos(fuzzed_data_provider.ConsumeIntegralInRange<uint64_t>(0, 4096))) {
+ setpos_fail = true;
+ }
+ },
+ [&] {
+ if (setpos_fail) {
+ // Calling FindByte(...) after a failed SetPos(...) call may result in an infinite loop.
+ return;
+ }
+ try {
+ opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>());
+ } catch (const std::ios_base::failure&) {
+ }
+ },
+ [&] {
+ ReadFromStream(fuzzed_data_provider, *opt_buffered_file);
+ });
}
opt_buffered_file->GetPos();
opt_buffered_file->GetType();
diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp
index 1ae421493e..8ece94d771 100644
--- a/src/test/fuzz/coins_view.cpp
+++ b/src/test/fuzz/coins_view.cpp
@@ -36,9 +36,7 @@ bool operator==(const Coin& a, const Coin& b)
void initialize_coins_view()
{
- static const ECCVerifyHandle ecc_verify_handle;
- ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
@@ -50,103 +48,93 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
Coin random_coin;
CMutableTransaction random_mutable_transaction;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) {
- case 0: {
- if (random_coin.IsSpent()) {
- break;
- }
- Coin coin = random_coin;
- bool expected_code_path = false;
- const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
- try {
- coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite);
- expected_code_path = true;
- } catch (const std::logic_error& e) {
- if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
- assert(!possible_overwrite);
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ if (random_coin.IsSpent()) {
+ return;
+ }
+ Coin coin = random_coin;
+ bool expected_code_path = false;
+ const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
+ try {
+ coins_view_cache.AddCoin(random_out_point, std::move(coin), possible_overwrite);
expected_code_path = true;
+ } catch (const std::logic_error& e) {
+ if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
+ assert(!possible_overwrite);
+ expected_code_path = true;
+ }
}
- }
- assert(expected_code_path);
- break;
- }
- case 1: {
- (void)coins_view_cache.Flush();
- break;
- }
- case 2: {
- coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider));
- break;
- }
- case 3: {
- Coin move_to;
- (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr);
- break;
- }
- case 4: {
- coins_view_cache.Uncache(random_out_point);
- break;
- }
- case 5: {
- if (fuzzed_data_provider.ConsumeBool()) {
- backend_coins_view = CCoinsView{};
- }
- coins_view_cache.SetBackend(backend_coins_view);
- break;
- }
- case 6: {
- const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
- if (!opt_out_point) {
- break;
- }
- random_out_point = *opt_out_point;
- break;
- }
- case 7: {
- const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
- if (!opt_coin) {
- break;
- }
- random_coin = *opt_coin;
- break;
- }
- case 8: {
- const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- if (!opt_mutable_transaction) {
- break;
- }
- random_mutable_transaction = *opt_mutable_transaction;
- break;
- }
- case 9: {
- CCoinsMap coins_map;
- while (fuzzed_data_provider.ConsumeBool()) {
- CCoinsCacheEntry coins_cache_entry;
- coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>();
+ assert(expected_code_path);
+ },
+ [&] {
+ (void)coins_view_cache.Flush();
+ },
+ [&] {
+ coins_view_cache.SetBestBlock(ConsumeUInt256(fuzzed_data_provider));
+ },
+ [&] {
+ Coin move_to;
+ (void)coins_view_cache.SpendCoin(random_out_point, fuzzed_data_provider.ConsumeBool() ? &move_to : nullptr);
+ },
+ [&] {
+ coins_view_cache.Uncache(random_out_point);
+ },
+ [&] {
if (fuzzed_data_provider.ConsumeBool()) {
- coins_cache_entry.coin = random_coin;
- } else {
- const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
- if (!opt_coin) {
- break;
+ backend_coins_view = CCoinsView{};
+ }
+ coins_view_cache.SetBackend(backend_coins_view);
+ },
+ [&] {
+ const std::optional<COutPoint> opt_out_point = ConsumeDeserializable<COutPoint>(fuzzed_data_provider);
+ if (!opt_out_point) {
+ return;
+ }
+ random_out_point = *opt_out_point;
+ },
+ [&] {
+ const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
+ if (!opt_coin) {
+ return;
+ }
+ random_coin = *opt_coin;
+ },
+ [&] {
+ const std::optional<CMutableTransaction> opt_mutable_transaction = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!opt_mutable_transaction) {
+ return;
+ }
+ random_mutable_transaction = *opt_mutable_transaction;
+ },
+ [&] {
+ CCoinsMap coins_map;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ CCoinsCacheEntry coins_cache_entry;
+ coins_cache_entry.flags = fuzzed_data_provider.ConsumeIntegral<unsigned char>();
+ if (fuzzed_data_provider.ConsumeBool()) {
+ coins_cache_entry.coin = random_coin;
+ } else {
+ const std::optional<Coin> opt_coin = ConsumeDeserializable<Coin>(fuzzed_data_provider);
+ if (!opt_coin) {
+ return;
+ }
+ coins_cache_entry.coin = *opt_coin;
}
- coins_cache_entry.coin = *opt_coin;
+ coins_map.emplace(random_out_point, std::move(coins_cache_entry));
}
- coins_map.emplace(random_out_point, std::move(coins_cache_entry));
- }
- bool expected_code_path = false;
- try {
- coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock());
- expected_code_path = true;
- } catch (const std::logic_error& e) {
- if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {
+ bool expected_code_path = false;
+ try {
+ coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock());
expected_code_path = true;
+ } catch (const std::logic_error& e) {
+ if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {
+ expected_code_path = true;
+ }
}
- }
- assert(expected_code_path);
- break;
- }
- }
+ assert(expected_code_path);
+ });
}
{
@@ -199,97 +187,90 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
}
if (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 6)) {
- case 0: {
- const CTransaction transaction{random_mutable_transaction};
- bool is_spent = false;
- for (const CTxOut& tx_out : transaction.vout) {
- if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) {
- is_spent = true;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const CTransaction transaction{random_mutable_transaction};
+ bool is_spent = false;
+ for (const CTxOut& tx_out : transaction.vout) {
+ if (Coin{tx_out, 0, transaction.IsCoinBase()}.IsSpent()) {
+ is_spent = true;
+ }
+ }
+ if (is_spent) {
+ // Avoid:
+ // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed.
+ return;
}
- }
- if (is_spent) {
- // Avoid:
- // coins.cpp:69: void CCoinsViewCache::AddCoin(const COutPoint &, Coin &&, bool): Assertion `!coin.IsSpent()' failed.
- break;
- }
- bool expected_code_path = false;
- const int height = fuzzed_data_provider.ConsumeIntegral<int>();
- const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
- try {
- AddCoins(coins_view_cache, transaction, height, possible_overwrite);
- expected_code_path = true;
- } catch (const std::logic_error& e) {
- if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
- assert(!possible_overwrite);
+ bool expected_code_path = false;
+ const int height = fuzzed_data_provider.ConsumeIntegral<int>();
+ const bool possible_overwrite = fuzzed_data_provider.ConsumeBool();
+ try {
+ AddCoins(coins_view_cache, transaction, height, possible_overwrite);
expected_code_path = true;
+ } catch (const std::logic_error& e) {
+ if (e.what() == std::string{"Attempted to overwrite an unspent coin (when possible_overwrite is false)"}) {
+ assert(!possible_overwrite);
+ expected_code_path = true;
+ }
}
- }
- assert(expected_code_path);
- break;
- }
- case 1: {
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
- (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
- break;
- }
- case 2: {
- TxValidationState state;
- CAmount tx_fee_out;
- const CTransaction transaction{random_mutable_transaction};
- if (ContainsSpentInput(transaction, coins_view_cache)) {
- // Avoid:
- // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
- break;
- }
- try {
- (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out);
- assert(MoneyRange(tx_fee_out));
- } catch (const std::runtime_error&) {
- }
- break;
- }
- case 3: {
- const CTransaction transaction{random_mutable_transaction};
- if (ContainsSpentInput(transaction, coins_view_cache)) {
- // Avoid:
- // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
- break;
- }
- (void)GetP2SHSigOpCount(transaction, coins_view_cache);
- break;
- }
- case 4: {
- const CTransaction transaction{random_mutable_transaction};
- if (ContainsSpentInput(transaction, coins_view_cache)) {
- // Avoid:
- // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
- break;
- }
- const int flags = fuzzed_data_provider.ConsumeIntegral<int>();
- if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
- // Avoid:
- // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
- break;
- }
- (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags);
- break;
- }
- case 5: {
- CCoinsStats stats;
- bool expected_code_path = false;
- try {
- (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED);
- } catch (const std::logic_error&) {
- expected_code_path = true;
- }
- assert(expected_code_path);
- break;
- }
- case 6: {
- (void)IsWitnessStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
- break;
- }
- }
+ assert(expected_code_path);
+ },
+ [&] {
+ (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
+ (void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
+ },
+ [&] {
+ TxValidationState state;
+ CAmount tx_fee_out;
+ const CTransaction transaction{random_mutable_transaction};
+ if (ContainsSpentInput(transaction, coins_view_cache)) {
+ // Avoid:
+ // consensus/tx_verify.cpp:171: bool Consensus::CheckTxInputs(const CTransaction &, TxValidationState &, const CCoinsViewCache &, int, CAmount &): Assertion `!coin.IsSpent()' failed.
+ return;
+ }
+ try {
+ (void)Consensus::CheckTxInputs(transaction, state, coins_view_cache, fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()), tx_fee_out);
+ assert(MoneyRange(tx_fee_out));
+ } catch (const std::runtime_error&) {
+ }
+ },
+ [&] {
+ const CTransaction transaction{random_mutable_transaction};
+ if (ContainsSpentInput(transaction, coins_view_cache)) {
+ // Avoid:
+ // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
+ return;
+ }
+ (void)GetP2SHSigOpCount(transaction, coins_view_cache);
+ },
+ [&] {
+ const CTransaction transaction{random_mutable_transaction};
+ if (ContainsSpentInput(transaction, coins_view_cache)) {
+ // Avoid:
+ // consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
+ return;
+ }
+ const int flags = fuzzed_data_provider.ConsumeIntegral<int>();
+ if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
+ // Avoid:
+ // script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.
+ return;
+ }
+ (void)GetTransactionSigOpCost(transaction, coins_view_cache, flags);
+ },
+ [&] {
+ CCoinsStats stats;
+ bool expected_code_path = false;
+ try {
+ (void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED);
+ } catch (const std::logic_error&) {
+ expected_code_path = true;
+ }
+ assert(expected_code_path);
+ },
+ [&] {
+ (void)IsWitnessStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
+ });
}
}
diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp
index c5702cf98e..71b4b00116 100644
--- a/src/test/fuzz/connman.cpp
+++ b/src/test/fuzz/connman.cpp
@@ -17,7 +17,7 @@
void initialize_connman()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(connman, initialize_connman)
@@ -32,114 +32,106 @@ FUZZ_TARGET_INIT(connman, initialize_connman)
CSubNet random_subnet;
std::string random_string;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 28)) {
- case 0:
- random_address = ConsumeAddress(fuzzed_data_provider);
- break;
- case 1:
- random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
- break;
- case 2:
- random_service = ConsumeService(fuzzed_data_provider);
- break;
- case 3:
- random_subnet = ConsumeSubNet(fuzzed_data_provider);
- break;
- case 4:
- random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
- break;
- case 5: {
- std::vector<CAddress> addresses;
- while (fuzzed_data_provider.ConsumeBool()) {
- addresses.push_back(ConsumeAddress(fuzzed_data_provider));
- }
- // Limit nTimePenalty to int32_t to avoid signed integer overflow
- (void)connman.AddNewAddresses(addresses, ConsumeAddress(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>());
- break;
- }
- case 6:
- connman.AddNode(random_string);
- break;
- case 7:
- connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- case 8:
- connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>());
- break;
- case 9:
- connman.DisconnectNode(random_netaddr);
- break;
- case 10:
- connman.DisconnectNode(random_string);
- break;
- case 11:
- connman.DisconnectNode(random_subnet);
- break;
- case 12:
- connman.ForEachNode([](auto) {});
- break;
- case 13:
- connman.ForEachNodeThen([](auto) {}, []() {});
- break;
- case 14:
- (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
- break;
- case 15:
- (void)connman.GetAddresses(fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
- break;
- case 16: {
- (void)connman.GetAddresses(random_node, fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
- break;
- }
- case 17:
- (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- case 18:
- (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL}));
- break;
- case 19:
- connman.MarkAddressGood(random_address);
- break;
- case 20:
- (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
- break;
- case 21:
- // Limit now to int32_t to avoid signed integer overflow
- (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral<int32_t>(), fuzzed_data_provider.ConsumeIntegral<int>());
- break;
- case 22: {
- CSerializedNetMsg serialized_net_msg;
- serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE);
- serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- connman.PushMessage(&random_node, std::move(serialized_net_msg));
- break;
- }
- case 23:
- connman.RemoveAddedNode(random_string);
- break;
- case 24: {
- const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
- if (SanityCheckASMap(asmap)) {
- connman.SetAsmap(asmap);
- }
- break;
- }
- case 25:
- connman.SetBestHeight(fuzzed_data_provider.ConsumeIntegral<int>());
- break;
- case 26:
- connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
- break;
- case 27:
- connman.SetServices(random_service, static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()));
- break;
- case 28:
- connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ random_address = ConsumeAddress(fuzzed_data_provider);
+ },
+ [&] {
+ random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
+ },
+ [&] {
+ random_service = ConsumeService(fuzzed_data_provider);
+ },
+ [&] {
+ random_subnet = ConsumeSubNet(fuzzed_data_provider);
+ },
+ [&] {
+ random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
+ },
+ [&] {
+ std::vector<CAddress> addresses;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ addresses.push_back(ConsumeAddress(fuzzed_data_provider));
+ }
+ // Limit nTimePenalty to int32_t to avoid signed integer overflow
+ (void)connman.AddNewAddresses(addresses, ConsumeAddress(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ },
+ [&] {
+ connman.AddNode(random_string);
+ },
+ [&] {
+ connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>());
+ },
+ [&] {
+ connman.DisconnectNode(random_netaddr);
+ },
+ [&] {
+ connman.DisconnectNode(random_string);
+ },
+ [&] {
+ connman.DisconnectNode(random_subnet);
+ },
+ [&] {
+ connman.ForEachNode([](auto) {});
+ },
+ [&] {
+ connman.ForEachNodeThen([](auto) {}, []() {});
+ },
+ [&] {
+ (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
+ },
+ [&] {
+ (void)connman.GetAddresses(fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
+ },
+ [&] {
+ (void)connman.GetAddresses(random_node, fuzzed_data_provider.ConsumeIntegral<size_t>(), fuzzed_data_provider.ConsumeIntegral<size_t>());
+ },
+ [&] {
+ (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL}));
+ },
+ [&] {
+ connman.MarkAddressGood(random_address);
+ },
+ [&] {
+ (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ // Limit now to int32_t to avoid signed integer overflow
+ (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral<int32_t>(), fuzzed_data_provider.ConsumeIntegral<int>());
+ },
+ [&] {
+ CSerializedNetMsg serialized_net_msg;
+ serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE);
+ serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ connman.PushMessage(&random_node, std::move(serialized_net_msg));
+ },
+ [&] {
+ connman.RemoveAddedNode(random_string);
+ },
+ [&] {
+ const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
+ if (SanityCheckASMap(asmap)) {
+ connman.SetAsmap(asmap);
+ }
+ },
+ [&] {
+ connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ connman.SetServices(random_service, ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS));
+ },
+ [&] {
+ connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
+ });
}
(void)connman.GetAddedNodeInfo();
- (void)connman.GetBestHeight();
(void)connman.GetExtraFullOutboundCount();
(void)connman.GetLocalServices();
(void)connman.GetMaxOutboundTarget();
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
index 4783cc1c43..c2bb3a1a4e 100644
--- a/src/test/fuzz/crypto.cpp
+++ b/src/test/fuzz/crypto.cpp
@@ -4,6 +4,7 @@
#include <crypto/hmac_sha256.h>
#include <crypto/hmac_sha512.h>
+#include <crypto/muhash.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
@@ -35,99 +36,98 @@ FUZZ_TARGET(crypto)
CSHA512 sha512;
SHA3_256 sha3;
CSipHasher sip_hasher{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
+ MuHash3072 muhash;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 2)) {
- case 0: {
- if (fuzzed_data_provider.ConsumeBool()) {
- data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- if (data.empty()) {
- data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (data.empty()) {
+ data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
}
- }
- (void)hash160.Write(data);
- (void)hash256.Write(data);
- (void)hmac_sha256.Write(data.data(), data.size());
- (void)hmac_sha512.Write(data.data(), data.size());
- (void)ripemd160.Write(data.data(), data.size());
- (void)sha1.Write(data.data(), data.size());
- (void)sha256.Write(data.data(), data.size());
- (void)sha3.Write(data);
- (void)sha512.Write(data.data(), data.size());
- (void)sip_hasher.Write(data.data(), data.size());
+ (void)hash160.Write(data);
+ (void)hash256.Write(data);
+ (void)hmac_sha256.Write(data.data(), data.size());
+ (void)hmac_sha512.Write(data.data(), data.size());
+ (void)ripemd160.Write(data.data(), data.size());
+ (void)sha1.Write(data.data(), data.size());
+ (void)sha256.Write(data.data(), data.size());
+ (void)sha3.Write(data);
+ (void)sha512.Write(data.data(), data.size());
+ (void)sip_hasher.Write(data.data(), data.size());
- (void)Hash(data);
- (void)Hash160(data);
- (void)sha512.Size();
- break;
- }
- case 1: {
- (void)hash160.Reset();
- (void)hash256.Reset();
- (void)ripemd160.Reset();
- (void)sha1.Reset();
- (void)sha256.Reset();
- (void)sha3.Reset();
- (void)sha512.Reset();
- break;
- }
- case 2: {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 9)) {
- case 0: {
- data.resize(CHash160::OUTPUT_SIZE);
- hash160.Finalize(data);
- break;
- }
- case 1: {
- data.resize(CHash256::OUTPUT_SIZE);
- hash256.Finalize(data);
- break;
- }
- case 2: {
- data.resize(CHMAC_SHA256::OUTPUT_SIZE);
- hmac_sha256.Finalize(data.data());
- break;
- }
- case 3: {
- data.resize(CHMAC_SHA512::OUTPUT_SIZE);
- hmac_sha512.Finalize(data.data());
- break;
- }
- case 4: {
- data.resize(CRIPEMD160::OUTPUT_SIZE);
- ripemd160.Finalize(data.data());
- break;
- }
- case 5: {
- data.resize(CSHA1::OUTPUT_SIZE);
- sha1.Finalize(data.data());
- break;
- }
- case 6: {
- data.resize(CSHA256::OUTPUT_SIZE);
- sha256.Finalize(data.data());
- break;
- }
- case 7: {
- data.resize(CSHA512::OUTPUT_SIZE);
- sha512.Finalize(data.data());
- break;
- }
- case 8: {
- data.resize(1);
- data[0] = sip_hasher.Finalize() % 256;
- break;
- }
- case 9: {
- data.resize(SHA3_256::OUTPUT_SIZE);
- sha3.Finalize(data);
- break;
- }
- }
- break;
- }
- }
+ (void)Hash(data);
+ (void)Hash160(data);
+ (void)sha512.Size();
+
+ if (fuzzed_data_provider.ConsumeBool()) {
+ muhash *= MuHash3072(data);
+ } else {
+ muhash /= MuHash3072(data);
+ }
+ },
+ [&] {
+ (void)hash160.Reset();
+ (void)hash256.Reset();
+ (void)ripemd160.Reset();
+ (void)sha1.Reset();
+ (void)sha256.Reset();
+ (void)sha3.Reset();
+ (void)sha512.Reset();
+ muhash = MuHash3072();
+ },
+ [&] {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ data.resize(CHash160::OUTPUT_SIZE);
+ hash160.Finalize(data);
+ },
+ [&] {
+ data.resize(CHash256::OUTPUT_SIZE);
+ hash256.Finalize(data);
+ },
+ [&] {
+ data.resize(CHMAC_SHA256::OUTPUT_SIZE);
+ hmac_sha256.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CHMAC_SHA512::OUTPUT_SIZE);
+ hmac_sha512.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CRIPEMD160::OUTPUT_SIZE);
+ ripemd160.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CSHA1::OUTPUT_SIZE);
+ sha1.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CSHA256::OUTPUT_SIZE);
+ sha256.Finalize(data.data());
+ },
+ [&] {
+ data.resize(CSHA512::OUTPUT_SIZE);
+ sha512.Finalize(data.data());
+ },
+ [&] {
+ data.resize(1);
+ data[0] = sip_hasher.Finalize() % 256;
+ },
+ [&] {
+ data.resize(SHA3_256::OUTPUT_SIZE);
+ sha3.Finalize(data);
+ },
+ [&] {
+ uint256 out;
+ muhash.Finalize(out);
+ });
+ });
}
if (fuzzed_data_provider.ConsumeBool()) {
uint64_t state[25];
diff --git a/src/test/fuzz/crypto_chacha20.cpp b/src/test/fuzz/crypto_chacha20.cpp
index d751466f11..bb8dd4594f 100644
--- a/src/test/fuzz/crypto_chacha20.cpp
+++ b/src/test/fuzz/crypto_chacha20.cpp
@@ -20,31 +20,26 @@ FUZZ_TARGET(crypto_chacha20)
chacha20 = ChaCha20{key.data(), key.size()};
}
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 4)) {
- case 0: {
- const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
- chacha20.SetKey(key.data(), key.size());
- break;
- }
- case 1: {
- chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- }
- case 2: {
- chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- }
- case 3: {
- std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- chacha20.Keystream(output.data(), output.size());
- break;
- }
- case 4: {
- std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
- const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
- chacha20.Crypt(input.data(), output.data(), input.size());
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::vector<unsigned char> key = ConsumeFixedLengthByteVector(fuzzed_data_provider, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(16, 32));
+ chacha20.SetKey(key.data(), key.size());
+ },
+ [&] {
+ chacha20.SetIV(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ chacha20.Seek(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ },
+ [&] {
+ std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ chacha20.Keystream(output.data(), output.size());
+ },
+ [&] {
+ std::vector<uint8_t> output(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
+ const std::vector<uint8_t> input = ConsumeFixedLengthByteVector(fuzzed_data_provider, output.size());
+ chacha20.Crypt(input.data(), output.data(), input.size());
+ });
}
}
diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
index 631af9c70d..0e1c44cded 100644
--- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
+++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp
@@ -29,44 +29,43 @@ FUZZ_TARGET(crypto_chacha20_poly1305_aead)
std::vector<uint8_t> out(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
bool is_encrypt = fuzzed_data_provider.ConsumeBool();
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 6)) {
- case 0: {
- buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(64, 4096);
- in = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
- out = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
- break;
- }
- case 1: {
- (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt);
- break;
- }
- case 2: {
- uint32_t len = 0;
- const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data());
- assert(ok);
- break;
- }
- case 3: {
- seqnr_payload += 1;
- aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
- if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
- aad_pos = 0;
- seqnr_aad += 1;
- }
- break;
- }
- case 4: {
- seqnr_payload = fuzzed_data_provider.ConsumeIntegral<int>();
- break;
- }
- case 5: {
- seqnr_aad = fuzzed_data_provider.ConsumeIntegral<int>();
- break;
- }
- case 6: {
- is_encrypt = fuzzed_data_provider.ConsumeBool();
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ buffer_size = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(64, 4096);
+ in = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
+ out = std::vector<uint8_t>(buffer_size + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
+ },
+ [&] {
+ (void)aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffer_size, is_encrypt);
+ },
+ [&] {
+ uint32_t len = 0;
+ const bool ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data());
+ assert(ok);
+ },
+ [&] {
+ if (AdditionOverflow(seqnr_payload, static_cast<uint64_t>(1))) {
+ return;
+ }
+ seqnr_payload += 1;
+ aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
+ if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
+ aad_pos = 0;
+ if (AdditionOverflow(seqnr_aad, static_cast<uint64_t>(1))) {
+ return;
+ }
+ seqnr_aad += 1;
+ }
+ },
+ [&] {
+ seqnr_payload = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ },
+ [&] {
+ seqnr_aad = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
+ },
+ [&] {
+ is_encrypt = fuzzed_data_provider.ConsumeBool();
+ });
}
}
diff --git a/src/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp
new file mode 100644
index 0000000000..f3b6e6af04
--- /dev/null
+++ b/src/test/fuzz/data_stream.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2020 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 <net.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <vector>
+
+void initialize_data_stream_addr_man()
+{
+ static const auto testing_setup = MakeFuzzingContext<>();
+}
+
+FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider);
+ CAddrMan addr_man;
+ CAddrDB::Read(addr_man, data_stream);
+}
diff --git a/src/test/fuzz/decode_tx.cpp b/src/test/fuzz/decode_tx.cpp
index 249f5a3cda..57431e65ba 100644
--- a/src/test/fuzz/decode_tx.cpp
+++ b/src/test/fuzz/decode_tx.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
index 544379c0b0..52841e069a 100644
--- a/src/test/fuzz/fuzz.h
+++ b/src/test/fuzz/fuzz.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,7 @@ using TypeInitialize = std::function<void()>;
void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, TypeInitialize init);
-void FuzzFrameworkEmptyFun() {}
+inline void FuzzFrameworkEmptyFun() {}
#define FUZZ_TARGET(name) \
FUZZ_TARGET_INIT(name, FuzzFrameworkEmptyFun)
diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp
index 0656ddc547..fa4024fc38 100644
--- a/src/test/fuzz/kitchen_sink.cpp
+++ b/src/test/fuzz/kitchen_sink.cpp
@@ -2,6 +2,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <merkleblock.h>
+#include <policy/fees.h>
#include <rpc/util.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
@@ -9,9 +11,25 @@
#include <util/error.h>
#include <util/translation.h>
+#include <array>
#include <cstdint>
#include <vector>
+namespace {
+constexpr TransactionError ALL_TRANSACTION_ERROR[] = {
+ TransactionError::OK,
+ TransactionError::MISSING_INPUTS,
+ TransactionError::ALREADY_IN_CHAIN,
+ TransactionError::P2P_DISABLED,
+ TransactionError::MEMPOOL_REJECTED,
+ TransactionError::MEMPOOL_ERROR,
+ TransactionError::INVALID_PSBT,
+ TransactionError::PSBT_MISMATCH,
+ TransactionError::SIGHASH_MISMATCH,
+ TransactionError::MAX_FEE_EXCEEDED,
+};
+}; // namespace
+
// The fuzzing kitchen sink: Fuzzing harness for functions that need to be
// fuzzed but a.) don't belong in any existing fuzzing harness file, and
// b.) are not important enough to warrant their own fuzzing harness file.
@@ -19,8 +37,23 @@ FUZZ_TARGET(kitchen_sink)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
- const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray<TransactionError>({TransactionError::OK, TransactionError::MISSING_INPUTS, TransactionError::ALREADY_IN_CHAIN, TransactionError::P2P_DISABLED, TransactionError::MEMPOOL_REJECTED, TransactionError::MEMPOOL_ERROR, TransactionError::INVALID_PSBT, TransactionError::PSBT_MISMATCH, TransactionError::SIGHASH_MISMATCH, TransactionError::MAX_FEE_EXCEEDED});
+ const TransactionError transaction_error = fuzzed_data_provider.PickValueInArray(ALL_TRANSACTION_ERROR);
(void)JSONRPCTransactionError(transaction_error);
(void)RPCErrorFromTransactionError(transaction_error);
(void)TransactionErrorString(transaction_error);
+
+ (void)StringForFeeEstimateHorizon(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
+
+ const OutputType output_type = fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES);
+ const std::string& output_type_string = FormatOutputType(output_type);
+ OutputType output_type_parsed;
+ const bool parsed = ParseOutputType(output_type_string, output_type_parsed);
+ assert(parsed);
+ assert(output_type == output_type_parsed);
+ (void)ParseOutputType(fuzzed_data_provider.ConsumeRandomLengthString(64), output_type_parsed);
+
+ const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ const std::vector<bool> bits = BytesToBits(bytes);
+ const std::vector<uint8_t> bytes_decoded = BitsToBytes(bits);
+ assert(bytes == bytes_decoded);
}
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
index c428a86631..207ee586bc 100644
--- a/src/test/fuzz/load_external_block_file.cpp
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -15,7 +15,7 @@
void initialize_load_external_block_file()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
}
FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)
diff --git a/src/test/fuzz/merkleblock.cpp b/src/test/fuzz/merkleblock.cpp
index 15bcfab3ad..23e0baa564 100644
--- a/src/test/fuzz/merkleblock.cpp
+++ b/src/test/fuzz/merkleblock.cpp
@@ -17,33 +17,31 @@ FUZZ_TARGET(merkleblock)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CPartialMerkleTree partial_merkle_tree;
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 1)) {
- case 0: {
- const std::optional<CPartialMerkleTree> opt_partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider);
- if (opt_partial_merkle_tree) {
- partial_merkle_tree = *opt_partial_merkle_tree;
- }
- break;
- }
- case 1: {
- CMerkleBlock merkle_block;
- const std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
- CBloomFilter bloom_filter;
- std::set<uint256> txids;
- if (opt_block && !opt_block->vtx.empty()) {
- if (fuzzed_data_provider.ConsumeBool()) {
- merkle_block = CMerkleBlock{*opt_block, bloom_filter};
- } else if (fuzzed_data_provider.ConsumeBool()) {
- while (fuzzed_data_provider.ConsumeBool()) {
- txids.insert(ConsumeUInt256(fuzzed_data_provider));
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::optional<CPartialMerkleTree> opt_partial_merkle_tree = ConsumeDeserializable<CPartialMerkleTree>(fuzzed_data_provider);
+ if (opt_partial_merkle_tree) {
+ partial_merkle_tree = *opt_partial_merkle_tree;
+ }
+ },
+ [&] {
+ CMerkleBlock merkle_block;
+ const std::optional<CBlock> opt_block = ConsumeDeserializable<CBlock>(fuzzed_data_provider);
+ CBloomFilter bloom_filter;
+ std::set<uint256> txids;
+ if (opt_block && !opt_block->vtx.empty()) {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ merkle_block = CMerkleBlock{*opt_block, bloom_filter};
+ } else if (fuzzed_data_provider.ConsumeBool()) {
+ while (fuzzed_data_provider.ConsumeBool()) {
+ txids.insert(ConsumeUInt256(fuzzed_data_provider));
+ }
+ merkle_block = CMerkleBlock{*opt_block, txids};
}
- merkle_block = CMerkleBlock{*opt_block, txids};
}
- }
- partial_merkle_tree = merkle_block.txn;
- break;
- }
- }
+ partial_merkle_tree = merkle_block.txn;
+ });
(void)partial_merkle_tree.GetNumTransactions();
std::vector<uint256> matches;
std::vector<unsigned int> indices;
diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp
new file mode 100644
index 0000000000..8f843ca773
--- /dev/null
+++ b/src/test/fuzz/muhash.cpp
@@ -0,0 +1,53 @@
+// Copyright (c) 2020 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 <crypto/muhash.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <vector>
+
+FUZZ_TARGET(muhash)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ std::vector<uint8_t> data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (data.empty()) {
+ data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+ if (data2.empty()) {
+ data2.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+
+ data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+
+ MuHash3072 muhash;
+
+ // Test that MuHash result is consistent independent of order of operations
+ muhash.Insert(data);
+ muhash.Insert(data2);
+
+ uint256 out;
+ muhash.Finalize(out);
+
+ muhash = MuHash3072();
+ muhash.Insert(data2);
+ muhash.Insert(data);
+
+ uint256 out2;
+ muhash.Finalize(out2);
+
+ assert(out == out2);
+
+ // Test that removing all added elements brings the object back to it's initial state
+ muhash /= muhash;
+ muhash.Finalize(out);
+
+ MuHash3072 muhash2;
+ muhash2.Finalize(out2);
+
+ assert(out == out2);
+}
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 66d7c512e4..21dca4eb05 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -13,6 +13,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <cstdint>
@@ -21,114 +22,84 @@
void initialize_net()
{
- static const BasicTestingSetup basic_testing_setup;
+ static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::MAIN);
}
FUZZ_TARGET_INIT(net, initialize_net)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
SetMockTime(ConsumeTime(fuzzed_data_provider));
- const std::optional<CAddress> address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!address) {
- return;
- }
- const std::optional<CAddress> address_bind = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!address_bind) {
- return;
- }
-
- CNode node{fuzzed_data_provider.ConsumeIntegral<NodeId>(),
- static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
- fuzzed_data_provider.ConsumeIntegral<int>(),
- INVALID_SOCKET,
- *address,
- fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
- fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
- *address_bind,
- fuzzed_data_provider.ConsumeRandomLengthString(32),
- fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH}),
- fuzzed_data_provider.ConsumeBool()};
+ CNode node{ConsumeNode(fuzzed_data_provider)};
node.SetCommonVersion(fuzzed_data_provider.ConsumeIntegral<int>());
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10)) {
- case 0: {
- node.CloseSocketDisconnect();
- break;
- }
- case 1: {
- node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
- break;
- }
- case 2: {
- const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
- if (!SanityCheckASMap(asmap)) {
- break;
- }
- CNodeStats stats;
- node.copyStats(stats, asmap);
- break;
- }
- case 3: {
- const CNode* add_ref_node = node.AddRef();
- assert(add_ref_node == &node);
- break;
- }
- case 4: {
- if (node.GetRefCount() > 0) {
- node.Release();
- }
- break;
- }
- case 5: {
- if (node.m_addr_known == nullptr) {
- break;
- }
- const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!addr_opt) {
- break;
- }
- node.AddAddressKnown(*addr_opt);
- break;
- }
- case 6: {
- if (node.m_addr_known == nullptr) {
- break;
- }
- const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
- if (!addr_opt) {
- break;
- }
- FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
- node.PushAddress(*addr_opt, fast_random_context);
- break;
- }
- case 7: {
- const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
- if (!inv_opt) {
- break;
- }
- node.AddKnownTx(inv_opt->hash);
- break;
- }
- case 8: {
- node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
- break;
- }
- case 9: {
- const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
- if (!service_opt) {
- break;
- }
- node.SetAddrLocal(*service_opt);
- break;
- }
- case 10: {
- const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- bool complete;
- node.ReceiveMsgBytes(b, complete);
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ node.CloseSocketDisconnect();
+ },
+ [&] {
+ node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32));
+ },
+ [&] {
+ const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
+ if (!SanityCheckASMap(asmap)) {
+ return;
+ }
+ CNodeStats stats;
+ node.copyStats(stats, asmap);
+ },
+ [&] {
+ const CNode* add_ref_node = node.AddRef();
+ assert(add_ref_node == &node);
+ },
+ [&] {
+ if (node.GetRefCount() > 0) {
+ node.Release();
+ }
+ },
+ [&] {
+ if (node.m_addr_known == nullptr) {
+ return;
+ }
+ const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!addr_opt) {
+ return;
+ }
+ node.AddAddressKnown(*addr_opt);
+ },
+ [&] {
+ if (node.m_addr_known == nullptr) {
+ return;
+ }
+ const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider);
+ if (!addr_opt) {
+ return;
+ }
+ FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)};
+ node.PushAddress(*addr_opt, fast_random_context);
+ },
+ [&] {
+ const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider);
+ if (!inv_opt) {
+ return;
+ }
+ node.AddKnownTx(inv_opt->hash);
+ },
+ [&] {
+ node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider));
+ },
+ [&] {
+ const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider);
+ if (!service_opt) {
+ return;
+ }
+ node.SetAddrLocal(*service_opt);
+ },
+ [&] {
+ const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ bool complete;
+ node.ReceiveMsgBytes(b, complete);
+ });
}
(void)node.GetAddrLocal();
@@ -136,15 +107,12 @@ FUZZ_TARGET_INIT(net, initialize_net)
(void)node.GetId();
(void)node.GetLocalNonce();
(void)node.GetLocalServices();
- (void)node.GetMyStartingHeight();
const int ref_count = node.GetRefCount();
assert(ref_count >= 0);
(void)node.GetCommonVersion();
(void)node.RelayAddrsWithConn();
- const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ?
- fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) :
- static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
(void)node.HasPermission(net_permission_flags);
(void)node.ConnectedThroughNetwork();
}
diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp
index 3620e16d30..544a33047b 100644
--- a/src/test/fuzz/net_permissions.cpp
+++ b/src/test/fuzz/net_permissions.cpp
@@ -17,18 +17,7 @@ FUZZ_TARGET(net_permissions)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(32);
- const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({
- NetPermissionFlags::PF_NONE,
- NetPermissionFlags::PF_BLOOMFILTER,
- NetPermissionFlags::PF_RELAY,
- NetPermissionFlags::PF_FORCERELAY,
- NetPermissionFlags::PF_NOBAN,
- NetPermissionFlags::PF_MEMPOOL,
- NetPermissionFlags::PF_ADDR,
- NetPermissionFlags::PF_ISIMPLICIT,
- NetPermissionFlags::PF_ALL,
- }) :
- static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ const NetPermissionFlags net_permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
NetWhitebindPermissions net_whitebind_permissions;
bilingual_str error_net_whitebind_permissions;
diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp
new file mode 100644
index 0000000000..aaebe83c0a
--- /dev/null
+++ b/src/test/fuzz/node_eviction.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) 2020 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 <net.h>
+#include <optional.h>
+#include <protocol.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <optional>
+#include <vector>
+
+FUZZ_TARGET(node_eviction)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ std::vector<NodeEvictionCandidate> eviction_candidates;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ eviction_candidates.push_back({
+ fuzzed_data_provider.ConsumeIntegral<NodeId>(),
+ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ fuzzed_data_provider.ConsumeIntegral<int64_t>(),
+ fuzzed_data_provider.ConsumeBool(),
+ fuzzed_data_provider.ConsumeBool(),
+ fuzzed_data_provider.ConsumeBool(),
+ fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
+ fuzzed_data_provider.ConsumeBool(),
+ fuzzed_data_provider.ConsumeBool(),
+ });
+ }
+ // Make a copy since eviction_candidates may be in some valid but otherwise
+ // indeterminate state after the SelectNodeToEvict(&&) call.
+ const std::vector<NodeEvictionCandidate> eviction_candidates_copy = eviction_candidates;
+ const Optional<NodeId> node_to_evict = SelectNodeToEvict(std::move(eviction_candidates));
+ if (node_to_evict) {
+ assert(std::any_of(eviction_candidates_copy.begin(), eviction_candidates_copy.end(), [&node_to_evict](const NodeEvictionCandidate& eviction_candidate) { return *node_to_evict == eviction_candidate.id; }));
+ }
+}
diff --git a/src/test/fuzz/p2p_transport_deserializer.cpp b/src/test/fuzz/p2p_transport_deserializer.cpp
index 6ba75309c8..163f1b839e 100644
--- a/src/test/fuzz/p2p_transport_deserializer.cpp
+++ b/src/test/fuzz/p2p_transport_deserializer.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/parse_hd_keypath.cpp b/src/test/fuzz/parse_hd_keypath.cpp
index 7d0d5643bf..411b70230a 100644
--- a/src/test/fuzz/parse_hd_keypath.cpp
+++ b/src/test/fuzz/parse_hd_keypath.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/parse_iso8601.cpp b/src/test/fuzz/parse_iso8601.cpp
index 4d5fa70dfa..dcb24ac127 100644
--- a/src/test/fuzz/parse_iso8601.cpp
+++ b/src/test/fuzz/parse_iso8601.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/parse_numbers.cpp b/src/test/fuzz/parse_numbers.cpp
index 89d9be392e..ddd2bcfba3 100644
--- a/src/test/fuzz/parse_numbers.cpp
+++ b/src/test/fuzz/parse_numbers.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/parse_script.cpp b/src/test/fuzz/parse_script.cpp
index 1382afbc2c..060ad3db12 100644
--- a/src/test/fuzz/parse_script.cpp
+++ b/src/test/fuzz/parse_script.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 8a17a4b51b..fff893fb3f 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -16,7 +16,7 @@
void initialize_policy_estimator()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
@@ -24,52 +24,48 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CBlockPolicyEstimator block_policy_estimator;
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 3)) {
- case 0: {
- const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
- if (!mtx) {
- break;
- }
- const CTransaction tx{*mtx};
- block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool());
- if (fuzzed_data_provider.ConsumeBool()) {
- (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool());
- }
- break;
- }
- case 1: {
- std::vector<CTxMemPoolEntry> mempool_entries;
- while (fuzzed_data_provider.ConsumeBool()) {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
if (!mtx) {
- break;
+ return;
}
const CTransaction tx{*mtx};
- mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
- }
- std::vector<const CTxMemPoolEntry*> ptrs;
- ptrs.reserve(mempool_entries.size());
- for (const CTxMemPoolEntry& mempool_entry : mempool_entries) {
- ptrs.push_back(&mempool_entry);
- }
- block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs);
- break;
- }
- case 2: {
- (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 3: {
- block_policy_estimator.FlushUnconfirmed();
- break;
- }
- }
+ block_policy_estimator.processTransaction(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx), fuzzed_data_provider.ConsumeBool());
+ if (fuzzed_data_provider.ConsumeBool()) {
+ (void)block_policy_estimator.removeTx(tx.GetHash(), /* inBlock */ fuzzed_data_provider.ConsumeBool());
+ }
+ },
+ [&] {
+ std::vector<CTxMemPoolEntry> mempool_entries;
+ while (fuzzed_data_provider.ConsumeBool()) {
+ const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider);
+ if (!mtx) {
+ break;
+ }
+ const CTransaction tx{*mtx};
+ mempool_entries.push_back(ConsumeTxMemPoolEntry(fuzzed_data_provider, tx));
+ }
+ std::vector<const CTxMemPoolEntry*> ptrs;
+ ptrs.reserve(mempool_entries.size());
+ for (const CTxMemPoolEntry& mempool_entry : mempool_entries) {
+ ptrs.push_back(&mempool_entry);
+ }
+ block_policy_estimator.processBlock(fuzzed_data_provider.ConsumeIntegral<unsigned int>(), ptrs);
+ },
+ [&] {
+ (void)block_policy_estimator.removeTx(ConsumeUInt256(fuzzed_data_provider), /* inBlock */ fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ block_policy_estimator.FlushUnconfirmed();
+ });
(void)block_policy_estimator.estimateFee(fuzzed_data_provider.ConsumeIntegral<int>());
EstimationResult result;
- (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
+ (void)block_policy_estimator.estimateRawFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeFloatingPoint<double>(), fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS), fuzzed_data_provider.ConsumeBool() ? &result : nullptr);
FeeCalculation fee_calculation;
(void)block_policy_estimator.estimateSmartFee(fuzzed_data_provider.ConsumeIntegral<int>(), fuzzed_data_provider.ConsumeBool() ? &fee_calculation : nullptr, fuzzed_data_provider.ConsumeBool());
- (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray({FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}));
+ (void)block_policy_estimator.HighestTargetTracked(fuzzed_data_provider.PickValueInArray(ALL_FEE_ESTIMATE_HORIZONS));
}
{
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 8fa52143d8..73242870a0 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -12,7 +12,7 @@
void initialize_policy_estimator_io()
{
- InitializeFuzzingContext();
+ static const auto testing_setup = MakeFuzzingContext<>();
}
FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp
index 02beb6eb37..c4348495bf 100644
--- a/src/test/fuzz/pow.cpp
+++ b/src/test/fuzz/pow.cpp
@@ -43,7 +43,10 @@ FUZZ_TARGET_INIT(pow, initialize_pow)
current_block.nHeight = current_height;
}
if (fuzzed_data_provider.ConsumeBool()) {
- current_block.nTime = fixed_time + current_height * consensus_params.nPowTargetSpacing;
+ const uint32_t seconds = current_height * consensus_params.nPowTargetSpacing;
+ if (!AdditionOverflow(fixed_time, seconds)) {
+ current_block.nTime = fixed_time + seconds;
+ }
}
if (fuzzed_data_provider.ConsumeBool()) {
current_block.nBits = fixed_bits;
diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp
index 01de8bdbb5..e7cc0f5297 100644
--- a/src/test/fuzz/process_message.cpp
+++ b/src/test/fuzz/process_message.cpp
@@ -13,6 +13,7 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
#include <test/util/mining.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
@@ -37,14 +38,8 @@ const TestingSetup* g_setup;
void initialize_process_message()
{
- static TestingSetup setup{
- CBaseChainParams::REGTEST,
- {
- "-nodebuglogfile",
- },
- };
- g_setup = &setup;
-
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
@@ -54,27 +49,38 @@ void initialize_process_message()
void fuzz_target(const std::vector<uint8_t>& buffer, const std::string& LIMIT_TO_MESSAGE_TYPE)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
+
ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate();
+ SetMockTime(1610000000); // any time to successfully reset ibd
chainstate.ResetIbd();
+
const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()};
if (!LIMIT_TO_MESSAGE_TYPE.empty() && random_message_type != LIMIT_TO_MESSAGE_TYPE) {
return;
}
- const bool jump_out_of_ibd{fuzzed_data_provider.ConsumeBool()};
- if (jump_out_of_ibd) chainstate.JumpOutOfIbd();
- CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION};
- CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY).release();
- p2p_node.fSuccessfullyConnected = true;
- p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetCommonVersion(PROTOCOL_VERSION);
+ CNode& p2p_node = *ConsumeNodeAsUniquePtr(fuzzed_data_provider).release();
+
+ const bool successfully_connected{true};
+ p2p_node.fSuccessfullyConnected = successfully_connected;
connman.AddTestNode(p2p_node);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
+ FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected);
+
+ const auto mock_time = ConsumeTime(fuzzed_data_provider);
+ SetMockTime(mock_time);
+
+ // fuzzed_data_provider is fully consumed after this call, don't use it
+ CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION};
try {
g_setup->m_node.peerman->ProcessMessage(p2p_node, random_message_type, random_bytes_data_stream,
GetTime<std::chrono::microseconds>(), std::atomic<bool>{false});
} catch (const std::ios_base::failure&) {
}
+ {
+ LOCK(p2p_node.cs_sendProcessing);
+ g_setup->m_node.peerman->SendMessages(&p2p_node);
+ }
SyncWithValidationInterfaceQueue();
LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement
g_setup->m_node.connman->StopNodes();
diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp
index e12e780a18..810f0aac92 100644
--- a/src/test/fuzz/process_messages.cpp
+++ b/src/test/fuzz/process_messages.cpp
@@ -17,18 +17,14 @@
#include <validation.h>
#include <validationinterface.h>
+namespace {
const TestingSetup* g_setup;
+} // namespace
void initialize_process_messages()
{
- static TestingSetup setup{
- CBaseChainParams::REGTEST,
- {
- "-nodebuglogfile",
- },
- };
- g_setup = &setup;
-
+ static const auto testing_setup = MakeFuzzingContext<const TestingSetup>();
+ g_setup = testing_setup.get();
for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
MineBlock(g_setup->m_node, CScript() << OP_TRUE);
}
@@ -41,31 +37,30 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
ConnmanTestMsg& connman = *(ConnmanTestMsg*)g_setup->m_node.connman.get();
TestChainState& chainstate = *(TestChainState*)&g_setup->m_node.chainman->ActiveChainstate();
+ SetMockTime(1610000000); // any time to successfully reset ibd
chainstate.ResetIbd();
- std::vector<CNode*> peers;
- bool jump_out_of_ibd{false};
+ std::vector<CNode*> peers;
const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3);
for (int i = 0; i < num_peers_to_add; ++i) {
- const ServiceFlags service_flags = ServiceFlags(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
- peers.push_back(MakeUnique<CNode>(i, service_flags, 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, conn_type).release());
+ peers.push_back(ConsumeNodeAsUniquePtr(fuzzed_data_provider, i).release());
CNode& p2p_node = *peers.back();
- p2p_node.fSuccessfullyConnected = true;
+ const bool successfully_connected{true};
+ p2p_node.fSuccessfullyConnected = successfully_connected;
p2p_node.fPauseSend = false;
- p2p_node.nVersion = PROTOCOL_VERSION;
- p2p_node.SetCommonVersion(PROTOCOL_VERSION);
g_setup->m_node.peerman->InitializeNode(&p2p_node);
+ FillNode(fuzzed_data_provider, p2p_node, /* init_version */ successfully_connected);
connman.AddTestNode(p2p_node);
}
while (fuzzed_data_provider.ConsumeBool()) {
- if (!jump_out_of_ibd) jump_out_of_ibd = fuzzed_data_provider.ConsumeBool();
- if (jump_out_of_ibd && chainstate.IsInitialBlockDownload()) chainstate.JumpOutOfIbd();
const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()};
+ const auto mock_time = ConsumeTime(fuzzed_data_provider);
+ SetMockTime(mock_time);
+
CSerializedNetMsg net_msg;
net_msg.m_type = random_message_type;
net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
@@ -79,6 +74,10 @@ FUZZ_TARGET_INIT(process_messages, initialize_process_messages)
connman.ProcessMessagesOnce(random_node);
} catch (const std::ios_base::failure&) {
}
+ {
+ LOCK(random_node.cs_sendProcessing);
+ g_setup->m_node.peerman->SendMessages(&random_node);
+ }
}
SyncWithValidationInterfaceQueue();
LOCK2(::cs_main, g_cs_orphans); // See init.cpp for rationale for implicit locking order requirement
diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp
index 6087ee964a..2a08b45aa3 100644
--- a/src/test/fuzz/rolling_bloom_filter.cpp
+++ b/src/test/fuzz/rolling_bloom_filter.cpp
@@ -22,29 +22,27 @@ FUZZ_TARGET(rolling_bloom_filter)
fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, 1000),
0.999 / fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(1, std::numeric_limits<unsigned int>::max())};
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) {
- case 0: {
- const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
- (void)rolling_bloom_filter.contains(b);
- rolling_bloom_filter.insert(b);
- const bool present = rolling_bloom_filter.contains(b);
- assert(present);
- break;
- }
- case 1: {
- const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
- if (!u256) {
- break;
- }
- (void)rolling_bloom_filter.contains(*u256);
- rolling_bloom_filter.insert(*u256);
- const bool present = rolling_bloom_filter.contains(*u256);
- assert(present);
- break;
- }
- case 2:
- rolling_bloom_filter.reset();
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ (void)rolling_bloom_filter.contains(b);
+ rolling_bloom_filter.insert(b);
+ const bool present = rolling_bloom_filter.contains(b);
+ assert(present);
+ },
+ [&] {
+ const std::optional<uint256> u256 = ConsumeDeserializable<uint256>(fuzzed_data_provider);
+ if (!u256) {
+ return;
+ }
+ (void)rolling_bloom_filter.contains(*u256);
+ rolling_bloom_filter.insert(*u256);
+ const bool present = rolling_bloom_filter.contains(*u256);
+ assert(present);
+ },
+ [&] {
+ rolling_bloom_filter.reset();
+ });
}
}
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index 892af655f6..7fadf36f98 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -71,7 +71,22 @@ FUZZ_TARGET_INIT(script, initialize_script)
(void)IsSolvable(signing_provider, script);
TxoutType which_type;
- (void)IsStandard(script, which_type);
+ bool is_standard_ret = IsStandard(script, which_type);
+ if (!is_standard_ret) {
+ assert(which_type == TxoutType::NONSTANDARD ||
+ which_type == TxoutType::NULL_DATA ||
+ which_type == TxoutType::MULTISIG);
+ }
+ if (which_type == TxoutType::NONSTANDARD) {
+ assert(!is_standard_ret);
+ }
+ if (which_type == TxoutType::NULL_DATA) {
+ assert(script.IsUnspendable());
+ }
+ if (script.IsUnspendable()) {
+ assert(which_type == TxoutType::NULL_DATA ||
+ which_type == TxoutType::NONSTANDARD);
+ }
(void)RecursiveDynamicUsage(script);
@@ -82,7 +97,6 @@ FUZZ_TARGET_INIT(script, initialize_script)
(void)script.IsPayToScriptHash();
(void)script.IsPayToWitnessScriptHash();
(void)script.IsPushOnly();
- (void)script.IsUnspendable();
(void)script.GetSigOpCount(/* fAccurate= */ false);
(void)FormatScript(script);
@@ -140,13 +154,13 @@ FUZZ_TARGET_INIT(script, initialize_script)
{
WitnessUnknown witness_unknown_1{};
- witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown_1.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown_1.length = witness_unknown_program_1.size();
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown_1.program);
WitnessUnknown witness_unknown_2{};
- witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<int>();
+ witness_unknown_2.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
const std::vector<uint8_t> witness_unknown_program_2 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
witness_unknown_2.length = witness_unknown_program_2.size();
std::copy(witness_unknown_program_2.begin(), witness_unknown_program_2.end(), witness_unknown_2.program);
diff --git a/src/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp
index d232e984bc..bdbfe817ff 100644
--- a/src/test/fuzz/script_ops.cpp
+++ b/src/test/fuzz/script_ops.cpp
@@ -16,56 +16,53 @@ FUZZ_TARGET(script_ops)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CScript script = ConsumeScript(fuzzed_data_provider);
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) {
- case 0: {
- CScript s = ConsumeScript(fuzzed_data_provider);
- script = std::move(s);
- break;
- }
- case 1: {
- const CScript& s = ConsumeScript(fuzzed_data_provider);
- script = s;
- break;
- }
- case 2:
- script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- case 3:
- script << ConsumeOpcodeType(fuzzed_data_provider);
- break;
- case 4:
- script << ConsumeScriptNum(fuzzed_data_provider);
- break;
- case 5:
- script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
- break;
- case 6:
- script.clear();
- break;
- case 7: {
- (void)script.GetSigOpCount(false);
- (void)script.GetSigOpCount(true);
- (void)script.GetSigOpCount(script);
- (void)script.HasValidOps();
- (void)script.IsPayToScriptHash();
- (void)script.IsPayToWitnessScriptHash();
- (void)script.IsPushOnly();
- (void)script.IsUnspendable();
- {
- CScript::const_iterator pc = script.begin();
- opcodetype opcode;
- (void)script.GetOp(pc, opcode);
- std::vector<uint8_t> data;
- (void)script.GetOp(pc, opcode, data);
- (void)script.IsPushOnly(pc);
- }
- {
- int version;
- std::vector<uint8_t> program;
- (void)script.IsWitnessProgram(version, program);
- }
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ CScript s = ConsumeScript(fuzzed_data_provider);
+ script = std::move(s);
+ },
+ [&] {
+ const CScript& s = ConsumeScript(fuzzed_data_provider);
+ script = s;
+ },
+ [&] {
+ script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ },
+ [&] {
+ script << ConsumeOpcodeType(fuzzed_data_provider);
+ },
+ [&] {
+ script << ConsumeScriptNum(fuzzed_data_provider);
+ },
+ [&] {
+ script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ },
+ [&] {
+ script.clear();
+ },
+ [&] {
+ (void)script.GetSigOpCount(false);
+ (void)script.GetSigOpCount(true);
+ (void)script.GetSigOpCount(script);
+ (void)script.HasValidOps();
+ (void)script.IsPayToScriptHash();
+ (void)script.IsPayToWitnessScriptHash();
+ (void)script.IsPushOnly();
+ (void)script.IsUnspendable();
+ {
+ CScript::const_iterator pc = script.begin();
+ opcodetype opcode;
+ (void)script.GetOp(pc, opcode);
+ std::vector<uint8_t> data;
+ (void)script.GetOp(pc, opcode, data);
+ (void)script.IsPushOnly(pc);
+ }
+ {
+ int version;
+ std::vector<uint8_t> program;
+ (void)script.IsWitnessProgram(version, program);
+ }
+ });
}
}
diff --git a/src/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp
index 650318f13c..bc4867839c 100644
--- a/src/test/fuzz/scriptnum_ops.cpp
+++ b/src/test/fuzz/scriptnum_ops.cpp
@@ -29,105 +29,99 @@ FUZZ_TARGET(scriptnum_ops)
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
CScriptNum script_num = ConsumeScriptNum(fuzzed_data_provider);
while (fuzzed_data_provider.remaining_bytes() > 0) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) {
- case 0: {
- const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- assert((script_num == i) != (script_num != i));
- assert((script_num <= i) != (script_num > i));
- assert((script_num >= i) != (script_num < i));
- // Avoid signed integer overflow:
- // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long'
- if (IsValidAddition(script_num, CScriptNum{i})) {
- assert((script_num + i) - i == script_num);
- }
- // Avoid signed integer overflow:
- // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long'
- if (IsValidSubtraction(script_num, CScriptNum{i})) {
- assert((script_num - i) + i == script_num);
- }
- break;
- }
- case 1: {
- const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
- assert((script_num == random_script_num) != (script_num != random_script_num));
- assert((script_num <= random_script_num) != (script_num > random_script_num));
- assert((script_num >= random_script_num) != (script_num < random_script_num));
- // Avoid signed integer overflow:
- // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long'
- if (IsValidAddition(script_num, random_script_num)) {
- assert((script_num + random_script_num) - random_script_num == script_num);
- }
- // Avoid signed integer overflow:
- // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long'
- if (IsValidSubtraction(script_num, random_script_num)) {
- assert((script_num - random_script_num) + random_script_num == script_num);
- }
- break;
- }
- case 2: {
- const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
- if (!IsValidAddition(script_num, random_script_num)) {
- // Avoid assertion failure:
- // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
- break;
- }
- script_num += random_script_num;
- break;
- }
- case 3: {
- const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
- if (!IsValidSubtraction(script_num, random_script_num)) {
- // Avoid assertion failure:
- // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
- break;
- }
- script_num -= random_script_num;
- break;
- }
- case 4:
- script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- case 5:
- script_num = script_num & ConsumeScriptNum(fuzzed_data_provider);
- break;
- case 6:
- script_num &= ConsumeScriptNum(fuzzed_data_provider);
- break;
- case 7:
- if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) {
- // Avoid assertion failure:
- // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed.
- break;
- }
- script_num = -script_num;
- break;
- case 8:
- script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- case 9: {
- const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- if (!IsValidAddition(script_num, CScriptNum{random_integer})) {
- // Avoid assertion failure:
- // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
- break;
- }
- script_num += random_integer;
- break;
- }
- case 10: {
- const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
- if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) {
- // Avoid assertion failure:
- // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
- break;
- }
- script_num -= random_integer;
- break;
- }
- case 11:
- script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>();
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ assert((script_num == i) != (script_num != i));
+ assert((script_num <= i) != (script_num > i));
+ assert((script_num >= i) != (script_num < i));
+ // Avoid signed integer overflow:
+ // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long'
+ if (IsValidAddition(script_num, CScriptNum{i})) {
+ assert((script_num + i) - i == script_num);
+ }
+ // Avoid signed integer overflow:
+ // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long'
+ if (IsValidSubtraction(script_num, CScriptNum{i})) {
+ assert((script_num - i) + i == script_num);
+ }
+ },
+ [&] {
+ const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
+ assert((script_num == random_script_num) != (script_num != random_script_num));
+ assert((script_num <= random_script_num) != (script_num > random_script_num));
+ assert((script_num >= random_script_num) != (script_num < random_script_num));
+ // Avoid signed integer overflow:
+ // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long'
+ if (IsValidAddition(script_num, random_script_num)) {
+ assert((script_num + random_script_num) - random_script_num == script_num);
+ }
+ // Avoid signed integer overflow:
+ // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long'
+ if (IsValidSubtraction(script_num, random_script_num)) {
+ assert((script_num - random_script_num) + random_script_num == script_num);
+ }
+ },
+ [&] {
+ const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
+ if (!IsValidAddition(script_num, random_script_num)) {
+ // Avoid assertion failure:
+ // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
+ return;
+ }
+ script_num += random_script_num;
+ },
+ [&] {
+ const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider);
+ if (!IsValidSubtraction(script_num, random_script_num)) {
+ // Avoid assertion failure:
+ // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
+ return;
+ }
+ script_num -= random_script_num;
+ },
+ [&] {
+ script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ },
+ [&] {
+ script_num = script_num & ConsumeScriptNum(fuzzed_data_provider);
+ },
+ [&] {
+ script_num &= ConsumeScriptNum(fuzzed_data_provider);
+ },
+ [&] {
+ if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) {
+ // Avoid assertion failure:
+ // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed.
+ return;
+ }
+ script_num = -script_num;
+ },
+ [&] {
+ script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ },
+ [&] {
+ const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ if (!IsValidAddition(script_num, CScriptNum{random_integer})) {
+ // Avoid assertion failure:
+ // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed.
+ return;
+ }
+ script_num += random_integer;
+ },
+ [&] {
+ const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) {
+ // Avoid assertion failure:
+ // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed.
+ return;
+ }
+ script_num -= random_integer;
+ },
+ [&] {
+ script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>();
+ });
(void)script_num.getint();
(void)script_num.getvch();
}
diff --git a/src/test/fuzz/signet.cpp b/src/test/fuzz/signet.cpp
index 541322d484..83effec064 100644
--- a/src/test/fuzz/signet.cpp
+++ b/src/test/fuzz/signet.cpp
@@ -17,7 +17,7 @@
void initialize_signet()
{
- InitializeFuzzingContext(CBaseChainParams::SIGNET);
+ static const auto testing_setup = MakeFuzzingContext<>(CBaseChainParams::SIGNET);
}
FUZZ_TARGET_INIT(signet, initialize_signet)
diff --git a/src/test/fuzz/spanparsing.cpp b/src/test/fuzz/spanparsing.cpp
index 293a7e7e90..b8996632bc 100644
--- a/src/test/fuzz/spanparsing.cpp
+++ b/src/test/fuzz/spanparsing.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp
index 4af0e750ce..b66a7abfb3 100644
--- a/src/test/fuzz/strprintf.cpp
+++ b/src/test/fuzz/strprintf.cpp
@@ -4,6 +4,7 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
#include <tinyformat.h>
#include <util/strencodings.h>
#include <util/translation.h>
@@ -109,32 +110,32 @@ FUZZ_TARGET(str_printf)
}
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) {
- case 0:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
- break;
- case 1:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
- break;
- case 2:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
- break;
- case 3:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
- break;
- case 4:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
- break;
- case 5:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32));
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeRandomLengthString(32).c_str());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<signed char>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<unsigned char>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<char>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<char>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeBool());
+ });
} catch (const tinyformat::format_error&) {
}
@@ -155,40 +156,40 @@ FUZZ_TARGET(str_printf)
}
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) {
- case 0:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
- break;
- case 1:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
- break;
- case 2:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
- break;
- case 3:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
- break;
- case 4:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
- break;
- case 5:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
- break;
- case 6:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
- break;
- case 7:
- (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- break;
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<float>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeFloatingPoint<double>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int16_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int32_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<int64_t>());
+ },
+ [&] {
+ (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ (void)tinyformat::format(bilingual_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>());
+ });
} catch (const tinyformat::format_error&) {
}
}
diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp
index 375a8c1ed0..47b38b6d23 100644
--- a/src/test/fuzz/system.cpp
+++ b/src/test/fuzz/system.cpp
@@ -32,71 +32,63 @@ FUZZ_TARGET(system)
}
while (fuzzed_data_provider.ConsumeBool()) {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 7)) {
- case 0: {
- args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16));
- break;
- }
- case 1: {
- args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
- break;
- }
- case 2: {
- args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
- break;
- }
- case 3: {
- args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool());
- break;
- }
- case 4: {
- const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN});
- // Avoid hitting:
- // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
- const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
- if (args_manager.GetArgFlags(argument_name) != nullopt) {
- break;
- }
- args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>(), options_category);
- break;
- }
- case 5: {
- // Avoid hitting:
- // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
- const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider);
- std::vector<std::string> hidden_arguments;
- for (const std::string& name : names) {
- const std::string hidden_argument = GetArgumentName(name);
- if (args_manager.GetArgFlags(hidden_argument) != nullopt) {
- continue;
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ args_manager.SelectConfigNetwork(fuzzed_data_provider.ConsumeRandomLengthString(16));
+ },
+ [&] {
+ args_manager.SoftSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
+ },
+ [&] {
+ args_manager.ForceSetArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeRandomLengthString(16));
+ },
+ [&] {
+ args_manager.SoftSetBoolArg(fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeBool());
+ },
+ [&] {
+ const OptionsCategory options_category = fuzzed_data_provider.PickValueInArray<OptionsCategory>({OptionsCategory::OPTIONS, OptionsCategory::CONNECTION, OptionsCategory::WALLET, OptionsCategory::WALLET_DEBUG_TEST, OptionsCategory::ZMQ, OptionsCategory::DEBUG_TEST, OptionsCategory::CHAINPARAMS, OptionsCategory::NODE_RELAY, OptionsCategory::BLOCK_CREATION, OptionsCategory::RPC, OptionsCategory::GUI, OptionsCategory::COMMANDS, OptionsCategory::REGISTER_COMMANDS, OptionsCategory::HIDDEN});
+ // Avoid hitting:
+ // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
+ const std::string argument_name = GetArgumentName(fuzzed_data_provider.ConsumeRandomLengthString(16));
+ if (args_manager.GetArgFlags(argument_name) != nullopt) {
+ return;
}
- if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) {
- continue;
+ args_manager.AddArg(argument_name, fuzzed_data_provider.ConsumeRandomLengthString(16), fuzzed_data_provider.ConsumeIntegral<unsigned int>(), options_category);
+ },
+ [&] {
+ // Avoid hitting:
+ // util/system.cpp:425: void ArgsManager::AddArg(const std::string &, const std::string &, unsigned int, const OptionsCategory &): Assertion `ret.second' failed.
+ const std::vector<std::string> names = ConsumeRandomLengthStringVector(fuzzed_data_provider);
+ std::vector<std::string> hidden_arguments;
+ for (const std::string& name : names) {
+ const std::string hidden_argument = GetArgumentName(name);
+ if (args_manager.GetArgFlags(hidden_argument) != nullopt) {
+ continue;
+ }
+ if (std::find(hidden_arguments.begin(), hidden_arguments.end(), hidden_argument) != hidden_arguments.end()) {
+ continue;
+ }
+ hidden_arguments.push_back(hidden_argument);
}
- hidden_arguments.push_back(hidden_argument);
- }
- args_manager.AddHiddenArgs(hidden_arguments);
- break;
- }
- case 6: {
- args_manager.ClearArgs();
- break;
- }
- case 7: {
- const std::vector<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider);
- std::vector<const char*> argv;
- argv.reserve(random_arguments.size());
- for (const std::string& random_argument : random_arguments) {
- argv.push_back(random_argument.c_str());
- }
- try {
- std::string error;
- (void)args_manager.ParseParameters(argv.size(), argv.data(), error);
- } catch (const std::logic_error&) {
- }
- break;
- }
- }
+ args_manager.AddHiddenArgs(hidden_arguments);
+ },
+ [&] {
+ args_manager.ClearArgs();
+ },
+ [&] {
+ const std::vector<std::string> random_arguments = ConsumeRandomLengthStringVector(fuzzed_data_provider);
+ std::vector<const char*> argv;
+ argv.reserve(random_arguments.size());
+ for (const std::string& random_argument : random_arguments) {
+ argv.push_back(random_argument.c_str());
+ }
+ try {
+ std::string error;
+ (void)args_manager.ParseParameters(argv.size(), argv.data(), error);
+ } catch (const std::logic_error&) {
+ }
+ });
}
const std::string s1 = fuzzed_data_provider.ConsumeRandomLengthString(16);
diff --git a/src/test/fuzz/tx_in.cpp b/src/test/fuzz/tx_in.cpp
index dd94922b86..f8247c1fa4 100644
--- a/src/test/fuzz/tx_in.cpp
+++ b/src/test/fuzz/tx_in.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/tx_out.cpp b/src/test/fuzz/tx_out.cpp
index 5e22c4adc5..39a50b6c80 100644
--- a/src/test/fuzz/tx_out.cpp
+++ b/src/test/fuzz/tx_out.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
new file mode 100644
index 0000000000..0a541e4186
--- /dev/null
+++ b/src/test/fuzz/util.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) 2021 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 <test/fuzz/util.h>
+#include <version.h>
+
+void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept
+{
+ const ServiceFlags remote_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
+ const NetPermissionFlags permission_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
+ const int32_t version = fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max());
+ const bool filter_txs = fuzzed_data_provider.ConsumeBool();
+
+ node.nServices = remote_services;
+ node.m_permissionFlags = permission_flags;
+ if (init_version) {
+ node.nVersion = version;
+ node.SetCommonVersion(std::min(version, PROTOCOL_VERSION));
+ }
+ if (node.m_tx_relay != nullptr) {
+ LOCK(node.m_tx_relay->cs_filter);
+ node.m_tx_relay->fRelayTxes = filter_txs;
+ }
+}
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index cf666a8b93..a12dc9a56d 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -22,10 +22,12 @@
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/util/net.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/time.h>
+#include <util/vector.h>
#include <version.h>
#include <algorithm>
@@ -35,6 +37,17 @@
#include <string>
#include <vector>
+template <typename... Callables>
+void CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables)
+{
+ constexpr size_t call_size{sizeof...(callables)};
+ static_assert(call_size >= 1);
+ const size_t call_index{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, call_size - 1)};
+
+ size_t i{0};
+ return ((i++ == call_index ? callables() : void()), ...);
+}
+
[[nodiscard]] inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataProvider& fuzzed_data_provider, const size_t max_length = 4096) noexcept
{
const std::string s = fuzzed_data_provider.ConsumeRandomLengthString(max_length);
@@ -86,6 +99,14 @@ template <typename T>
return obj;
}
+template <typename WeakEnumType, size_t size>
+[[nodiscard]] WeakEnumType ConsumeWeakEnum(FuzzedDataProvider& fuzzed_data_provider, const WeakEnumType (&all_types)[size]) noexcept
+{
+ return fuzzed_data_provider.ConsumeBool() ?
+ fuzzed_data_provider.PickValueInArray<WeakEnumType>(all_types) :
+ WeakEnumType(fuzzed_data_provider.ConsumeIntegral<typename std::underlying_type<WeakEnumType>::type>());
+}
+
[[nodiscard]] inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE));
@@ -156,37 +177,31 @@ template <typename T>
[[nodiscard]] inline CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
CTxDestination tx_destination;
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
- case 0: {
- tx_destination = CNoDestination{};
- break;
- }
- case 1: {
- tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
- break;
- }
- case 2: {
- tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
- break;
- }
- case 3: {
- tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
- break;
- }
- case 4: {
- tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
- break;
- }
- case 5: {
- WitnessUnknown witness_unknown{};
- witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<int>();
- const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
- witness_unknown.length = witness_unknown_program_1.size();
- std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
- tx_destination = witness_unknown;
- break;
- }
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ tx_destination = CNoDestination{};
+ },
+ [&] {
+ tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
+ },
+ [&] {
+ tx_destination = ScriptHash{ConsumeUInt160(fuzzed_data_provider)};
+ },
+ [&] {
+ tx_destination = WitnessV0ScriptHash{ConsumeUInt256(fuzzed_data_provider)};
+ },
+ [&] {
+ tx_destination = WitnessV0KeyHash{ConsumeUInt160(fuzzed_data_provider)};
+ },
+ [&] {
+ WitnessUnknown witness_unknown{};
+ witness_unknown.version = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
+ const std::vector<uint8_t> witness_unknown_program_1 = fuzzed_data_provider.ConsumeBytes<uint8_t>(40);
+ witness_unknown.length = witness_unknown_program_1.size();
+ std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
+ tx_destination = witness_unknown;
+ });
return tx_destination;
}
@@ -249,7 +264,7 @@ template <class T>
return result;
}
-CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
+inline CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION});
CNetAddr net_addr;
@@ -271,40 +286,55 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
return net_addr;
}
-CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
+inline CSubNet ConsumeSubNet(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint8_t>()};
}
-CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
+inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
}
-CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
+inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
- return {ConsumeService(fuzzed_data_provider), static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
+ return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
}
-CNode ConsumeNode(FuzzedDataProvider& fuzzed_data_provider) noexcept
+template <bool ReturnUniquePtr = false>
+auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
{
- const NodeId node_id = fuzzed_data_provider.ConsumeIntegral<NodeId>();
- const ServiceFlags local_services = static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
- const int my_starting_height = fuzzed_data_provider.ConsumeIntegral<int>();
+ const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegral<NodeId>());
+ const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
const SOCKET socket = INVALID_SOCKET;
const CAddress address = ConsumeAddress(fuzzed_data_provider);
const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
const CAddress addr_bind = ConsumeAddress(fuzzed_data_provider);
const std::string addr_name = fuzzed_data_provider.ConsumeRandomLengthString(64);
- const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND_FULL_RELAY, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
- const bool inbound_onion = fuzzed_data_provider.ConsumeBool();
- return {node_id, local_services, my_starting_height, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion};
+ const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES);
+ const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
+ if constexpr (ReturnUniquePtr) {
+ return std::make_unique<CNode>(node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion);
+ } else {
+ return CNode{node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion};
+ }
}
+inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); }
+
+void FillNode(FuzzedDataProvider& fuzzed_data_provider, CNode& node, bool init_version) noexcept;
-void InitializeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST)
+template <class T = const BasicTestingSetup>
+std::unique_ptr<T> MakeFuzzingContext(const std::string& chain_name = CBaseChainParams::REGTEST, const std::vector<const char*>& extra_args = {})
{
- static const BasicTestingSetup basic_testing_setup{chain_name, {"-nodebuglogfile"}};
+ // Prepend default arguments for fuzzing
+ const std::vector<const char*> arguments = Cat(
+ {
+ "-nodebuglogfile",
+ },
+ extra_args);
+
+ return MakeUnique<T>(chain_name, arguments);
}
class FuzzedFileProvider
@@ -323,32 +353,26 @@ public:
return nullptr;
}
std::string mode;
- switch (m_fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5)) {
- case 0: {
- mode = "r";
- break;
- }
- case 1: {
- mode = "r+";
- break;
- }
- case 2: {
- mode = "w";
- break;
- }
- case 3: {
- mode = "w+";
- break;
- }
- case 4: {
- mode = "a";
- break;
- }
- case 5: {
- mode = "a+";
- break;
- }
- }
+ CallOneOf(
+ m_fuzzed_data_provider,
+ [&] {
+ mode = "r";
+ },
+ [&] {
+ mode = "r+";
+ },
+ [&] {
+ mode = "w";
+ },
+ [&] {
+ mode = "w+";
+ },
+ [&] {
+ mode = "a";
+ },
+ [&] {
+ mode = "a+";
+ });
#ifdef _GNU_SOURCE
const cookie_io_functions_t io_hooks = {
FuzzedFileProvider::read,
@@ -446,66 +470,64 @@ public:
return {fuzzed_data_provider};
}
-#define WRITE_TO_STREAM_CASE(id, type, consume) \
- case id: { \
- type o = consume; \
- stream << o; \
- break; \
+#define WRITE_TO_STREAM_CASE(type, consume) \
+ [&] { \
+ type o = consume; \
+ stream << o; \
}
template <typename Stream>
void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
{
while (fuzzed_data_provider.ConsumeBool()) {
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) {
- WRITE_TO_STREAM_CASE(0, bool, fuzzed_data_provider.ConsumeBool())
- WRITE_TO_STREAM_CASE(1, char, fuzzed_data_provider.ConsumeIntegral<char>())
- WRITE_TO_STREAM_CASE(2, int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>())
- WRITE_TO_STREAM_CASE(3, uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>())
- WRITE_TO_STREAM_CASE(4, int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>())
- WRITE_TO_STREAM_CASE(5, uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>())
- WRITE_TO_STREAM_CASE(6, int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>())
- WRITE_TO_STREAM_CASE(7, uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>())
- WRITE_TO_STREAM_CASE(8, int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>())
- WRITE_TO_STREAM_CASE(9, uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>())
- WRITE_TO_STREAM_CASE(10, float, fuzzed_data_provider.ConsumeFloatingPoint<float>())
- WRITE_TO_STREAM_CASE(11, double, fuzzed_data_provider.ConsumeFloatingPoint<double>())
- WRITE_TO_STREAM_CASE(12, std::string, fuzzed_data_provider.ConsumeRandomLengthString(32))
- WRITE_TO_STREAM_CASE(13, std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider))
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()),
+ WRITE_TO_STREAM_CASE(char, fuzzed_data_provider.ConsumeIntegral<char>()),
+ WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()),
+ WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()),
+ WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()),
+ WRITE_TO_STREAM_CASE(uint16_t, fuzzed_data_provider.ConsumeIntegral<uint16_t>()),
+ WRITE_TO_STREAM_CASE(int32_t, fuzzed_data_provider.ConsumeIntegral<int32_t>()),
+ WRITE_TO_STREAM_CASE(uint32_t, fuzzed_data_provider.ConsumeIntegral<uint32_t>()),
+ WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()),
+ WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()),
+ WRITE_TO_STREAM_CASE(float, fuzzed_data_provider.ConsumeFloatingPoint<float>()),
+ WRITE_TO_STREAM_CASE(double, fuzzed_data_provider.ConsumeFloatingPoint<double>()),
+ WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)),
+ WRITE_TO_STREAM_CASE(std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider)));
} catch (const std::ios_base::failure&) {
break;
}
}
}
-#define READ_FROM_STREAM_CASE(id, type) \
- case id: { \
- type o; \
- stream >> o; \
- break; \
+#define READ_FROM_STREAM_CASE(type) \
+ [&] { \
+ type o; \
+ stream >> o; \
}
template <typename Stream>
void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noexcept
{
while (fuzzed_data_provider.ConsumeBool()) {
try {
- switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 13)) {
- READ_FROM_STREAM_CASE(0, bool)
- READ_FROM_STREAM_CASE(1, char)
- READ_FROM_STREAM_CASE(2, int8_t)
- READ_FROM_STREAM_CASE(3, uint8_t)
- READ_FROM_STREAM_CASE(4, int16_t)
- READ_FROM_STREAM_CASE(5, uint16_t)
- READ_FROM_STREAM_CASE(6, int32_t)
- READ_FROM_STREAM_CASE(7, uint32_t)
- READ_FROM_STREAM_CASE(8, int64_t)
- READ_FROM_STREAM_CASE(9, uint64_t)
- READ_FROM_STREAM_CASE(10, float)
- READ_FROM_STREAM_CASE(11, double)
- READ_FROM_STREAM_CASE(12, std::string)
- READ_FROM_STREAM_CASE(13, std::vector<char>)
- }
+ CallOneOf(
+ fuzzed_data_provider,
+ READ_FROM_STREAM_CASE(bool),
+ READ_FROM_STREAM_CASE(char),
+ READ_FROM_STREAM_CASE(int8_t),
+ READ_FROM_STREAM_CASE(uint8_t),
+ READ_FROM_STREAM_CASE(int16_t),
+ READ_FROM_STREAM_CASE(uint16_t),
+ READ_FROM_STREAM_CASE(int32_t),
+ READ_FROM_STREAM_CASE(uint32_t),
+ READ_FROM_STREAM_CASE(int64_t),
+ READ_FROM_STREAM_CASE(uint64_t),
+ READ_FROM_STREAM_CASE(float),
+ READ_FROM_STREAM_CASE(double),
+ READ_FROM_STREAM_CASE(std::string),
+ READ_FROM_STREAM_CASE(std::vector<char>));
} catch (const std::ios_base::failure&) {
break;
}
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 9bc7cc5dab..942d54ede8 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 3de79a9f45..e967273636 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2019 The Bitcoin Core developers
+// Copyright (c) 2011-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index beac65942e..a1b41e17ed 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -181,7 +181,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
{
SOCKET hSocket = INVALID_SOCKET;
NodeId id = 0;
- int height = 0;
in_addr ipv4Addr;
ipv4Addr.s_addr = 0xa0b0c001;
@@ -190,7 +189,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
std::string pszDest;
std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(
- id++, NODE_NETWORK, height, hSocket, addr,
+ id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 0,
/* nLocalHostNonceIn = */ 0,
CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY);
@@ -200,10 +199,11 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode1->IsFeelerConn() == false);
BOOST_CHECK(pnode1->IsAddrFetchConn() == false);
BOOST_CHECK(pnode1->IsInboundConn() == false);
+ BOOST_CHECK(pnode1->IsInboundOnion() == false);
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(
- id++, NODE_NETWORK, height, hSocket, addr,
+ id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 1,
/* nLocalHostNonceIn = */ 1,
CAddress(), pszDest, ConnectionType::INBOUND,
@@ -214,24 +214,26 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode2->IsFeelerConn() == false);
BOOST_CHECK(pnode2->IsAddrFetchConn() == false);
BOOST_CHECK(pnode2->IsInboundConn() == true);
+ BOOST_CHECK(pnode2->IsInboundOnion() == false);
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
std::unique_ptr<CNode> pnode3 = MakeUnique<CNode>(
- id++, NODE_NETWORK, height, hSocket, addr,
+ id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 0,
/* nLocalHostNonceIn = */ 0,
CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY,
- /* inbound_onion = */ true);
+ /* inbound_onion = */ false);
BOOST_CHECK(pnode3->IsFullOutboundConn() == true);
BOOST_CHECK(pnode3->IsManualConn() == false);
BOOST_CHECK(pnode3->IsBlockOnlyConn() == false);
BOOST_CHECK(pnode3->IsFeelerConn() == false);
BOOST_CHECK(pnode3->IsAddrFetchConn() == false);
BOOST_CHECK(pnode3->IsInboundConn() == false);
+ BOOST_CHECK(pnode3->IsInboundOnion() == false);
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
std::unique_ptr<CNode> pnode4 = MakeUnique<CNode>(
- id++, NODE_NETWORK, height, hSocket, addr,
+ id++, NODE_NETWORK, hSocket, addr,
/* nKeyedNetGroupIn = */ 1,
/* nLocalHostNonceIn = */ 1,
CAddress(), pszDest, ConnectionType::INBOUND,
@@ -242,6 +244,7 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK(pnode4->IsFeelerConn() == false);
BOOST_CHECK(pnode4->IsAddrFetchConn() == false);
BOOST_CHECK(pnode4->IsInboundConn() == true);
+ BOOST_CHECK(pnode4->IsInboundOnion() == true);
BOOST_CHECK_EQUAL(pnode4->ConnectedThroughNetwork(), Network::NET_ONION);
}
@@ -676,7 +679,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
in_addr ipv4AddrPeer;
ipv4AddrPeer.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
- std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY);
+ std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND_FULL_RELAY);
pnode->fSuccessfullyConnected.store(true);
// the peer claims to be reaching us via IPv6
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index ac4db3a5b6..66ad7bb5ea 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -226,8 +226,22 @@ BOOST_AUTO_TEST_CASE(subnet_test)
// IPv4 address with IPv6 netmask or the other way around.
BOOST_CHECK(!CSubNet(ResolveIP("1.1.1.1"), ResolveIP("ffff::")).IsValid());
BOOST_CHECK(!CSubNet(ResolveIP("::1"), ResolveIP("255.0.0.0")).IsValid());
- // Can't subnet TOR (or any other non-IPv4 and non-IPv6 network).
- BOOST_CHECK(!CSubNet(ResolveIP("5wyqrzbvrdsumnok.onion"), ResolveIP("255.0.0.0")).IsValid());
+
+ // Create Non-IP subnets.
+
+ const CNetAddr tor_addr{
+ ResolveIP("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion")};
+
+ subnet = CSubNet(tor_addr);
+ BOOST_CHECK(subnet.IsValid());
+ BOOST_CHECK_EQUAL(subnet.ToString(), tor_addr.ToString());
+ BOOST_CHECK(subnet.Match(tor_addr));
+ BOOST_CHECK(
+ !subnet.Match(ResolveIP("kpgvmscirrdqpekbqjsvw5teanhatztpp2gl6eee4zkowvwfxwenqaid.onion")));
+ BOOST_CHECK(!subnet.Match(ResolveIP("1.2.3.4")));
+
+ BOOST_CHECK(!CSubNet(tor_addr, 200).IsValid());
+ BOOST_CHECK(!CSubNet(tor_addr, ResolveIP("255.0.0.0")).IsValid());
subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
@@ -442,8 +456,7 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("1.2.3.0/24\0example.com\0"s, ret));
- // We only do subnetting for IPv4 and IPv6
- BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret));
+ BOOST_CHECK(LookupSubNet("5wyqrzbvrdsumnok.onion"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com"s, ret));
BOOST_CHECK(!LookupSubNet("5wyqrzbvrdsumnok.onion\0example.com\0"s, ret));
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 1d7f4861fb..d5a4d3fd80 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index 8c2712f764..c489ac04e9 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 9a490aaf6b..740b2c72db 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 2e5a7549b7..21162356b8 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -9,6 +9,7 @@
#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
+#include <functional>
#include <mutex>
BOOST_AUTO_TEST_SUITE(scheduler_tests)
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index 1d6bcadf69..366385b619 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -183,23 +183,23 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
s.clear();
s << ToByteVector(pubkey) << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<PKHash>(&address) &&
- *boost::get<PKHash>(&address) == PKHash(pubkey));
+ BOOST_CHECK(std::get_if<PKHash>(&address) &&
+ *std::get_if<PKHash>(&address) == PKHash(pubkey));
// TxoutType::PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<PKHash>(&address) &&
- *boost::get<PKHash>(&address) == PKHash(pubkey));
+ BOOST_CHECK(std::get_if<PKHash>(&address) &&
+ *std::get_if<PKHash>(&address) == PKHash(pubkey));
// TxoutType::SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<ScriptHash>(&address) &&
- *boost::get<ScriptHash>(&address) == ScriptHash(redeemScript));
+ BOOST_CHECK(std::get_if<ScriptHash>(&address) &&
+ *std::get_if<ScriptHash>(&address) == ScriptHash(redeemScript));
// TxoutType::MULTISIG
s.clear();
@@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
BOOST_CHECK(ExtractDestination(s, address));
WitnessV0KeyHash keyhash;
CHash160().Write(pubkey).Finalize(keyhash);
- BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
+ BOOST_CHECK(std::get_if<WitnessV0KeyHash>(&address) && *std::get_if<WitnessV0KeyHash>(&address) == keyhash);
// TxoutType::WITNESS_V0_SCRIPTHASH
s.clear();
@@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
s << OP_0 << ToByteVector(scripthash);
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
+ BOOST_CHECK(std::get_if<WitnessV0ScriptHash>(&address) && *std::get_if<WitnessV0ScriptHash>(&address) == scripthash);
// TxoutType::WITNESS_UNKNOWN with unknown version
s.clear();
@@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
unk.length = 33;
unk.version = 1;
std::copy(pubkey.begin(), pubkey.end(), unk.program);
- BOOST_CHECK(boost::get<WitnessUnknown>(&address) && *boost::get<WitnessUnknown>(&address) == unk);
+ BOOST_CHECK(std::get_if<WitnessUnknown>(&address) && *std::get_if<WitnessUnknown>(&address) == unk);
}
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
@@ -259,8 +259,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEY);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
- *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) &&
+ *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
// TxoutType::PUBKEYHASH
s.clear();
@@ -269,8 +269,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEYHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
- *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) &&
+ *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
// TxoutType::SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
@@ -280,8 +280,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::SCRIPTHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) &&
- *boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
+ BOOST_CHECK(std::get_if<ScriptHash>(&addresses[0]) &&
+ *std::get_if<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
// TxoutType::MULTISIG
s.clear();
@@ -293,10 +293,10 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TxoutType::MULTISIG);
BOOST_CHECK_EQUAL(addresses.size(), 2U);
BOOST_CHECK_EQUAL(nRequired, 2);
- BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
- *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
- BOOST_CHECK(boost::get<PKHash>(&addresses[1]) &&
- *boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[0]) &&
+ *std::get_if<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
+ BOOST_CHECK(std::get_if<PKHash>(&addresses[1]) &&
+ *std::get_if<PKHash>(&addresses[1]) == PKHash(pubkeys[1]));
// TxoutType::NULL_DATA
s.clear();
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index c509a252e0..8f5ee1e8e2 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index 71275f69d9..3e4d1dac9e 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -6,7 +6,6 @@
#include <test/util/setup_common.h>
#include <boost/test/unit_test.hpp>
-#include <boost/thread/mutex.hpp>
#include <mutex>
@@ -110,11 +109,6 @@ BOOST_AUTO_TEST_CASE(double_lock_mutex)
TestDoubleLock<Mutex>(true /* should throw */);
}
-BOOST_AUTO_TEST_CASE(double_lock_boost_mutex)
-{
- TestDoubleLock<boost::mutex>(true /* should throw */);
-}
-
BOOST_AUTO_TEST_CASE(double_lock_recursive_mutex)
{
TestDoubleLock<RecursiveMutex>(false /* should not throw */);
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index a55145c738..ce555f7299 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 1f520074b1..1eb30c68d6 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -24,6 +24,7 @@
#include <util/strencodings.h>
#include <validation.h>
+#include <functional>
#include <map>
#include <string>
@@ -428,12 +429,10 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
// check all inputs concurrently, with the cache
PrecomputedTransactionData txdata(tx);
- boost::thread_group threadGroup;
CCheckQueue<CScriptCheck> scriptcheckqueue(128);
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
- for (int i=0; i<20; i++)
- threadGroup.create_thread(std::bind(&CCheckQueue<CScriptCheck>::Thread, std::ref(scriptcheckqueue)));
+ scriptcheckqueue.StartWorkerThreads(20);
std::vector<Coin> coins;
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
@@ -455,9 +454,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction)
bool controlCheck = control.Wait();
assert(controlCheck);
-
- threadGroup.interrupt_all();
- threadGroup.join_all();
+ scriptcheckqueue.StopWorkerThreads();
}
SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutableTransaction& input2, const CTransactionRef tx)
@@ -762,7 +759,9 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
// Only one TxoutType::NULL_DATA permitted in all cases
t.vout.resize(2);
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ t.vout[0].nValue = 0;
t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
+ t.vout[1].nValue = 0;
reason.clear();
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
BOOST_CHECK_EQUAL(reason, "multi-op-return");
diff --git a/src/test/util/logging.cpp b/src/test/util/logging.cpp
index 65a64f2384..c1dd47f06c 100644
--- a/src/test/util/logging.cpp
+++ b/src/test/util/logging.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/util/logging.h b/src/test/util/logging.h
index a49f9a7292..ebe0ecf623 100644
--- a/src/test/util/logging.h
+++ b/src/test/util/logging.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp
index 74536ae74c..0c6487fbfa 100644
--- a/src/test/util/mining.cpp
+++ b/src/test/util/mining.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 1208e92762..e25036be26 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -30,4 +30,35 @@ struct ConnmanTestMsg : public CConnman {
bool ReceiveMsgFrom(CNode& node, CSerializedNetMsg& ser_msg) const;
};
+constexpr ServiceFlags ALL_SERVICE_FLAGS[]{
+ NODE_NONE,
+ NODE_NETWORK,
+ NODE_BLOOM,
+ NODE_WITNESS,
+ NODE_COMPACT_FILTERS,
+ NODE_NETWORK_LIMITED,
+};
+
+constexpr NetPermissionFlags ALL_NET_PERMISSION_FLAGS[]{
+ NetPermissionFlags::PF_NONE,
+ NetPermissionFlags::PF_BLOOMFILTER,
+ NetPermissionFlags::PF_RELAY,
+ NetPermissionFlags::PF_FORCERELAY,
+ NetPermissionFlags::PF_NOBAN,
+ NetPermissionFlags::PF_MEMPOOL,
+ NetPermissionFlags::PF_ADDR,
+ NetPermissionFlags::PF_DOWNLOAD,
+ NetPermissionFlags::PF_ISIMPLICIT,
+ NetPermissionFlags::PF_ALL,
+};
+
+constexpr ConnectionType ALL_CONNECTION_TYPES[]{
+ ConnectionType::INBOUND,
+ ConnectionType::OUTBOUND_FULL_RELAY,
+ ConnectionType::MANUAL,
+ ConnectionType::FEELER,
+ ConnectionType::BLOCK_RELAY,
+ ConnectionType::ADDR_FETCH,
+};
+
#endif // BITCOIN_TEST_UTIL_NET_H
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index db8b43d039..8a9694f55b 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -143,9 +143,7 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
// Start script-checking threads. Set g_parallel_script_checks to true so they are used.
constexpr int script_check_threads = 2;
- for (int i = 0; i < script_check_threads; ++i) {
- threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
- }
+ StartScriptCheckWorkerThreads(script_check_threads);
g_parallel_script_checks = true;
}
@@ -154,6 +152,7 @@ ChainTestingSetup::~ChainTestingSetup()
if (m_node.scheduler) m_node.scheduler->stop();
threadGroup.interrupt_all();
threadGroup.join_all();
+ StopScriptCheckWorkerThreads();
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler();
m_node.connman.reset();
@@ -192,9 +191,9 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
m_node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
- m_node.peerman = std::make_unique<PeerManager>(chainparams, *m_node.connman, m_node.banman.get(),
- *m_node.scheduler, *m_node.chainman, *m_node.mempool,
- false);
+ m_node.peerman = PeerManager::make(chainparams, *m_node.connman, m_node.banman.get(),
+ *m_node.scheduler, *m_node.chainman, *m_node.mempool,
+ false);
{
CConnman::Options options;
options.m_msgproc = m_node.peerman.get();
@@ -239,12 +238,12 @@ TestChain100Setup::~TestChain100Setup()
gArgs.ForceSetArg("-segwitheight", "0");
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx)
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const
{
return FromTx(MakeTransactionRef(tx));
}
-CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx)
+CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransactionRef& tx) const
{
return CTxMemPoolEntry(tx, nFee, nTime, nHeight,
spendsCoinbase, sigOpCost, lp);
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index 0498e7d182..dff8cf825e 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -145,8 +145,8 @@ struct TestMemPoolEntryHelper
nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { }
- CTxMemPoolEntry FromTx(const CMutableTransaction& tx);
- CTxMemPoolEntry FromTx(const CTransactionRef& tx);
+ CTxMemPoolEntry FromTx(const CMutableTransaction& tx) const;
+ CTxMemPoolEntry FromTx(const CTransactionRef& tx) const;
// Change the default value
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index a9ef0f73cc..4133f2623b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -2014,12 +2014,6 @@ struct Tracker
copies = t.copies + 1;
return *this;
}
- Tracker& operator=(Tracker&& t) noexcept
- {
- origin = t.origin;
- copies = t.copies;
- return *this;
- }
};
}
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index c8a375275f..92d8cf2e7d 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
return outp;
};
- CChainState& c1 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool));
+ CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(mempool));
c1.InitCoinsDB(
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 75939e0140..3d8570e27c 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
// Create a legacy (IBD) chainstate.
//
- CChainState& c1 = *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool));
+ CChainState& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(mempool));
chainstates.push_back(&c1);
c1.InitCoinsDB(
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
@@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
// Create a snapshot-based chainstate.
//
- CChainState& c2 = *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool, GetRandHash()));
+ CChainState& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(mempool, GetRandHash()));
chainstates.push_back(&c2);
c2.InitCoinsDB(
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
@@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
// Create a legacy (IBD) chainstate.
//
- CChainState& c1 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool));
+ CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(mempool));
chainstates.push_back(&c1);
c1.InitCoinsDB(
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
@@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
// Create a snapshot-based chainstate.
//
- CChainState& c2 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool, GetRandHash()));
+ CChainState& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(mempool, GetRandHash()));
chainstates.push_back(&c2);
c2.InitCoinsDB(
/* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp
index c3816af0cd..9e37f14921 100644
--- a/src/test/validation_tests.cpp
+++ b/src/test/validation_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(signet_parse_tests)
CMutableTransaction cb;
cb.vout.emplace_back(0, CScript{});
block.vtx.push_back(MakeTransactionRef(cb));
- block.vtx.push_back(MakeTransactionRef(cb)); // Add dummy tx to excercise merkle root code
+ block.vtx.push_back(MakeTransactionRef(cb)); // Add dummy tx to exercise merkle root code
BOOST_CHECK(!SignetTxs::Create(block, challenge));
BOOST_CHECK(!CheckSignetBlockSolution(block, signet_params->GetConsensus()));
diff --git a/src/threadsafety.h b/src/threadsafety.h
index 52bf83b676..28b6177927 100644
--- a/src/threadsafety.h
+++ b/src/threadsafety.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 9d91f42b1b..908ad35e1b 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Copyright (c) 2017 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,10 +15,11 @@
#include <util/strencodings.h>
#include <util/system.h>
-#include <vector>
#include <deque>
+#include <functional>
#include <set>
#include <stdlib.h>
+#include <vector>
#include <boost/signals2/signal.hpp>
#include <boost/algorithm/string/split.hpp>
diff --git a/src/torcontrol.h b/src/torcontrol.h
index 71a6960e54..00f19db6ae 100644
--- a/src/torcontrol.h
+++ b/src/torcontrol.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index d18182c07d..470e665844 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -618,6 +618,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (GetRand(m_check_ratio) >= 1) return;
+ AssertLockHeld(::cs_main);
LOCK(cs);
LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
@@ -1127,5 +1128,3 @@ CTxMemPool::EpochGuard::~EpochGuard()
++pool.m_epoch;
pool.m_has_epoch_guard = false;
}
-
-SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
diff --git a/src/txmempool.h b/src/txmempool.h
index 15797cbc00..0a9cd81ff5 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -15,13 +15,13 @@
#include <amount.h>
#include <coins.h>
-#include <crypto/siphash.h>
#include <indirectmap.h>
#include <optional.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <sync.h>
#include <random.h>
+#include <util/hasher.h>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
@@ -398,20 +398,6 @@ enum class MemPoolRemovalReason {
REPLACED, //!< Removed for replacement
};
-class SaltedTxidHasher
-{
-private:
- /** Salt */
- const uint64_t k0, k1;
-
-public:
- SaltedTxidHasher();
-
- size_t operator()(const uint256& txid) const {
- return SipHashUint256(k0, k1, txid);
- }
-};
-
/**
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
* that may be included in the next block.
@@ -616,7 +602,7 @@ public:
* all inputs are in the mapNextTx array). If sanity-checking is turned off,
* check does nothing.
*/
- void check(const CCoinsViewCache *pcoins) const;
+ void check(const CCoinsViewCache *pcoins) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
// addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of
diff --git a/src/uint256.cpp b/src/uint256.cpp
index f358b62903..cd9cbb566a 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/uint256.h b/src/uint256.h
index ceae70707e..fadf2320af 100644
--- a/src/uint256.h
+++ b/src/uint256.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/asmap.h b/src/util/asmap.h
index b31e639bb5..d0588bc8c3 100644
--- a/src/util/asmap.h
+++ b/src/util/asmap.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/check.h b/src/util/check.h
index e7620d97a0..bc62da3440 100644
--- a/src/util/check.h
+++ b/src/util/check.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/error.cpp b/src/util/error.cpp
index 6c94b80683..76fac4d391 100644
--- a/src/util/error.cpp
+++ b/src/util/error.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2010-2019 The Bitcoin Core developers
+// Copyright (c) 2010-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/error.h b/src/util/error.h
index b9830c9eea..6633498d2b 100644
--- a/src/util/error.h
+++ b/src/util/error.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010-2019 The Bitcoin Core developers
+// Copyright (c) 2010-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/fees.cpp b/src/util/fees.cpp
index 1855c0bc90..cbefe18dbb 100644
--- a/src/util/fees.cpp
+++ b/src/util/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/fees.h b/src/util/fees.h
index 3f1c33ad9c..9ef2389d3e 100644
--- a/src/util/fees.h
+++ b/src/util/fees.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_FEES_H
diff --git a/src/util/golombrice.h b/src/util/golombrice.h
index 425e7f6681..67d262406f 100644
--- a/src/util/golombrice.h
+++ b/src/util/golombrice.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/hasher.cpp b/src/util/hasher.cpp
new file mode 100644
index 0000000000..5900daf050
--- /dev/null
+++ b/src/util/hasher.cpp
@@ -0,0 +1,19 @@
+// Copyright (c) 2019 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 <random.h>
+#include <util/hasher.h>
+
+#include <limits>
+
+SaltedTxidHasher::SaltedTxidHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
+
+SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
+
+SaltedSipHasher::SaltedSipHasher() : m_k0(GetRand(std::numeric_limits<uint64_t>::max())), m_k1(GetRand(std::numeric_limits<uint64_t>::max())) {}
+
+size_t SaltedSipHasher::operator()(const Span<const unsigned char>& script) const
+{
+ return CSipHasher(m_k0, m_k1).Write(script.data(), script.size()).Finalize();
+}
diff --git a/src/util/hasher.h b/src/util/hasher.h
new file mode 100644
index 0000000000..fa2fea30d8
--- /dev/null
+++ b/src/util/hasher.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_HASHER_H
+#define BITCOIN_UTIL_HASHER_H
+
+#include <crypto/siphash.h>
+#include <primitives/transaction.h>
+#include <uint256.h>
+
+class SaltedTxidHasher
+{
+private:
+ /** Salt */
+ const uint64_t k0, k1;
+
+public:
+ SaltedTxidHasher();
+
+ size_t operator()(const uint256& txid) const {
+ return SipHashUint256(k0, k1, txid);
+ }
+};
+
+class SaltedOutpointHasher
+{
+private:
+ /** Salt */
+ const uint64_t k0, k1;
+
+public:
+ SaltedOutpointHasher();
+
+ /**
+ * This *must* return size_t. With Boost 1.46 on 32-bit systems the
+ * unordered_map will behave unpredictably if the custom hasher returns a
+ * uint64_t, resulting in failures when syncing the chain (#4634).
+ *
+ * Having the hash noexcept allows libstdc++'s unordered_map to recalculate
+ * the hash during rehash, so it does not have to cache the value. This
+ * reduces node's memory by sizeof(size_t). The required recalculation has
+ * a slight performance penalty (around 1.6%), but this is compensated by
+ * memory savings of about 9% which allow for a larger dbcache setting.
+ *
+ * @see https://gcc.gnu.org/onlinedocs/gcc-9.2.0/libstdc++/manual/manual/unordered_associative.html
+ */
+ size_t operator()(const COutPoint& id) const noexcept {
+ return SipHashUint256Extra(k0, k1, id.hash, id.n);
+ }
+};
+
+struct FilterHeaderHasher
+{
+ size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
+};
+
+/**
+ * We're hashing a nonce into the entries themselves, so we don't need extra
+ * blinding in the set hash computation.
+ *
+ * This may exhibit platform endian dependent behavior but because these are
+ * nonced hashes (random) and this state is only ever used locally it is safe.
+ * All that matters is local consistency.
+ */
+class SignatureCacheHasher
+{
+public:
+ template <uint8_t hash_select>
+ uint32_t operator()(const uint256& key) const
+ {
+ static_assert(hash_select <8, "SignatureCacheHasher only has 8 hashes available.");
+ uint32_t u;
+ std::memcpy(&u, key.begin()+4*hash_select, 4);
+ return u;
+ }
+};
+
+struct BlockHasher
+{
+ // this used to call `GetCheapHash()` in uint256, which was later moved; the
+ // cheap hash function simply calls ReadLE64() however, so the end result is
+ // identical
+ size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
+};
+
+class SaltedSipHasher
+{
+private:
+ /** Salt */
+ const uint64_t m_k0, m_k1;
+
+public:
+ SaltedSipHasher();
+
+ size_t operator()(const Span<const unsigned char>& script) const;
+};
+
+#endif // BITCOIN_UTIL_HASHER_H
diff --git a/src/util/memory.h b/src/util/memory.h
index 4d73b32869..f21b81bade 100644
--- a/src/util/memory.h
+++ b/src/util/memory.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/util/message.cpp b/src/util/message.cpp
index e1d5cff48c..73948e4ff1 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -31,7 +31,7 @@ MessageVerificationResult MessageVerify(
return MessageVerificationResult::ERR_INVALID_ADDRESS;
}
- if (boost::get<PKHash>(&destination) == nullptr) {
+ if (std::get_if<PKHash>(&destination) == nullptr) {
return MessageVerificationResult::ERR_ADDRESS_NO_KEY;
}
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index 8ee43c620b..b4a61202ef 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -166,7 +166,7 @@ bool TimingResistantEqual(const T& a, const T& b)
}
/** Parse number as fixed point according to JSON number syntax.
- * See http://json.org/number.gif
+ * See https://json.org/number.gif
* @returns true on success, false on error.
* @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
*/
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 5f30136fa2..d1fb921642 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -398,7 +398,7 @@ bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
}
if (filepath) {
std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
- *filepath = fs::absolute(temp ? settings + ".tmp" : settings, GetDataDir(/* net_specific= */ true));
+ *filepath = fsbridge::AbsPathJoin(GetDataDir(/* net_specific= */ true), temp ? settings + ".tmp" : settings);
}
return true;
}
@@ -1047,27 +1047,36 @@ bool FileCommit(FILE *file)
LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
return false;
}
-#else
- #if HAVE_FDATASYNC
- if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
- LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
- return false;
- }
- #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
+#elif defined(MAC_OSX) && defined(F_FULLFSYNC)
if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
return false;
}
- #else
+#elif HAVE_FDATASYNC
+ if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
+ LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
+ return false;
+ }
+#else
if (fsync(fileno(file)) != 0 && errno != EINVAL) {
LogPrintf("%s: fsync failed: %d\n", __func__, errno);
return false;
}
- #endif
#endif
return true;
}
+void DirectoryCommit(const fs::path &dirname)
+{
+#ifndef WIN32
+ FILE* file = fsbridge::fopen(dirname, "r");
+ if (file) {
+ fsync(fileno(file));
+ fclose(file);
+ }
+#endif
+}
+
bool TruncateFile(FILE *file, unsigned int length) {
#if defined(WIN32)
return _chsize(_fileno(file), length) == 0;
@@ -1302,7 +1311,7 @@ fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
if (path.is_absolute()) {
return path;
}
- return fs::absolute(path, GetDataDir(net_specific));
+ return fsbridge::AbsPathJoin(GetDataDir(net_specific), path);
}
void ScheduleBatchPriority()
diff --git a/src/util/system.h b/src/util/system.h
index 2be8bb754b..010fc5b49f 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -56,7 +56,19 @@ bool error(const char* fmt, const Args&... args)
}
void PrintExceptionContinue(const std::exception *pex, const char* pszThread);
+
+/**
+ * Ensure file contents are fully committed to disk, using a platform-specific
+ * feature analogous to fsync().
+ */
bool FileCommit(FILE *file);
+
+/**
+ * Sync directory contents. This is required on some environments to ensure that
+ * newly created files are committed to disk.
+ */
+void DirectoryCommit(const fs::path &dirname);
+
bool TruncateFile(FILE *file, unsigned int length);
int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
diff --git a/src/util/trace.h b/src/util/trace.h
new file mode 100644
index 0000000000..9c92cb10e7
--- /dev/null
+++ b/src/util/trace.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2020 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTIL_TRACE_H
+#define BITCOIN_UTIL_TRACE_H
+
+#ifdef ENABLE_TRACING
+
+#include <sys/sdt.h>
+
+#define TRACE(context, event) DTRACE_PROBE(context, event)
+#define TRACE1(context, event, a) DTRACE_PROBE1(context, event, a)
+#define TRACE2(context, event, a, b) DTRACE_PROBE2(context, event, a, b)
+#define TRACE3(context, event, a, b, c) DTRACE_PROBE3(context, event, a, b, c)
+#define TRACE4(context, event, a, b, c, d) DTRACE_PROBE4(context, event, a, b, c, d)
+#define TRACE5(context, event, a, b, c, d, e) DTRACE_PROBE5(context, event, a, b, c, d, e)
+#define TRACE6(context, event, a, b, c, d, e, f) DTRACE_PROBE6(context, event, a, b, c, d, e, f)
+#define TRACE7(context, event, a, b, c, d, e, f, g) DTRACE_PROBE7(context, event, a, b, c, d, e, f, g)
+#define TRACE8(context, event, a, b, c, d, e, f, g, h) DTRACE_PROBE8(context, event, a, b, c, d, e, f, g, h)
+#define TRACE9(context, event, a, b, c, d, e, f, g, h, i) DTRACE_PROBE9(context, event, a, b, c, d, e, f, g, h, i)
+#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j) DTRACE_PROBE10(context, event, a, b, c, d, e, f, g, h, i, j)
+#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k) DTRACE_PROBE11(context, event, a, b, c, d, e, f, g, h, i, j, k)
+#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l) DTRACE_PROBE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l)
+
+#else
+
+#define TRACE(context, event)
+#define TRACE1(context, event, a)
+#define TRACE2(context, event, a, b)
+#define TRACE3(context, event, a, b, c)
+#define TRACE4(context, event, a, b, c, d)
+#define TRACE5(context, event, a, b, c, d, e)
+#define TRACE6(context, event, a, b, c, d, e, f)
+#define TRACE7(context, event, a, b, c, d, e, f, g)
+#define TRACE8(context, event, a, b, c, d, e, f, g, h)
+#define TRACE9(context, event, a, b, c, d, e, f, g, h, i)
+#define TRACE10(context, event, a, b, c, d, e, f, g, h, i, j)
+#define TRACE11(context, event, a, b, c, d, e, f, g, h, i, j, k)
+#define TRACE12(context, event, a, b, c, d, e, f, g, h, i, j, k, l)
+
+#endif
+
+
+#endif /* BITCOIN_UTIL_TRACE_H */
diff --git a/src/util/translation.h b/src/util/translation.h
index 695d6dac96..99899ef3c2 100644
--- a/src/util/translation.h
+++ b/src/util/translation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Bitcoin Core developers
+// Copyright (c) 2019-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/validation.cpp b/src/validation.cpp
index 2585345dee..eeb99f0f0a 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -404,36 +404,41 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
}
-// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
-// were somehow broken and returning the wrong scriptPubKeys
-static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
- unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
+/**
+* Checks to avoid mempool polluting consensus critical paths since cached
+* signature and script validity results will be reused if we validate this
+* transaction again during block validation.
+* */
+static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state,
+ const CCoinsViewCache& view, const CTxMemPool& pool,
+ unsigned int flags, PrecomputedTransactionData& txdata)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
+{
AssertLockHeld(cs_main);
-
- // pool.cs should be locked already, but go ahead and re-take the lock here
- // to enforce that mempool doesn't change between when we check the view
- // and when we actually call through to CheckInputScripts
- LOCK(pool.cs);
+ AssertLockHeld(pool.cs);
assert(!tx.IsCoinBase());
for (const CTxIn& txin : tx.vin) {
const Coin& coin = view.AccessCoin(txin.prevout);
- // AcceptToMemoryPoolWorker has already checked that the coins are
- // available, so this shouldn't fail. If the inputs are not available
- // here then return false.
+ // This coin was checked in PreChecks and MemPoolAccept
+ // has been holding cs_main since then.
+ Assume(!coin.IsSpent());
if (coin.IsSpent()) return false;
- // Check equivalence for available inputs.
+ // If the Coin is available, there are 2 possibilities:
+ // it is available in our current ChainstateActive UTXO set,
+ // or it's a UTXO provided by a transaction in our mempool.
+ // Ensure the scriptPubKeys in Coins from CoinsView are correct.
const CTransactionRef& txFrom = pool.get(txin.prevout.hash);
if (txFrom) {
assert(txFrom->GetHash() == txin.prevout.hash);
assert(txFrom->vout.size() > txin.prevout.n);
assert(txFrom->vout[txin.prevout.n] == coin.out);
} else {
- const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout);
- assert(!coinFromDisk.IsSpent());
- assert(coinFromDisk.out == coin.out);
+ const Coin& coinFromUTXOSet = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout);
+ assert(!coinFromUTXOSet.IsSpent());
+ assert(coinFromUTXOSet.out == coin.out);
}
}
@@ -502,13 +507,13 @@ private:
// Run the script checks using our policy flags. As this can be slow, we should
// only invoke this on transactions that have otherwise passed policy checks.
- bool PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool PolicyScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Re-run the script checks, using consensus flags, and try to cache the
// result in the scriptcache. This should be done after
// PolicyScriptChecks(). This requires that all inputs either be in our
// utxo set or in the mempool.
- bool ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool ConsensusScriptChecks(ATMPArgs& args, const Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Try to add the transaction to the mempool, removing any conflicts first.
// Returns true if the transaction is in the mempool after any size
@@ -516,7 +521,7 @@ private:
bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
// Compare a package's feerate against minimum allowed.
- bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state)
+ bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs)
{
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
@@ -637,7 +642,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
LockPoints lp;
m_view.SetBackend(m_viewmempool);
- CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
+ const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
// do all inputs exist?
for (const CTxIn& txin : tx.vin) {
if (!coins_cache.HaveCoinInCache(txin.prevout)) {
@@ -1758,9 +1763,14 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationSt
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
-void ThreadScriptCheck(int worker_num) {
- util::ThreadRename(strprintf("scriptch.%i", worker_num));
- scriptcheckqueue.Thread();
+void StartScriptCheckWorkerThreads(int threads_num)
+{
+ scriptcheckqueue.StartWorkerThreads(threads_num);
+}
+
+void StopScriptCheckWorkerThreads()
+{
+ scriptcheckqueue.StopWorkerThreads();
}
VersionBitsCache versionbitscache GUARDED_BY(cs_main);
@@ -5035,15 +5045,9 @@ bool LoadMempool(CTxMemPool& pool)
pool.PrioritiseTransaction(i.first, i.second);
}
- // TODO: remove this try except in v0.22
std::set<uint256> unbroadcast_txids;
- try {
- file >> unbroadcast_txids;
- unbroadcast = unbroadcast_txids.size();
- } catch (const std::exception&) {
- // mempool.dat files created prior to v0.21 will not have an
- // unbroadcast set. No need to log a failure if parsing fails here.
- }
+ file >> unbroadcast_txids;
+ unbroadcast = unbroadcast_txids.size();
for (const auto& txid : unbroadcast_txids) {
// Ensure transactions were accepted to mempool then add to
// unbroadcast set.
diff --git a/src/validation.h b/src/validation.h
index d10b260d8a..d3fbabe1a2 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -23,6 +23,7 @@
#include <txdb.h>
#include <versionbits.h>
#include <serialize.h>
+#include <util/hasher.h>
#include <atomic>
#include <map>
@@ -93,14 +94,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Setting the target to >= 550 MiB will make it likely we can respect the target.
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
-struct BlockHasher
-{
- // this used to call `GetCheapHash()` in uint256, which was later moved; the
- // cheap hash function simply calls ReadLE64() however, so the end result is
- // identical
- size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
-};
-
/** Current sync state passed to tip changed callbacks. */
enum class SynchronizationState {
INIT_REINDEX,
@@ -156,8 +149,10 @@ void LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
bool LoadGenesisBlock(const CChainParams& chainparams);
/** Unload database information */
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman);
-/** Run an instance of the script checking thread */
-void ThreadScriptCheck(int worker_num);
+/** Run instances of script checking worker threads */
+void StartScriptCheckWorkerThreads(int threads_num);
+/** Stop all of the script checking worker threads */
+void StopScriptCheckWorkerThreads();
/**
* Return transaction from the block at block_index.
* If block_index is not provided, fall back to mempool.
diff --git a/src/version.h b/src/version.h
index 019c3a3ae7..ee646eefc3 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/versionbitsinfo.cpp b/src/versionbitsinfo.cpp
index 20dfc044ca..fa41bad46d 100644
--- a/src/versionbitsinfo.cpp
+++ b/src/versionbitsinfo.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index 6ed48593fb..c0d107bf39 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -723,6 +723,23 @@ bool BerkeleyBatch::TxnAbort()
return (ret == 0);
}
+bool BerkeleyDatabaseSanityCheck()
+{
+ int major, minor;
+ DbEnv::version(&major, &minor, nullptr);
+
+ /* If the major version differs, or the minor version of library is *older*
+ * than the header that was compiled against, flag an error.
+ */
+ if (major != DB_VERSION_MAJOR || minor < DB_VERSION_MINOR) {
+ LogPrintf("BerkeleyDB database version conflict: header version is %d.%d, library version is %d.%d\n",
+ DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor);
+ return false;
+ }
+
+ return true;
+}
+
std::string BerkeleyDatabaseVersion()
{
return DbEnv::version(nullptr, nullptr, nullptr);
diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h
index bf1617d67f..a8209587d7 100644
--- a/src/wallet/bdb.h
+++ b/src/wallet/bdb.h
@@ -223,6 +223,10 @@ public:
std::string BerkeleyDatabaseVersion();
+/** Perform sanity check of runtime BDB version versus linked BDB version.
+ */
+bool BerkeleyDatabaseSanityCheck();
+
//! Return object giving access to Berkeley database at specified path.
std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 1a45a2b313..a2dea84d17 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 49c1134ec6..cf9768b927 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2018 The Bitcoin Core developers
+// Copyright (c) 2017-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h
index f2df786e2e..f7325541a9 100644
--- a/src/wallet/crypter.h
+++ b/src/wallet/crypter.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 1bbfa197d7..5e319d4f95 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -231,7 +231,7 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
// Write back transaction
mtx = CMutableTransaction(*tx_new);
// Mark new tx not replaceable, if requested.
- if (!coin_control.m_signal_bip125_rbf.get_value_or(wallet.m_signal_rbf)) {
+ if (!coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf)) {
for (auto& input : mtx.vin) {
if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
}
@@ -256,7 +256,7 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti
errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
return Result::MISC_ERROR;
}
- CWalletTx& oldWtx = it->second;
+ const CWalletTx& oldWtx = it->second;
// make sure the transaction still has no descendants and hasn't been mined in the meantime
Result result = PreconditionChecks(wallet, oldWtx, errors);
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 249bc833c6..429101e774 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -49,7 +49,7 @@ CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_contr
// We will use smart fee estimation
unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : wallet.m_confirm_target;
// By default estimates are economical iff we are signaling opt-in-RBF
- bool conservative_estimate = !coin_control.m_signal_bip125_rbf.get_value_or(wallet.m_signal_rbf);
+ bool conservative_estimate = !coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf);
// Allow to override the default fee estimate mode over the CoinControl instance
if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 085dde1026..0d2be64dfb 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -86,6 +86,11 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
bool WalletInit::ParameterInteraction() const
{
+#ifdef USE_BDB
+ if (!BerkeleyDatabaseSanityCheck()) {
+ return InitError(Untranslated("A version conflict was detected between the run-time BerkeleyDB library and the one used during compilation."));
+ }
+#endif
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);
diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h
index 5cdd7dff80..38ed7e7770 100644
--- a/src/wallet/ismine.h
+++ b/src/wallet/ismine.h
@@ -14,7 +14,27 @@
class CWallet;
class CScript;
-/** IsMine() return codes */
+/**
+ * IsMine() return codes, which depend on ScriptPubKeyMan implementation.
+ * Not every ScriptPubKeyMan covers all types, please refer to
+ * https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.21.0.md#ismine-semantics
+ * for better understanding.
+ *
+ * For LegacyScriptPubKeyMan,
+ * ISMINE_NO: the scriptPubKey is not in the wallet;
+ * ISMINE_WATCH_ONLY: the scriptPubKey has been imported into the wallet;
+ * ISMINE_SPENDABLE: the scriptPubKey corresponds to an address owned by the wallet user (can spend with the private key);
+ * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user;
+ * ISMINE_ALL: all ISMINE flags except for USED;
+ * ISMINE_ALL_USED: all ISMINE flags including USED;
+ * ISMINE_ENUM_ELEMENTS: the number of isminetype enum elements.
+ *
+ * For DescriptorScriptPubKeyMan and future ScriptPubKeyMan,
+ * ISMINE_NO: the scriptPubKey is not in the wallet;
+ * ISMINE_SPENDABLE: the scriptPubKey matches a scriptPubKey in the wallet.
+ * ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user.
+ *
+ */
enum isminetype : unsigned int
{
ISMINE_NO = 0,
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
index 036fd4956f..30832f983b 100644
--- a/src/wallet/load.cpp
+++ b/src/wallet/load.cpp
@@ -62,7 +62,7 @@ bool VerifyWallets(interfaces::Chain& chain)
std::set<fs::path> wallet_paths;
for (const auto& wallet_file : gArgs.GetArgs("-wallet")) {
- const fs::path path = fs::absolute(wallet_file, GetWalletDir());
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), wallet_file);
if (!wallet_paths.insert(path).second) {
chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
diff --git a/src/wallet/load.h b/src/wallet/load.h
index e12343de27..7910f0d6e1 100644
--- a/src/wallet/load.h
+++ b/src/wallet/load.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 6b46868d10..8505ddc309 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1740,3 +1740,72 @@ RPCHelpMan importdescriptors()
},
};
}
+
+RPCHelpMan listdescriptors()
+{
+ return RPCHelpMan{
+ "listdescriptors",
+ "\nList descriptors imported into a descriptor-enabled wallet.",
+ {},
+ RPCResult{
+ RPCResult::Type::ARR, "", "Response is an array of descriptor objects",
+ {
+ {RPCResult::Type::OBJ, "", "", {
+ {RPCResult::Type::STR, "desc", "Descriptor string representation"},
+ {RPCResult::Type::NUM, "timestamp", "The creation time of the descriptor"},
+ {RPCResult::Type::BOOL, "active", "Activeness flag"},
+ {RPCResult::Type::BOOL, "internal", true, "Whether this is internal or external descriptor; defined only for active descriptors"},
+ {RPCResult::Type::ARR_FIXED, "range", true, "Defined only for ranged descriptors", {
+ {RPCResult::Type::NUM, "", "Range start inclusive"},
+ {RPCResult::Type::NUM, "", "Range end inclusive"},
+ }},
+ {RPCResult::Type::NUM, "next", true, "The next index to generate addresses from; defined only for ranged descriptors"},
+ }},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("listdescriptors", "") + HelpExampleRpc("listdescriptors", "")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ if (!wallet) return NullUniValue;
+
+ if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets");
+ }
+
+ LOCK(wallet->cs_wallet);
+
+ UniValue response(UniValue::VARR);
+ const auto active_spk_mans = wallet->GetActiveScriptPubKeyMans();
+ for (const auto& spk_man : wallet->GetAllScriptPubKeyMans()) {
+ const auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man);
+ if (!desc_spk_man) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Unexpected ScriptPubKey manager type.");
+ }
+ UniValue spk(UniValue::VOBJ);
+ LOCK(desc_spk_man->cs_desc_man);
+ const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
+ spk.pushKV("desc", wallet_descriptor.descriptor->ToString());
+ spk.pushKV("timestamp", wallet_descriptor.creation_time);
+ const bool active = active_spk_mans.count(desc_spk_man) != 0;
+ spk.pushKV("active", active);
+ const auto& type = wallet_descriptor.descriptor->GetOutputType();
+ if (active && type != nullopt) {
+ spk.pushKV("internal", wallet->GetScriptPubKeyMan(*type, true) == desc_spk_man);
+ }
+ if (wallet_descriptor.descriptor->IsRange()) {
+ UniValue range(UniValue::VARR);
+ range.push_back(wallet_descriptor.range_start);
+ range.push_back(wallet_descriptor.range_end - 1);
+ spk.pushKV("range", range);
+ spk.pushKV("next", wallet_descriptor.next_index);
+ }
+ response.push_back(spk);
+ }
+
+ return response;
+},
+ };
+}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 94a73b67df..46de273d63 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -309,7 +309,7 @@ static RPCHelpMan getrawchangeaddress()
throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
}
- OutputType output_type = pwallet->m_default_change_type.get_value_or(pwallet->m_default_address_type);
+ OutputType output_type = pwallet->m_default_change_type.value_or(pwallet->m_default_address_type);
if (!request.params[0].isNull()) {
if (!ParseOutputType(request.params[0].get_str(), output_type)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
@@ -627,7 +627,7 @@ static RPCHelpMan signmessage()
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
- const PKHash *pkhash = boost::get<PKHash>(&dest);
+ const PKHash* pkhash = std::get_if<PKHash>(&dest);
if (!pkhash) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
@@ -1573,8 +1573,7 @@ static RPCHelpMan listsinceblock()
LOCK(wallet.cs_wallet);
- // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
- Optional<int> height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
+ Optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
Optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
@@ -2616,7 +2615,18 @@ static RPCHelpMan loadwallet()
if (!wallet) {
// Map bad format to not found, since bad format is returned when the
// wallet directory exists, but doesn't contain a data file.
- RPCErrorCode code = status == DatabaseStatus::FAILED_NOT_FOUND || status == DatabaseStatus::FAILED_BAD_FORMAT ? RPC_WALLET_NOT_FOUND : RPC_WALLET_ERROR;
+ RPCErrorCode code = RPC_WALLET_ERROR;
+ switch (status) {
+ case DatabaseStatus::FAILED_NOT_FOUND:
+ case DatabaseStatus::FAILED_BAD_FORMAT:
+ code = RPC_WALLET_NOT_FOUND;
+ break;
+ case DatabaseStatus::FAILED_ALREADY_LOADED:
+ code = RPC_WALLET_ALREADY_LOADED;
+ break;
+ default: // RPC_WALLET_ERROR is returned for all other cases.
+ break;
+ }
throw JSONRPCError(code, error.original);
}
@@ -3003,7 +3013,7 @@ static RPCHelpMan listunspent()
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
if (provider) {
if (scriptPubKey.IsPayToScriptHash()) {
- const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
+ const CScriptID& hash = CScriptID(std::get<ScriptHash>(address));
CScript redeemScript;
if (provider->GetCScript(hash, redeemScript)) {
entry.pushKV("redeemScript", HexStr(redeemScript));
@@ -3013,7 +3023,7 @@ static RPCHelpMan listunspent()
bool extracted = ExtractDestination(redeemScript, witness_destination);
CHECK_NONFATAL(extracted);
// Also return the witness script
- const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(witness_destination);
+ const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(witness_destination);
CScriptID id;
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
CScript witnessScript;
@@ -3023,7 +3033,7 @@ static RPCHelpMan listunspent()
}
}
} else if (scriptPubKey.IsPayToWitnessScriptHash()) {
- const WitnessV0ScriptHash& whash = boost::get<WitnessV0ScriptHash>(address);
+ const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(address);
CScriptID id;
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
CScript witnessScript;
@@ -3450,10 +3460,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
CWallet* const pwallet = wallet.get();
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
- if (!pwallet->chain().rpcEnableDeprecated("bumpfee")) {
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "Using bumpfee with wallets that have private keys disabled is deprecated. Use psbtbumpfee instead or restart bitcoind with -deprecatedrpc=bumpfee. This functionality will be removed in 0.22");
- }
- want_psbt = true;
+ throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
}
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
@@ -3597,7 +3604,7 @@ static RPCHelpMan rescanblockchain()
}
int start_height = 0;
- Optional<int> stop_height = MakeOptional(false, int());
+ Optional<int> stop_height;
uint256 start_block;
{
LOCK(pwallet->cs_wallet);
@@ -3646,7 +3653,7 @@ static RPCHelpMan rescanblockchain()
};
}
-class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
+class DescribeWalletAddressVisitor
{
public:
const SigningProvider * const provider;
@@ -3665,7 +3672,7 @@ public:
UniValue subobj(UniValue::VOBJ);
UniValue detail = DescribeAddress(embedded);
subobj.pushKVs(detail);
- UniValue wallet_detail = boost::apply_visitor(*this, embedded);
+ UniValue wallet_detail = std::visit(*this, embedded);
subobj.pushKVs(wallet_detail);
subobj.pushKV("address", EncodeDestination(embedded));
subobj.pushKV("scriptPubKey", HexStr(subscript));
@@ -3748,7 +3755,7 @@ static UniValue DescribeWalletAddress(const CWallet* const pwallet, const CTxDes
provider = pwallet->GetSolvingProvider(script);
}
ret.pushKVs(detail);
- ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(provider.get()), dest));
+ ret.pushKVs(std::visit(DescribeWalletAddressVisitor(provider.get()), dest));
return ret;
}
@@ -3824,13 +3831,19 @@ RPCHelpMan getaddressinfo()
LOCK(pwallet->cs_wallet);
- UniValue ret(UniValue::VOBJ);
- CTxDestination dest = DecodeDestination(request.params[0].get_str());
+ std::string error_msg;
+ CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
+
// Make sure the destination is valid
if (!IsValidDestination(dest)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ // Set generic error message in case 'DecodeDestination' didn't set it
+ if (error_msg.empty()) error_msg = "Invalid address";
+
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error_msg);
}
+ UniValue ret(UniValue::VOBJ);
+
std::string currentAddress = EncodeDestination(dest);
ret.pushKV("address", currentAddress);
@@ -4538,73 +4551,75 @@ RPCHelpMan importprunedfunds();
RPCHelpMan removeprunedfunds();
RPCHelpMan importmulti();
RPCHelpMan importdescriptors();
+RPCHelpMan listdescriptors();
Span<const CRPCCommand> GetWalletRPCCommands()
{
// clang-format off
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
- { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
- { "wallet", "abortrescan", &abortrescan, {} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
- { "wallet", "backupwallet", &backupwallet, {"destination"} },
- { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
- { "wallet", "psbtbumpfee", &psbtbumpfee, {"txid", "options"} },
- { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors", "load_on_startup"} },
- { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
- { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
- { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
- { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} },
- { "wallet", "getaddressinfo", &getaddressinfo, {"address"} },
- { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly","avoid_reuse"} },
- { "wallet", "getnewaddress", &getnewaddress, {"label","address_type"} },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
- { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
- { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly","verbose"} },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
- { "wallet", "getbalances", &getbalances, {} },
- { "wallet", "getwalletinfo", &getwalletinfo, {} },
- { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
- { "wallet", "importdescriptors", &importdescriptors, {"requests"} },
- { "wallet", "importmulti", &importmulti, {"requests","options"} },
- { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
- { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
- { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, {"filename"} },
- { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
- { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
- { "wallet", "listlabels", &listlabels, {"purpose"} },
- { "wallet", "listlockunspent", &listlockunspent, {} },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
- { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
- { "wallet", "listtransactions", &listtransactions, {"label|dummy","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
- { "wallet", "listwalletdir", &listwalletdir, {} },
- { "wallet", "listwallets", &listwallets, {} },
- { "wallet", "loadwallet", &loadwallet, {"filename", "load_on_startup"} },
- { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
- { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
- { "wallet", "send", &send, {"outputs","conf_target","estimate_mode","fee_rate","options"} },
- { "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode","fee_rate","verbose"} },
- { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse","fee_rate","verbose"} },
- { "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
- { "wallet", "setlabel", &setlabel, {"address","label"} },
- { "wallet", "settxfee", &settxfee, {"amount"} },
- { "wallet", "setwalletflag", &setwalletflag, {"flag","value"} },
- { "wallet", "signmessage", &signmessage, {"address","message"} },
- { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
- { "wallet", "unloadwallet", &unloadwallet, {"wallet_name", "load_on_startup"} },
- { "wallet", "upgradewallet", &upgradewallet, {"version"} },
- { "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} },
- { "wallet", "walletlock", &walletlock, {} },
- { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
- { "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} },
+{ // category actor (function)
+ // ------------------ ------------------------
+ { "rawtransactions", &fundrawtransaction, },
+ { "wallet", &abandontransaction, },
+ { "wallet", &abortrescan, },
+ { "wallet", &addmultisigaddress, },
+ { "wallet", &backupwallet, },
+ { "wallet", &bumpfee, },
+ { "wallet", &psbtbumpfee, },
+ { "wallet", &createwallet, },
+ { "wallet", &dumpprivkey, },
+ { "wallet", &dumpwallet, },
+ { "wallet", &encryptwallet, },
+ { "wallet", &getaddressesbylabel, },
+ { "wallet", &getaddressinfo, },
+ { "wallet", &getbalance, },
+ { "wallet", &getnewaddress, },
+ { "wallet", &getrawchangeaddress, },
+ { "wallet", &getreceivedbyaddress, },
+ { "wallet", &getreceivedbylabel, },
+ { "wallet", &gettransaction, },
+ { "wallet", &getunconfirmedbalance, },
+ { "wallet", &getbalances, },
+ { "wallet", &getwalletinfo, },
+ { "wallet", &importaddress, },
+ { "wallet", &importdescriptors, },
+ { "wallet", &importmulti, },
+ { "wallet", &importprivkey, },
+ { "wallet", &importprunedfunds, },
+ { "wallet", &importpubkey, },
+ { "wallet", &importwallet, },
+ { "wallet", &keypoolrefill, },
+ { "wallet", &listaddressgroupings, },
+ { "wallet", &listdescriptors, },
+ { "wallet", &listlabels, },
+ { "wallet", &listlockunspent, },
+ { "wallet", &listreceivedbyaddress, },
+ { "wallet", &listreceivedbylabel, },
+ { "wallet", &listsinceblock, },
+ { "wallet", &listtransactions, },
+ { "wallet", &listunspent, },
+ { "wallet", &listwalletdir, },
+ { "wallet", &listwallets, },
+ { "wallet", &loadwallet, },
+ { "wallet", &lockunspent, },
+ { "wallet", &removeprunedfunds, },
+ { "wallet", &rescanblockchain, },
+ { "wallet", &send, },
+ { "wallet", &sendmany, },
+ { "wallet", &sendtoaddress, },
+ { "wallet", &sethdseed, },
+ { "wallet", &setlabel, },
+ { "wallet", &settxfee, },
+ { "wallet", &setwalletflag, },
+ { "wallet", &signmessage, },
+ { "wallet", &signrawtransactionwithwallet, },
+ { "wallet", &unloadwallet, },
+ { "wallet", &upgradewallet, },
+ { "wallet", &walletcreatefundedpsbt, },
+ { "wallet", &walletlock, },
+ { "wallet", &walletpassphrase, },
+ { "wallet", &walletpassphrasechange, },
+ { "wallet", &walletprocesspsbt, },
};
// clang-format on
return MakeSpan(commands);
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index cec46a0fbb..8f6b69bc78 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -304,7 +304,7 @@ private:
/* the HD chain data model (external chain counters) */
CHDChain m_hd_chain;
- std::unordered_map<CKeyID, CHDChain, KeyIDHasher> m_inactive_hd_chains;
+ std::unordered_map<CKeyID, CHDChain, SaltedSipHasher> m_inactive_hd_chains;
/* HD derive new child key (on internal or external chain) */
void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h
index 442563184e..70ab4f797a 100644
--- a/src/wallet/sqlite.h
+++ b/src/wallet/sqlite.h
@@ -37,7 +37,7 @@ public:
explicit SQLiteBatch(SQLiteDatabase& database);
~SQLiteBatch() override { Close(); }
- /* No-op. See commeng on SQLiteDatabase::Flush */
+ /* No-op. See comment on SQLiteDatabase::Flush */
void Flush() override {}
void Close() override;
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 019161415c..202804c9ff 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
BOOST_CHECK( testWallet.SelectCoinsMinConf(1 * MIN_CHANGE, filter_confirmed, GroupCoins(vCoins), setCoinsRet, nValueRet, coin_selection_params, bnb_used));
BOOST_CHECK_EQUAL(nValueRet, 1 * MIN_CHANGE); // we should get the exact amount
- // run the 'mtgox' test (see http://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
+ // run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
empty_wallet();
for (int j = 0; j < 20; j++)
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 1a28852a6b..27179839b7 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 334e4ae0d8..f035a70a20 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -1,8 +1,9 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 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 <fs.h>
+#include <univalue.h>
#include <util/check.h>
#include <util/system.h>
@@ -37,6 +38,9 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
{
+ gArgs.LockSettings([&](util::Settings& settings) {
+ settings.forced_settings.erase("walletdir");
+ });
fs::current_path(m_cwd);
}
diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h
index f666c45a34..37ae907de5 100644
--- a/src/wallet/test/init_test_fixture.h
+++ b/src/wallet/test/init_test_fixture.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 9b905569fc..e70b56c529 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018-2019 The Bitcoin Core developers
+// Copyright (c) 2018-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index 0ef8b9c4bf..5d25885bd4 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index 10ddfa22ef..5b421840e0 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2019 The Bitcoin Core developers
+// Copyright (c) 2014-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index a6db261914..5480f3ab22 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -550,7 +550,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
list = wallet->ListCoins();
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
// Check initial balance from one mature coinbase transaction.
@@ -566,7 +566,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
list = wallet->ListCoins();
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
// Lock both coins. Confirm number of available coins drops to 0.
@@ -595,7 +595,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
list = wallet->ListCoins();
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(std::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
}
diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp
index a3859e2e4b..558121ae42 100644
--- a/src/wallet/test/walletdb_tests.cpp
+++ b/src/wallet/test/walletdb_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2019 The Bitcoin Core developers
+// Copyright (c) 2012-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 740e671595..723552860a 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -85,9 +85,9 @@ static void UpdateWalletSetting(interfaces::Chain& chain,
std::vector<bilingual_str>& warnings)
{
if (load_on_startup == nullopt) return;
- if (load_on_startup.get() && !AddWalletSetting(chain, wallet_name)) {
+ if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) {
warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));
- } else if (!load_on_startup.get() && !RemoveWalletSetting(chain, wallet_name)) {
+ } else if (!load_on_startup.value() && !RemoveWalletSetting(chain, wallet_name)) {
warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));
}
}
@@ -570,7 +570,7 @@ void CWallet::AddToSpends(const uint256& wtxid)
{
auto it = mapWallet.find(wtxid);
assert(it != mapWallet.end());
- CWalletTx& thisTx = it->second;
+ const CWalletTx& thisTx = it->second;
if (thisTx.IsCoinBase()) // Coinbases don't spend anything!
return;
@@ -1054,7 +1054,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
// Can't mark abandoned if confirmed or in mempool
auto it = mapWallet.find(hashTx);
assert(it != mapWallet.end());
- CWalletTx& origtx = it->second;
+ const CWalletTx& origtx = it->second;
if (origtx.GetDepthInMainChain() != 0 || origtx.InMempool()) {
return false;
}
@@ -2709,7 +2709,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, const uin
return locktime;
}
-OutputType CWallet::TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend)
+OutputType CWallet::TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const
{
// If -changetype is specified, always use that change type.
if (change_type) {
@@ -2789,7 +2789,7 @@ bool CWallet::CreateTransactionInternal(
CScript scriptChange;
// coin control: send change to custom address
- if (!boost::get<CNoDestination>(&coin_control.destChange)) {
+ if (!std::get_if<CNoDestination>(&coin_control.destChange)) {
scriptChange = GetScriptForDestination(coin_control.destChange);
} else { // no coin control: send change to newly generated address
// Note: We use a new key here to keep it from being obvious which side is the change.
@@ -3051,7 +3051,7 @@ bool CWallet::CreateTransactionInternal(
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest possible change from prior
// behavior."
- const uint32_t nSequence = coin_control.m_signal_bip125_rbf.get_value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
+ const uint32_t nSequence = coin_control.m_signal_bip125_rbf.value_or(m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1);
for (const auto& coin : selected_coins) {
txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence));
}
@@ -3724,7 +3724,7 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key, const std::string &value)
{
- if (boost::get<CNoDestination>(&dest))
+ if (std::get_if<CNoDestination>(&dest))
return false;
m_address_book[dest].destdata.insert(std::make_pair(key, value));
@@ -3780,7 +3780,7 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons
// 2. Path to an existing directory.
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
- const fs::path& wallet_path = fs::absolute(name, GetWalletDir());
+ const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), name);
fs::file_type path_type = fs::symlink_status(wallet_path).type();
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
@@ -4055,8 +4055,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
- // The way the 'time_first_key' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
- Optional<int64_t> time_first_key = MakeOptional(false, int64_t());;
+ Optional<int64_t> time_first_key;
for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
int64_t time = spk_man->GetTimeFirstKey();
if (!time_first_key || time < *time_first_key) time_first_key = time;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index e6beb111fb..e3eae1dd95 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -930,7 +930,7 @@ public:
Balance GetBalance(int min_depth = 0, bool avoid_reuse = true) const;
CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
- OutputType TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend);
+ OutputType TransactionChangeType(const Optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const;
/**
* Insert additional inputs into the transaction by
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 5b72a01939..4e6270220e 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -426,7 +426,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
uint256 checksum;
ssValue >> checksum;
if ((checksum_valid = Hash(vchPrivKey) != checksum)) {
- strErr = "Error reading wallet database: Crypted key corrupt";
+ strErr = "Error reading wallet database: Encrypted key corrupt";
return false;
}
}
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index fe3fcb32c2..bc90491a2c 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -103,25 +103,27 @@ static void WalletShowInfo(CWallet* wallet_instance)
tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
}
-bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
+bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command, const std::string& name)
{
- fs::path path = fs::absolute(name, GetWalletDir());
+ const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), name);
- // -format is only allowed with createfromdump. Disallow it for all other commands.
- if (gArgs.IsArgSet("-format") && command != "createfromdump") {
+ if (args.IsArgSet("-format") && command != "createfromdump") {
tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n");
return false;
}
- // -dumpfile is only allowed with dump and createfromdump. Disallow it for all other commands.
- if (gArgs.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
+ if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
return false;
}
+ if (args.IsArgSet("-descriptors") && command != "create") {
+ tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
+ return false;
+ }
if (command == "create") {
DatabaseOptions options;
options.require_create = true;
- if (gArgs.GetBoolArg("-descriptors", false)) {
+ if (args.GetBoolArg("-descriptors", false)) {
options.create_flags |= WALLET_FLAG_DESCRIPTORS;
options.require_format = DatabaseFormat::SQLITE;
}
diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h
index d0b8d6812a..f544a6f727 100644
--- a/src/wallet/wallettool.h
+++ b/src/wallet/wallettool.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2019 The Bitcoin Core developers
+// Copyright (c) 2016-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,7 @@
namespace WalletTool {
void WalletShowInfo(CWallet* wallet_instance);
-bool ExecuteWalletToolFunc(const std::string& command, const std::string& file);
+bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command, const std::string& file);
} // namespace WalletTool
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index 16ddad3a84..dd2f071b6c 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h
index d4143ceff4..67b2ee2b98 100644
--- a/src/wallet/walletutil.h
+++ b/src/wallet/walletutil.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h
index a55e02f2dc..660b0eed5d 100644
--- a/src/walletinitinterface.h
+++ b/src/walletinitinterface.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2019 The Bitcoin Core developers
+// Copyright (c) 2017-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/warnings.cpp b/src/warnings.cpp
index 1dec663a73..60388cc713 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/warnings.h b/src/warnings.h
index e87b64a86d..c38edb4570 100644
--- a/src/warnings.h
+++ b/src/warnings.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index 3938f6fd2c..90aefb0018 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
index dddba8d6b6..6f0b202a18 100644
--- a/src/zmq/zmqabstractnotifier.h
+++ b/src/zmq/zmqabstractnotifier.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index a2f994d7df..86f47d71f3 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index 788a383517..8f81bfd63f 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2019 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
index c0207f9dd6..168ba841c8 100644
--- a/src/zmq/zmqpublishnotifier.cpp
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -17,6 +17,7 @@
#include <cstdarg>
#include <cstddef>
#include <map>
+#include <optional>
#include <string>
#include <utility>
@@ -227,50 +228,43 @@ bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &tr
return SendZmqMessage(MSG_RAWTX, &(*ss.begin()), ss.size());
}
+// Helper function to send a 'sequence' topic message with the following structure:
+// <32-byte hash> | <1-byte label> | <8-byte LE sequence> (optional)
+static bool SendSequenceMsg(CZMQAbstractPublishNotifier& notifier, uint256 hash, char label, std::optional<uint64_t> sequence = {})
+{
+ unsigned char data[sizeof(hash) + sizeof(label) + sizeof(uint64_t)];
+ for (unsigned int i = 0; i < sizeof(hash); ++i) {
+ data[sizeof(hash) - 1 - i] = hash.begin()[i];
+ }
+ data[sizeof(hash)] = label;
+ if (sequence) WriteLE64(data + sizeof(hash) + sizeof(label), *sequence);
+ return notifier.SendZmqMessage(MSG_SEQUENCE, data, sequence ? sizeof(data) : sizeof(hash) + sizeof(label));
+}
-// TODO: Dedup this code to take label char, log string
bool CZMQPublishSequenceNotifier::NotifyBlockConnect(const CBlockIndex *pindex)
{
uint256 hash = pindex->GetBlockHash();
LogPrint(BCLog::ZMQ, "zmq: Publish sequence block connect %s to %s\n", hash.GetHex(), this->address);
- char data[sizeof(uint256)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(data) - 1] = 'C'; // Block (C)onnect
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Block (C)onnect */ 'C');
}
bool CZMQPublishSequenceNotifier::NotifyBlockDisconnect(const CBlockIndex *pindex)
{
uint256 hash = pindex->GetBlockHash();
LogPrint(BCLog::ZMQ, "zmq: Publish sequence block disconnect %s to %s\n", hash.GetHex(), this->address);
- char data[sizeof(uint256)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(data) - 1] = 'D'; // Block (D)isconnect
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Block (D)isconnect */ 'D');
}
bool CZMQPublishSequenceNotifier::NotifyTransactionAcceptance(const CTransaction &transaction, uint64_t mempool_sequence)
{
uint256 hash = transaction.GetHash();
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool acceptance %s to %s\n", hash.GetHex(), this->address);
- unsigned char data[sizeof(uint256)+sizeof(mempool_sequence)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(uint256)] = 'A'; // Mempool (A)cceptance
- WriteLE64(data+sizeof(uint256)+1, mempool_sequence);
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Mempool (A)cceptance */ 'A', mempool_sequence);
}
bool CZMQPublishSequenceNotifier::NotifyTransactionRemoval(const CTransaction &transaction, uint64_t mempool_sequence)
{
uint256 hash = transaction.GetHash();
LogPrint(BCLog::ZMQ, "zmq: Publish hashtx mempool removal %s to %s\n", hash.GetHex(), this->address);
- unsigned char data[sizeof(uint256)+sizeof(mempool_sequence)+1];
- for (unsigned int i = 0; i < sizeof(uint256); i++)
- data[sizeof(uint256) - 1 - i] = hash.begin()[i];
- data[sizeof(uint256)] = 'R'; // Mempool (R)emoval
- WriteLE64(data+sizeof(uint256)+1, mempool_sequence);
- return SendZmqMessage(MSG_SEQUENCE, data, sizeof(data));
+ return SendSequenceMsg(*this, hash, /* Mempool (R)emoval */ 'R', mempool_sequence);
}
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
index f13ed6f537..c1d66bddb1 100644
--- a/src/zmq/zmqpublishnotifier.h
+++ b/src/zmq/zmqpublishnotifier.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp
index 1dd751b493..81859f924f 100644
--- a/src/zmq/zmqrpc.cpp
+++ b/src/zmq/zmqrpc.cpp
@@ -52,9 +52,9 @@ static RPCHelpMan getzmqnotifications()
}
const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // ----------------- ------------------------ ----------------------- ----------
- { "zmq", "getzmqnotifications", &getzmqnotifications, {} },
+{ // category actor (function)
+ // ----------------- -----------------------
+ { "zmq", &getzmqnotifications, },
};
} // anonymous namespace
diff --git a/test/README.md b/test/README.md
index 2341eef00d..17bf8a1406 100644
--- a/test/README.md
+++ b/test/README.md
@@ -264,7 +264,7 @@ Use the `-v` option for verbose output.
| [`lint-python.sh`](lint/lint-python.sh) | [mypy](https://github.com/python/mypy) | [0.781](https://github.com/bitcoin/bitcoin/pull/19348) | `pip3 install mypy==0.781`
| [`lint-shell.sh`](lint/lint-shell.sh) | [ShellCheck](https://github.com/koalaman/shellcheck) | [0.7.1](https://github.com/bitcoin/bitcoin/pull/19348) | [details...](https://github.com/koalaman/shellcheck#installing)
| [`lint-shell.sh`](lint/lint-shell.sh) | [yq](https://github.com/kislyuk/yq) | default | `pip3 install yq`
-| [`lint-spelling.sh`](lint/lint-spelling.sh) | [codespell](https://github.com/codespell-project/codespell) | [1.17.1](https://github.com/bitcoin/bitcoin/pull/19348) | `pip3 install codespell==1.17.1`
+| [`lint-spelling.sh`](lint/lint-spelling.sh) | [codespell](https://github.com/codespell-project/codespell) | [2.0.0](https://github.com/bitcoin/bitcoin/pull/20817) | `pip3 install codespell==2.0.0`
Please be aware that on Linux distributions all dependencies are usually available as packages, but could be outdated.
diff --git a/test/functional/README.md b/test/functional/README.md
index 2764acbf18..2d04413eb2 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -23,7 +23,7 @@ don't have test cases for.
- The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md).
Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version),
to prevent accidentally introducing modern syntax from an unsupported Python version.
- The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
+ The CI linter job also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that
could lead to bugs and issues in the test code.
- Use [type hints](https://docs.python.org/3/library/typing.html) in your code to improve code readability
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index c28bb7115f..97f24e1b6e 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""An example functional test
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 60492350ee..6c5857c5ce 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 BIP68 implementation."""
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index aad255c4a9..b7c2887ee8 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -126,8 +126,13 @@ class BIP65Test(BitcoinTestFramework):
# First we show that this tx is valid except for CLTV by getting it
# rejected from the mempool for exactly that reason.
assert_equal(
- [{'txid': spendtx.hash, 'allowed': False, 'reject-reason': 'non-mandatory-script-verify-flag (Negative locktime)'}],
- self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
+ [{
+ 'txid': spendtx.hash,
+ 'wtxid': spendtx.getwtxid(),
+ 'allowed': False,
+ 'reject-reason': 'non-mandatory-script-verify-flag (Negative locktime)',
+ }],
+ self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
)
# Now we verify that a block with this transaction is also invalid.
diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py
index 3e28dae4b3..2445b6d977 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -7,6 +7,7 @@
import os
from test_framework.test_framework import BitcoinTestFramework
+from test_framework import util
class ConfArgsTest(BitcoinTestFramework):
@@ -42,10 +43,11 @@ class ConfArgsTest(BitcoinTestFramework):
conf.write("wallet=foo\n")
self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Config setting for -wallet only applied on %s network when in [%s] section.' % (self.chain, self.chain))
+ main_conf_file_path = os.path.join(self.options.tmpdir, 'node0', 'bitcoin_main.conf')
+ util.write_config(main_conf_file_path, n=0, chain='', extra_config='includeconf={}\n'.format(inc_conf_file_path))
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
- conf.write('regtest=0\n') # mainnet
conf.write('acceptnonstdtxn=1\n')
- self.nodes[0].assert_start_raises_init_error(expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
+ self.nodes[0].assert_start_raises_init_error(extra_args=["-conf={}".format(main_conf_file_path)], expected_msg='Error: acceptnonstdtxn is not currently supported for main chain')
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('nono\n')
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 7a2e35c095..f9ece244fb 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 recovery from a crash during chainstate writing.
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 3f7efdbded..3b430139b1 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -112,8 +112,13 @@ class BIP66Test(BitcoinTestFramework):
# First we show that this tx is valid except for DERSIG by getting it
# rejected from the mempool for exactly that reason.
assert_equal(
- [{'txid': spendtx.hash, 'allowed': False, 'reject-reason': 'non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
- self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0)
+ [{
+ 'txid': spendtx.hash,
+ 'wtxid': spendtx.getwtxid(),
+ 'allowed': False,
+ 'reject-reason': 'non-mandatory-script-verify-flag (Non-canonical DER signature)',
+ }],
+ self.nodes[0].testmempoolaccept(rawtxs=[spendtx.serialize().hex()], maxfeerate=0),
)
# Now we verify that a block with this transaction is also invalid.
diff --git a/test/functional/feature_help.py b/test/functional/feature_help.py
index 9f18413255..babe9bfc80 100755
--- a/test/functional/feature_help.py
+++ b/test/functional/feature_help.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Verify that starting bitcoin with -h works as expected."""
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py
index abf87e8f0c..803feb509a 100755
--- a/test/functional/feature_minchainwork.py
+++ b/test/functional/feature_minchainwork.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2018 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 logic for setting nMinimumChainWork on command line.
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 47bc8dbb49..f2313bac13 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 -alertnotify, -blocknotify and -walletnotify options."""
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index b0eac7056b..bdbfa5aed1 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -60,7 +60,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.wit_address = w0.getnewaddress(address_type='p2sh-segwit')
self.wit_ms_address = wmulti.addmultisigaddress(1, [self.pubkey], '', 'p2sh-segwit')['address']
if not self.options.descriptors:
- # Legacy wallets need to import these so that they are watched by the wallet. This is unnecssary (and does not need to be tested) for descriptor wallets
+ # Legacy wallets need to import these so that they are watched by the wallet. This is unnecessary (and does not need to be tested) for descriptor wallets
wmulti.importaddress(self.ms_address)
wmulti.importaddress(self.wit_ms_address)
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index 05b658ed87..cd5eff9184 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 bitcoind with different proxy configuration.
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index 1b531ad51d..c6f55c62b4 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 RBF code."""
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index 31cea8d1b7..68585b7475 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 running bitcoind with -reindex and -reindex-chainstate options.
diff --git a/test/functional/feature_shutdown.py b/test/functional/feature_shutdown.py
index a76e0f1b50..291df4c518 100755
--- a/test/functional/feature_shutdown.py
+++ b/test/functional/feature_shutdown.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 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 bitcoind shutdown."""
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index 2e4f4796b0..062a7affb5 100755
--- a/test/functional/feature_versionbits_warning.py
+++ b/test/functional/feature_versionbits_warning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2020 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 version bits warning system.
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index d675ae174c..946bfa51d4 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 notification interface."""
@@ -80,34 +80,43 @@ class ZMQTest (BitcoinTestFramework):
self.log.debug("Destroying ZMQ context")
self.ctx.destroy(linger=None)
+ # Restart node with the specified zmq notifications enabled, subscribe to
+ # all of them and return the corresponding ZMQSubscriber objects.
+ def setup_zmq_test(self, services, recv_timeout=60, connect_nodes=False):
+ subscribers = []
+ for topic, address in services:
+ socket = self.ctx.socket(zmq.SUB)
+ socket.set(zmq.RCVTIMEO, recv_timeout*1000)
+ subscribers.append(ZMQSubscriber(socket, topic.encode()))
+
+ self.restart_node(0, ["-zmqpub%s=%s" % (topic, address) for topic, address in services])
+
+ if connect_nodes:
+ self.connect_nodes(0, 1)
+
+ for i, sub in enumerate(subscribers):
+ sub.socket.connect(services[i][1])
+
+ # Relax so that the subscribers are ready before publishing zmq messages
+ sleep(0.2)
+
+ return subscribers
+
def test_basic(self):
# Invalid zmq arguments don't take down the node, see #17185.
self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"])
address = 'tcp://127.0.0.1:28332'
- sockets = []
- subs = []
- services = [b"hashblock", b"hashtx", b"rawblock", b"rawtx"]
- for service in services:
- sockets.append(self.ctx.socket(zmq.SUB))
- sockets[-1].set(zmq.RCVTIMEO, 60000)
- subs.append(ZMQSubscriber(sockets[-1], service))
-
- # Subscribe to all available topics.
+ subs = self.setup_zmq_test(
+ [(topic, address) for topic in ["hashblock", "hashtx", "rawblock", "rawtx"]],
+ connect_nodes=True)
+
hashblock = subs[0]
hashtx = subs[1]
rawblock = subs[2]
rawtx = subs[3]
- self.restart_node(0, ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [hashblock, hashtx, rawblock, rawtx]])
- self.connect_nodes(0, 1)
- for socket in sockets:
- socket.connect(address)
-
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
-
num_blocks = 5
self.log.info("Generate %(n)d blocks (and %(n)d coinbase txes)" % {"n": num_blocks})
genhashes = self.nodes[0].generatetoaddress(num_blocks, ADDRESS_BCRT1_UNSPENDABLE)
@@ -174,25 +183,10 @@ class ZMQTest (BitcoinTestFramework):
address = 'tcp://127.0.0.1:28333'
- services = [b"hashblock", b"hashtx"]
- sockets = []
- subs = []
- for service in services:
- sockets.append(self.ctx.socket(zmq.SUB))
- # 2 second timeout to check end of notifications
- sockets[-1].set(zmq.RCVTIMEO, 2000)
- subs.append(ZMQSubscriber(sockets[-1], service))
-
- # Subscribe to all available topics.
- hashblock = subs[0]
- hashtx = subs[1]
-
# Should only notify the tip if a reorg occurs
- self.restart_node(0, ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [hashblock, hashtx]])
- for socket in sockets:
- socket.connect(address)
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ hashblock, hashtx = self.setup_zmq_test(
+ [(topic, address) for topic in ["hashblock", "hashtx"]],
+ recv_timeout=2) # 2 second timeout to check end of notifications
# Generate 1 block in nodes[0] with 1 mempool tx and receive all notifications
payment_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1.0)
@@ -240,15 +234,7 @@ class ZMQTest (BitcoinTestFramework):
<32-byte hash>A<8-byte LE uint> : Transactionhash added mempool
"""
self.log.info("Testing 'sequence' publisher")
- address = 'tcp://127.0.0.1:28333'
- socket = self.ctx.socket(zmq.SUB)
- socket.set(zmq.RCVTIMEO, 60000)
- seq = ZMQSubscriber(socket, b'sequence')
-
- self.restart_node(0, ['-zmqpub%s=%s' % (seq.topic.decode(), address)])
- socket.connect(address)
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")])
# Mempool sequence number starts at 1
seq_num = 1
@@ -399,16 +385,7 @@ class ZMQTest (BitcoinTestFramework):
return
self.log.info("Testing 'mempool sync' usage of sequence notifier")
- address = 'tcp://127.0.0.1:28333'
- socket = self.ctx.socket(zmq.SUB)
- socket.set(zmq.RCVTIMEO, 60000)
- seq = ZMQSubscriber(socket, b'sequence')
-
- self.restart_node(0, ['-zmqpub%s=%s' % (seq.topic.decode(), address)])
- self.connect_nodes(0, 1)
- socket.connect(address)
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ [seq] = self.setup_zmq_test([("sequence", "tcp://127.0.0.1:28333")], connect_nodes=True)
# In-memory counter, should always start at 1
next_mempool_seq = self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"]
@@ -508,26 +485,17 @@ class ZMQTest (BitcoinTestFramework):
def test_multiple_interfaces(self):
# Set up two subscribers with different addresses
- subscribers = []
- for i in range(2):
- address = 'tcp://127.0.0.1:%d' % (28334 + i)
- socket = self.ctx.socket(zmq.SUB)
- socket.set(zmq.RCVTIMEO, 60000)
- hashblock = ZMQSubscriber(socket, b"hashblock")
- socket.connect(address)
- subscribers.append({'address': address, 'hashblock': hashblock})
-
- self.restart_node(0, ['-zmqpub%s=%s' % (subscriber['hashblock'].topic.decode(), subscriber['address']) for subscriber in subscribers])
-
- # Relax so that the subscriber is ready before publishing zmq messages
- sleep(0.2)
+ subscribers = self.setup_zmq_test([
+ ("hashblock", "tcp://127.0.0.1:28334"),
+ ("hashblock", "tcp://127.0.0.1:28335"),
+ ])
# Generate 1 block in nodes[0] and receive all notifications
self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)
# Should receive the same block hash on both subscribers
- assert_equal(self.nodes[0].getbestblockhash(), subscribers[0]['hashblock'].receive().hex())
- assert_equal(self.nodes[0].getbestblockhash(), subscribers[1]['hashblock'].receive().hex())
+ assert_equal(self.nodes[0].getbestblockhash(), subscribers[0].receive().hex())
+ assert_equal(self.nodes[0].getbestblockhash(), subscribers[1].receive().hex())
if __name__ == '__main__':
ZMQTest().main()
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index fc4c775668..c4002f524a 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -51,6 +51,8 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
def check_mempool_result(self, result_expected, *args, **kwargs):
"""Wrapper to check result of testmempoolaccept on node_0's mempool"""
result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
+ for r in result_test:
+ r.pop('wtxid') # Skip check for now
assert_equal(result_expected, result_test)
assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size) # Must not change mempool state
diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py
index 8ac91bd008..eb08765ebf 100755
--- a/test/functional/mempool_compatibility.py
+++ b/test/functional/mempool_compatibility.py
@@ -16,15 +16,15 @@ Only v0.15.2 is required by this test. The rest is used in other backwards compa
import os
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.wallet import MiniWallet
class MempoolCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
- self.wallet_names = [None, self.default_wallet_name]
+ self.wallet_names = [None]
def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
self.skip_if_no_previous_releases()
def setup_network(self):
@@ -38,8 +38,15 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Test that mempool.dat is compatible between versions")
- old_node = self.nodes[0]
- new_node = self.nodes[1]
+ old_node, new_node = self.nodes
+ new_wallet = MiniWallet(new_node)
+ new_wallet.generate(1)
+ new_node.generate(100)
+ # Sync the nodes to ensure old_node has the block that contains the coinbase that new_wallet will spend.
+ # Otherwise, because coinbases are only valid in a block and not as loose txns, if the nodes aren't synced
+ # unbroadcasted_tx won't pass old_node's `MemPoolAccept::PreChecks`.
+ self.connect_nodes(0, 1)
+ self.sync_blocks()
recipient = old_node.getnewaddress()
self.stop_node(1)
@@ -58,7 +65,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework):
assert old_tx_hash in new_node.getrawmempool()
self.log.info("Add unbroadcasted tx to mempool on new node and shutdown")
- unbroadcasted_tx_hash = new_node.sendtoaddress(recipient, 0.0001)
+ unbroadcasted_tx_hash = new_wallet.send_self_transfer(from_node=new_node)['txid']
assert unbroadcasted_tx_hash in new_node.getrawmempool()
mempool = new_node.getrawmempool(True)
assert mempool[unbroadcasted_tx_hash]['unbroadcast']
diff --git a/test/functional/mempool_package_onemore.py b/test/functional/mempool_package_onemore.py
index e956fe07d2..a9e2b000fb 100755
--- a/test/functional/mempool_package_onemore.py
+++ b/test/functional/mempool_package_onemore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 descendant package tracking carve-out allowing one final transaction in
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index d7cb7db9f8..461f9237ff 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 descendant package tracking code."""
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 187c9026f6..4aa58270b6 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -1,69 +1,62 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 resurrection of mined transactions when the blockchain is re-organized."""
-from test_framework.blocktools import create_raw_transaction
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+from test_framework.wallet import MiniWallet
class MempoolCoinbaseTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
-
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
+ self.setup_clean_chain = True
def run_test(self):
- node0_address = self.nodes[0].getnewaddress()
+ node = self.nodes[0]
+ wallet = MiniWallet(node)
+
+ # Add enough mature utxos to the wallet so that all txs spend confirmed coins
+ wallet.generate(3)
+ node.generate(100)
+
# Spend block 1/2/3's coinbase transactions
- # Mine a block.
+ # Mine a block
# Create three more transactions, spending the spends
- # Mine another block.
+ # Mine another block
# ... make sure all the transactions are confirmed
# Invalidate both blocks
# ... make sure all the transactions are put back in the mempool
# Mine a new block
- # ... make sure all the transactions are confirmed again.
-
- b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]
- coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
- spends1_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]
- spends1_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw]
-
+ # ... make sure all the transactions are confirmed again
blocks = []
- blocks.extend(self.nodes[0].generate(1))
-
- spends2_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.98) for txid in spends1_id]
- spends2_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw]
+ spends1_ids = [wallet.send_self_transfer(from_node=node)['txid'] for _ in range(3)]
+ blocks.extend(node.generate(1))
+ spends2_ids = [wallet.send_self_transfer(from_node=node)['txid'] for _ in range(3)]
+ blocks.extend(node.generate(1))
- blocks.extend(self.nodes[0].generate(1))
+ spends_ids = set(spends1_ids + spends2_ids)
# mempool should be empty, all txns confirmed
- assert_equal(set(self.nodes[0].getrawmempool()), set())
- for txid in spends1_id+spends2_id:
- tx = self.nodes[0].gettransaction(txid)
- assert tx["confirmations"] > 0
+ assert_equal(set(node.getrawmempool()), set())
+ confirmed_txns = set(node.getblock(blocks[0])['tx'] + node.getblock(blocks[1])['tx'])
+ # Checks that all spend txns are contained in the mined blocks
+ assert spends_ids < confirmed_txns
# Use invalidateblock to re-org back
- for node in self.nodes:
- node.invalidateblock(blocks[0])
+ node.invalidateblock(blocks[0])
# All txns should be back in mempool with 0 confirmations
- assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))
- for txid in spends1_id+spends2_id:
- tx = self.nodes[0].gettransaction(txid)
- assert tx["confirmations"] == 0
+ assert_equal(set(node.getrawmempool()), spends_ids)
# Generate another block, they should all get mined
- self.nodes[0].generate(1)
+ blocks = node.generate(1)
# mempool should be empty, all txns confirmed
- assert_equal(set(self.nodes[0].getrawmempool()), set())
- for txid in spends1_id+spends2_id:
- tx = self.nodes[0].gettransaction(txid)
- assert tx["confirmations"] > 0
+ assert_equal(set(node.getrawmempool()), set())
+ confirmed_txns = set(node.getblock(blocks[0])['tx'])
+ assert spends_ids < confirmed_txns
if __name__ == '__main__':
diff --git a/test/functional/mempool_spend_coinbase.py b/test/functional/mempool_spend_coinbase.py
index 86d382ff69..a249a73315 100755
--- a/test/functional/mempool_spend_coinbase.py
+++ b/test/functional/mempool_spend_coinbase.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 spending coinbase transactions.
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index 2adafb1fdb..cc32f78e2e 100755
--- a/test/functional/mining_getblocktemplate_longpoll.py
+++ b/test/functional/mining_getblocktemplate_longpoll.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 longpolling with getblocktemplate."""
diff --git a/test/functional/p2p_add_connections.py b/test/functional/p2p_add_connections.py
new file mode 100755
index 0000000000..a63c3a3287
--- /dev/null
+++ b/test/functional/p2p_add_connections.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 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 add_outbound_p2p_connection test framework functionality"""
+
+from test_framework.p2p import P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+def check_node_connections(*, node, num_in, num_out):
+ info = node.getnetworkinfo()
+ assert_equal(info["connections_in"], num_in)
+ assert_equal(info["connections_out"], num_out)
+
+
+class P2PAddConnections(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 2
+
+ def setup_network(self):
+ self.setup_nodes()
+ # Don't connect the nodes
+
+ def run_test(self):
+ self.log.info("Add 8 outbounds to node 0")
+ for i in range(8):
+ self.log.info(f"outbound: {i}")
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="outbound-full-relay")
+
+ self.log.info("Add 2 block-relay-only connections to node 0")
+ for i in range(2):
+ self.log.info(f"block-relay-only: {i}")
+ # set p2p_idx based on the outbound connections already open to the
+ # node, so add 8 to account for the previous full-relay connections
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 8, connection_type="block-relay-only")
+
+ self.log.info("Add 2 block-relay-only connections to node 1")
+ for i in range(2):
+ self.log.info(f"block-relay-only: {i}")
+ self.nodes[1].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i, connection_type="block-relay-only")
+
+ self.log.info("Add 5 inbound connections to node 1")
+ for i in range(5):
+ self.log.info(f"inbound: {i}")
+ self.nodes[1].add_p2p_connection(P2PInterface())
+
+ self.log.info("Add 8 outbounds to node 1")
+ for i in range(8):
+ self.log.info(f"outbound: {i}")
+ # bump p2p_idx to account for the 2 existing outbounds on node 1
+ self.nodes[1].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 2)
+
+ self.log.info("Check the connections opened as expected")
+ check_node_connections(node=self.nodes[0], num_in=0, num_out=10)
+ check_node_connections(node=self.nodes[1], num_in=5, num_out=10)
+
+ self.log.info("Disconnect p2p connections & try to re-open")
+ self.nodes[0].disconnect_p2ps()
+ check_node_connections(node=self.nodes[0], num_in=0, num_out=0)
+
+ self.log.info("Add 8 outbounds to node 0")
+ for i in range(8):
+ self.log.info(f"outbound: {i}")
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i)
+ check_node_connections(node=self.nodes[0], num_in=0, num_out=8)
+
+ self.log.info("Add 2 block-relay-only connections to node 0")
+ for i in range(2):
+ self.log.info(f"block-relay-only: {i}")
+ # bump p2p_idx to account for the 8 existing outbounds on node 0
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 8, connection_type="block-relay-only")
+ check_node_connections(node=self.nodes[0], num_in=0, num_out=10)
+
+ self.log.info("Restart node 0 and try to reconnect to p2ps")
+ self.restart_node(0)
+
+ self.log.info("Add 4 outbounds to node 0")
+ for i in range(4):
+ self.log.info(f"outbound: {i}")
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i)
+ check_node_connections(node=self.nodes[0], num_in=0, num_out=4)
+
+ self.log.info("Add 2 block-relay-only connections to node 0")
+ for i in range(2):
+ self.log.info(f"block-relay-only: {i}")
+ # bump p2p_idx to account for the 4 existing outbounds on node 0
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=i + 4, connection_type="block-relay-only")
+ check_node_connections(node=self.nodes[0], num_in=0, num_out=6)
+
+ check_node_connections(node=self.nodes[1], num_in=5, num_out=10)
+
+
+if __name__ == '__main__':
+ P2PAddConnections().main()
diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py
index 3250cbecf9..03662babef 100755
--- a/test/functional/p2p_blockfilters.py
+++ b/test/functional/p2p_blockfilters.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests NODE_COMPACT_FILTERS (BIP 157/158).
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index e80422d1cf..c592ab52b1 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -1,11 +1,14 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 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 p2p blocksonly"""
+"""Test p2p blocksonly mode & block-relay-only connections."""
-from test_framework.messages import msg_tx, CTransaction, FromHex
-from test_framework.p2p import P2PInterface
+import time
+
+from test_framework.blocktools import create_transaction
+from test_framework.messages import msg_tx
+from test_framework.p2p import P2PInterface, P2PTxInvStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -16,50 +19,32 @@ class P2PBlocksOnly(BitcoinTestFramework):
self.num_nodes = 1
self.extra_args = [["-blocksonly"]]
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
def run_test(self):
- block_relay_peer = self.nodes[0].add_p2p_connection(P2PInterface())
-
- self.log.info('Check that txs from p2p are rejected and result in disconnect')
- prevtx = self.nodes[0].getblock(self.nodes[0].getblockhash(1), 2)['tx'][0]
- rawtx = self.nodes[0].createrawtransaction(
- inputs=[{
- 'txid': prevtx['txid'],
- 'vout': 0
- }],
- outputs=[{
- self.nodes[0].get_deterministic_priv_key().address: 50 - 0.00125
- }],
- )
- sigtx = self.nodes[0].signrawtransactionwithkey(
- hexstring=rawtx,
- privkeys=[self.nodes[0].get_deterministic_priv_key().key],
- prevtxs=[{
- 'txid': prevtx['txid'],
- 'vout': 0,
- 'scriptPubKey': prevtx['vout'][0]['scriptPubKey']['hex'],
- }],
- )['hex']
+ self.blocksonly_mode_tests()
+ self.blocks_relay_conn_tests()
+
+ def blocksonly_mode_tests(self):
+ self.log.info("Tests with node running in -blocksonly mode")
assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], False)
- with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
- block_relay_peer.send_message(msg_tx(FromHex(CTransaction(), sigtx)))
- block_relay_peer.wait_for_disconnect()
- assert_equal(self.nodes[0].getmempoolinfo()['size'], 0)
- # Remove the disconnected peer and add a new one.
- del self.nodes[0].p2ps[0]
- tx_relay_peer = self.nodes[0].add_p2p_connection(P2PInterface())
+ self.nodes[0].add_p2p_connection(P2PInterface())
+ tx, txid, tx_hex = self.check_p2p_tx_violation()
self.log.info('Check that txs from rpc are not rejected and relayed to other peers')
+ tx_relay_peer = self.nodes[0].add_p2p_connection(P2PInterface())
assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True)
- txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
+
+ assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True)
with self.nodes[0].assert_debug_log(['received getdata for: wtx {} peer=1'.format(txid)]):
- self.nodes[0].sendrawtransaction(sigtx)
+ self.nodes[0].sendrawtransaction(tx_hex)
tx_relay_peer.wait_for_tx(txid)
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
- self.log.info('Check that txs from peers with relay-permission are not rejected and relayed to others')
self.log.info("Restarting node 0 with relay permission and blocksonly")
- self.restart_node(0, ["-persistmempool=0", "-whitelist=relay@127.0.0.1", "-blocksonly", '-deprecatedrpc=whitelisted'])
+ self.restart_node(0, ["-persistmempool=0", "-whitelist=relay@127.0.0.1", "-blocksonly"])
assert_equal(self.nodes[0].getrawmempool(), [])
first_peer = self.nodes[0].add_p2p_connection(P2PInterface())
second_peer = self.nodes[0].add_p2p_connection(P2PInterface())
@@ -67,8 +52,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
assert_equal(peer_1_info['permissions'], ['relay'])
peer_2_info = self.nodes[0].getpeerinfo()[1]
assert_equal(peer_2_info['permissions'], ['relay'])
- assert_equal(self.nodes[0].testmempoolaccept([sigtx])[0]['allowed'], True)
- txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
+ assert_equal(self.nodes[0].testmempoolaccept([tx_hex])[0]['allowed'], True)
self.log.info('Check that the tx from first_peer with relay-permission is relayed to others (ie.second_peer)')
with self.nodes[0].assert_debug_log(["received getdata"]):
@@ -78,13 +62,58 @@ class P2PBlocksOnly(BitcoinTestFramework):
# But if, for some reason, first_peer decides to relay transactions to us anyway, we should relay them to
# second_peer since we gave relay permission to first_peer.
# See https://github.com/bitcoin/bitcoin/issues/19943 for details.
- first_peer.send_message(msg_tx(FromHex(CTransaction(), sigtx)))
+ first_peer.send_message(msg_tx(tx))
self.log.info('Check that the peer with relay-permission is still connected after sending the transaction')
assert_equal(first_peer.is_connected, True)
second_peer.wait_for_tx(txid)
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
self.log.info("Relay-permission peer's transaction is accepted and relayed")
+ self.nodes[0].disconnect_p2ps()
+ self.nodes[0].generate(1)
+
+ def blocks_relay_conn_tests(self):
+ self.log.info('Tests with node in normal mode with block-relay-only connections')
+ self.restart_node(0, ["-noblocksonly"]) # disables blocks only mode
+ assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], True)
+
+ # Ensure we disconnect if a block-relay-only connection sends us a transaction
+ self.nodes[0].add_outbound_p2p_connection(P2PInterface(), p2p_idx=0, connection_type="block-relay-only")
+ assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], False)
+ _, txid, tx_hex = self.check_p2p_tx_violation(index=2)
+
+ self.log.info("Check that txs from RPC are not sent to blockrelay connection")
+ conn = self.nodes[0].add_outbound_p2p_connection(P2PTxInvStore(), p2p_idx=1, connection_type="block-relay-only")
+
+ self.nodes[0].sendrawtransaction(tx_hex)
+
+ # Bump time forward to ensure nNextInvSend timer pops
+ self.nodes[0].setmocktime(int(time.time()) + 60)
+
+ # Calling sync_with_ping twice requires that the node calls
+ # `ProcessMessage` twice, and thus ensures `SendMessages` must have
+ # been called at least once
+ conn.sync_with_ping()
+ conn.sync_with_ping()
+ assert(int(txid, 16) not in conn.get_invs())
+
+ def check_p2p_tx_violation(self, index=1):
+ self.log.info('Check that txs from P2P are rejected and result in disconnect')
+ input_txid = self.nodes[0].getblock(self.nodes[0].getblockhash(index), 2)['tx'][0]['txid']
+ tx = create_transaction(self.nodes[0], input_txid, self.nodes[0].getnewaddress(), amount=(50 - 0.001))
+ txid = tx.rehash()
+ tx_hex = tx.serialize().hex()
+
+ with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
+ self.nodes[0].p2ps[0].send_message(msg_tx(tx))
+ self.nodes[0].p2ps[0].wait_for_disconnect()
+ assert_equal(self.nodes[0].getmempoolinfo()['size'], 0)
+
+ # Remove the disconnected peer
+ del self.nodes[0].p2ps[0]
+
+ return tx, txid, tx_hex
+
if __name__ == '__main__':
P2PBlocksOnly().main()
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 9a9df73049..55573efc06 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2020 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 compact blocks (BIP 152).
diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py
index a7f51b5364..fb8529ad2b 100755
--- a/test/functional/p2p_disconnect_ban.py
+++ b/test/functional/p2p_disconnect_ban.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 node disconnect and ban behavior"""
diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py
index 72a255991c..d60aa5b383 100755
--- a/test/functional/p2p_eviction.py
+++ b/test/functional/p2p_eviction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index 51b7623fe3..a2a122b352 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2020 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 processing of feefilter messages."""
diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py
index 9614ab6872..469d66a851 100755
--- a/test/functional/p2p_fingerprint.py
+++ b/test/functional/p2p_fingerprint.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2018 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 various fingerprinting protections.
diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py
index 489d903c21..cca7390ae3 100755
--- a/test/functional/p2p_invalid_tx.py
+++ b/test/functional/p2p_invalid_tx.py
@@ -143,7 +143,7 @@ class InvalidTxRequestTest(BitcoinTestFramework):
}
# Transactions that do not end up in the mempool
# tx_orphan_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx)
- # tx_orphan_invaid, because it has negative fee (p2ps[1] is disconnected for relaying that tx)
+ # tx_orphan_invalid, because it has negative fee (p2ps[1] is disconnected for relaying that tx)
self.wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12) # p2ps[1] is no longer connected
assert_equal(expected_mempool, set(node.getrawmempool()))
diff --git a/test/functional/p2p_nobloomfilter_messages.py b/test/functional/p2p_nobloomfilter_messages.py
index c2311cb197..507a71b2a9 100755
--- a/test/functional/p2p_nobloomfilter_messages.py
+++ b/test/functional/p2p_nobloomfilter_messages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 invalid p2p messages for nodes with bloom filters disabled.
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index b1a7ef6877..8d95f155c8 100755
--- a/test/functional/p2p_node_network_limited.py
+++ b/test/functional/p2p_node_network_limited.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Tests NODE_NETWORK_LIMITED.
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index ed82e6a2e2..62652d949d 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -38,35 +38,24 @@ class P2PPermissionsTests(BitcoinTestFramework):
# default permissions (no specific permissions)
["-whitelist=127.0.0.1"],
# Make sure the default values in the command line documentation match the ones here
- ["relay", "noban", "mempool", "download"],
- True)
-
- self.checkpermission(
- # check without deprecatedrpc=whitelisted
- ["-whitelist=127.0.0.1"],
- # Make sure the default values in the command line documentation match the ones here
- ["relay", "noban", "mempool", "download"],
- None)
+ ["relay", "noban", "mempool", "download"])
self.checkpermission(
# no permission (even with forcerelay)
["-whitelist=@127.0.0.1", "-whitelistforcerelay=1"],
- [],
- False)
+ [])
self.checkpermission(
# relay permission removed (no specific permissions)
["-whitelist=127.0.0.1", "-whitelistrelay=0"],
- ["noban", "mempool", "download"],
- True)
+ ["noban", "mempool", "download"])
self.checkpermission(
# forcerelay and relay permission added
# Legacy parameter interaction which set whitelistrelay to true
# if whitelistforcerelay is true
["-whitelist=127.0.0.1", "-whitelistforcerelay"],
- ["forcerelay", "relay", "noban", "mempool", "download"],
- True)
+ ["forcerelay", "relay", "noban", "mempool", "download"])
# Let's make sure permissions are merged correctly
# For this, we need to use whitebind instead of bind
@@ -76,39 +65,28 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.checkpermission(
["-whitelist=noban@127.0.0.1"],
# Check parameter interaction forcerelay should activate relay
- ["noban", "bloomfilter", "forcerelay", "relay", "download"],
- False)
+ ["noban", "bloomfilter", "forcerelay", "relay", "download"])
self.replaceinconfig(1, "whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1")
self.checkpermission(
# legacy whitelistrelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"],
- ["noban", "mempool", "download"],
- False)
-
- self.checkpermission(
- # check without deprecatedrpc=whitelisted
- ["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"],
- ["noban", "mempool", "download"],
- None)
+ ["noban", "mempool", "download"])
self.checkpermission(
# legacy whitelistforcerelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"],
- ["noban", "mempool", "download"],
- False)
+ ["noban", "mempool", "download"])
self.checkpermission(
# missing mempool permission to be considered legacy whitelisted
["-whitelist=noban@127.0.0.1"],
- ["noban", "download"],
- False)
+ ["noban", "download"])
self.checkpermission(
# all permission added
["-whitelist=all@127.0.0.1"],
- ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download", "addr"],
- False)
+ ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download", "addr"])
self.stop_node(1)
self.nodes[1].assert_start_raises_init_error(["-whitelist=oopsie@127.0.0.1"], "Invalid P2P permission", match=ErrorMatch.PARTIAL_REGEX)
@@ -169,19 +147,13 @@ class P2PPermissionsTests(BitcoinTestFramework):
reject_reason='Not relaying non-mempool transaction {} from forcerelay peer=0'.format(txid)
)
- def checkpermission(self, args, expectedPermissions, whitelisted):
- if whitelisted is not None:
- args = [*args, '-deprecatedrpc=whitelisted']
+ def checkpermission(self, args, expectedPermissions):
self.restart_node(1, args)
self.connect_nodes(0, 1)
peerinfo = self.nodes[1].getpeerinfo()[0]
- if whitelisted is None:
- assert 'whitelisted' not in peerinfo
- else:
- assert_equal(peerinfo['whitelisted'], whitelisted)
assert_equal(len(expectedPermissions), len(peerinfo['permissions']))
for p in expectedPermissions:
- if not p in peerinfo['permissions']:
+ if p not in peerinfo['permissions']:
raise AssertionError("Expected permissions %r is not granted." % p)
def replaceinconfig(self, nodeid, old, new):
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index a9d8b12d70..54891b07e1 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -686,13 +686,35 @@ class SegWitTest(BitcoinTestFramework):
if not self.segwit_active:
# Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed
# in blocks and the tx is impossible to mine right now.
- assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True, 'vsize': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}])
+ assert_equal(
+ self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]),
+ [{
+ 'txid': tx3.hash,
+ 'wtxid': tx3.getwtxid(),
+ 'allowed': True,
+ 'vsize': tx3.get_vsize(),
+ 'fees': {
+ 'base': Decimal('0.00001000'),
+ },
+ }],
+ )
# Create the same output as tx3, but by replacing tx
tx3_out = tx3.vout[0]
tx3 = tx
tx3.vout = [tx3_out]
tx3.rehash()
- assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True, 'vsize': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00011000')}}])
+ assert_equal(
+ self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]),
+ [{
+ 'txid': tx3.hash,
+ 'wtxid': tx3.getwtxid(),
+ 'allowed': True,
+ 'vsize': tx3.get_vsize(),
+ 'fees': {
+ 'base': Decimal('0.00011000'),
+ },
+ }],
+ )
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
self.nodes[0].generate(1)
diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py
index 47832b04bf..a7e240dcfa 100755
--- a/test/functional/p2p_timeouts.py
+++ b/test/functional/p2p_timeouts.py
@@ -74,9 +74,9 @@ class TimeoutsTest(BitcoinTestFramework):
no_version_node.send_message(msg_ping())
expected_timeout_logs = [
- "version handshake timeout from 0",
- "socket no message in first 3 seconds, 1 0 from 1",
- "socket no message in first 3 seconds, 0 0 from 2",
+ "version handshake timeout peer=0",
+ "socket no message in first 3 seconds, 1 0 peer=1",
+ "socket no message in first 3 seconds, 0 0 peer=2",
]
with self.nodes[0].assert_debug_log(expected_msgs=expected_timeout_logs):
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index f965677408..99be6b7b8e 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -20,6 +20,7 @@ Tests correspond to code in rpc/blockchain.cpp.
from decimal import Decimal
import http.client
+import os
import subprocess
from test_framework.blocktools import (
@@ -42,7 +43,9 @@ from test_framework.util import (
assert_raises_rpc_error,
assert_is_hex_string,
assert_is_hash_string,
+ get_datadir_path,
)
+from test_framework.wallet import MiniWallet
class BlockchainTest(BitcoinTestFramework):
@@ -63,6 +66,7 @@ class BlockchainTest(BitcoinTestFramework):
self._test_getnetworkhashps()
self._test_stopatheight()
self._test_waitforblockheight()
+ self._test_getblock()
assert self.nodes[0].verifychain(4, 0)
def mine_chain(self):
@@ -364,6 +368,46 @@ class BlockchainTest(BitcoinTestFramework):
assert_waitforheight(current_height)
assert_waitforheight(current_height + 1)
+ def _test_getblock(self):
+ node = self.nodes[0]
+
+ miniwallet = MiniWallet(node)
+ miniwallet.generate(5)
+ node.generate(100)
+
+ fee_per_byte = Decimal('0.00000010')
+ fee_per_kb = 1000 * fee_per_byte
+
+ miniwallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
+ blockhash = node.generate(1)[0]
+
+ self.log.info("Test that getblock with verbosity 1 doesn't include fee")
+ block = node.getblock(blockhash, 1)
+ assert 'fee' not in block['tx'][1]
+
+ self.log.info('Test that getblock with verbosity 2 includes expected fee')
+ block = node.getblock(blockhash, 2)
+ tx = block['tx'][1]
+ assert 'fee' in tx
+ assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)
+
+ self.log.info("Test that getblock with verbosity 2 still works with pruned Undo data")
+ datadir = get_datadir_path(self.options.tmpdir, 0)
+
+ def move_block_file(old, new):
+ old_path = os.path.join(datadir, self.chain, 'blocks', old)
+ new_path = os.path.join(datadir, self.chain, 'blocks', new)
+ os.rename(old_path, new_path)
+
+ # Move instead of deleting so we can restore chain state afterwards
+ move_block_file('rev00000.dat', 'rev_wrong')
+
+ block = node.getblock(blockhash, 2)
+ assert 'fee' not in block['tx'][1]
+
+ # Restore chain state
+ move_block_file('rev_wrong', 'rev00000.dat')
+
if __name__ == '__main__':
BlockchainTest().main()
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index f19c60dc36..31baeba582 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 multisig RPCs"""
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index adcd8a7d4c..1af79b9f7c 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -1,10 +1,9 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 deprecation of RPC calls."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_raises_rpc_error, find_vout_for_address
class DeprecatedRpcTest(BitcoinTestFramework):
def set_test_params(self):
@@ -24,37 +23,7 @@ class DeprecatedRpcTest(BitcoinTestFramework):
# assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].rpc.generate, 1)
# self.nodes[1].generate(1)
- if self.is_wallet_compiled():
- self.log.info("Test bumpfee RPC")
- self.nodes[0].generate(101)
- self.nodes[0].createwallet(wallet_name='nopriv', disable_private_keys=True)
- noprivs0 = self.nodes[0].get_wallet_rpc('nopriv')
- w0 = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
- self.nodes[1].createwallet(wallet_name='nopriv', disable_private_keys=True)
- noprivs1 = self.nodes[1].get_wallet_rpc('nopriv')
-
- address = w0.getnewaddress()
- desc = w0.getaddressinfo(address)['desc']
- change_addr = w0.getrawchangeaddress()
- change_desc = w0.getaddressinfo(change_addr)['desc']
- txid = w0.sendtoaddress(address=address, amount=10)
- vout = find_vout_for_address(w0, txid, address)
- self.nodes[0].generate(1)
- rawtx = w0.createrawtransaction([{'txid': txid, 'vout': vout}], {w0.getnewaddress(): 5}, 0, True)
- rawtx = w0.fundrawtransaction(rawtx, {'changeAddress': change_addr})
- signed_tx = w0.signrawtransactionwithwallet(rawtx['hex'])['hex']
-
- noprivs0.importmulti([{'desc': desc, 'timestamp': 0}, {'desc': change_desc, 'timestamp': 0, 'internal': True}])
- noprivs1.importmulti([{'desc': desc, 'timestamp': 0}, {'desc': change_desc, 'timestamp': 0, 'internal': True}])
-
- txid = w0.sendrawtransaction(signed_tx)
- self.sync_all()
-
- assert_raises_rpc_error(-32, 'Using bumpfee with wallets that have private keys disabled is deprecated. Use psbtbumpfee instead or restart bitcoind with -deprecatedrpc=bumpfee. This functionality will be removed in 0.22', noprivs0.bumpfee, txid)
- bumped_psbt = noprivs1.bumpfee(txid)
- assert 'psbt' in bumped_psbt
- else:
- self.log.info("No tested deprecated RPC methods")
+ self.log.info("No tested deprecated RPC methods")
if __name__ == '__main__':
DeprecatedRpcTest().main()
diff --git a/test/functional/rpc_getblockfilter.py b/test/functional/rpc_getblockfilter.py
index c3c3622cf9..044dbd35bf 100755
--- a/test/functional/rpc_getblockfilter.py
+++ b/test/functional/rpc_getblockfilter.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# Copyright (c) 2018-2020 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 getblockfilter RPC."""
diff --git a/test/functional/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py
index ea064f9763..563f54c5e7 100755
--- a/test/functional/rpc_getdescriptorinfo.py
+++ b/test/functional/rpc_getdescriptorinfo.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 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 getdescriptorinfo RPC.
diff --git a/test/functional/rpc_getpeerinfo_deprecation.py b/test/functional/rpc_getpeerinfo_deprecation.py
deleted file mode 100755
index 340a66e12f..0000000000
--- a/test/functional/rpc_getpeerinfo_deprecation.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2020 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 deprecation of getpeerinfo RPC fields."""
-
-from test_framework.test_framework import BitcoinTestFramework
-
-
-class GetpeerinfoDeprecationTest(BitcoinTestFramework):
- def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [[], ["-deprecatedrpc=banscore"]]
-
- def run_test(self):
- self.test_banscore_deprecation()
- self.test_addnode_deprecation()
-
- def test_banscore_deprecation(self):
- self.log.info("Test getpeerinfo by default no longer returns a banscore field")
- assert "banscore" not in self.nodes[0].getpeerinfo()[0].keys()
-
- self.log.info("Test getpeerinfo returns banscore with -deprecatedrpc=banscore")
- assert "banscore" in self.nodes[1].getpeerinfo()[0].keys()
-
- def test_addnode_deprecation(self):
- self.restart_node(1, ["-deprecatedrpc=getpeerinfo_addnode"])
- self.connect_nodes(0, 1)
-
- self.log.info("Test getpeerinfo by default no longer returns an addnode field")
- assert "addnode" not in self.nodes[0].getpeerinfo()[0].keys()
-
- self.log.info("Test getpeerinfo returns addnode with -deprecatedrpc=addnode")
- assert "addnode" in self.nodes[1].getpeerinfo()[0].keys()
-
-
-if __name__ == "__main__":
- GetpeerinfoDeprecationTest().main()
diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py
index 9b981b864e..1eefd109f8 100755
--- a/test/functional/rpc_help.py
+++ b/test/functional/rpc_help.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 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 RPC help output."""
@@ -7,7 +7,39 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
+from collections import defaultdict
import os
+import re
+
+
+def parse_string(s):
+ assert s[0] == '"'
+ assert s[-1] == '"'
+ return s[1:-1]
+
+
+def process_mapping(fname):
+ """Find and parse conversion table in implementation file `fname`."""
+ cmds = []
+ in_rpcs = False
+ with open(fname, "r", encoding="utf8") as f:
+ for line in f:
+ line = line.rstrip()
+ if not in_rpcs:
+ if line == 'static const CRPCConvertParam vRPCConvertParams[] =':
+ in_rpcs = True
+ else:
+ if line.startswith('};'):
+ in_rpcs = False
+ elif '{' in line and '"' in line:
+ m = re.search(r'{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *},', line)
+ assert m, 'No match to table expression: %s' % line
+ name = parse_string(m.group(1))
+ idx = int(m.group(2))
+ argname = parse_string(m.group(3))
+ cmds.append((name, idx, argname))
+ assert not in_rpcs and cmds
+ return cmds
class HelpRpcTest(BitcoinTestFramework):
@@ -16,11 +48,43 @@ class HelpRpcTest(BitcoinTestFramework):
self.supports_cli = False
def run_test(self):
+ self.test_client_conversion_table()
self.test_categories()
self.dump_help()
if self.is_wallet_compiled():
self.wallet_help()
+ def test_client_conversion_table(self):
+ file_conversion_table = os.path.join(self.config["environment"]["SRCDIR"], 'src', 'rpc', 'client.cpp')
+ mapping_client = process_mapping(file_conversion_table)
+ # Ignore echojson in client table
+ mapping_client = [m for m in mapping_client if m[0] != 'echojson']
+
+ mapping_server = self.nodes[0].help("dump_all_command_conversions")
+ # Filter all RPCs whether they need conversion
+ mapping_server_conversion = [tuple(m[:3]) for m in mapping_server if not m[3]]
+
+ # Only check if all RPC methods have been compiled (i.e. wallet is enabled)
+ if self.is_wallet_compiled() and sorted(mapping_client) != sorted(mapping_server_conversion):
+ raise AssertionError("RPC client conversion table ({}) and RPC server named arguments mismatch!\n{}".format(
+ file_conversion_table,
+ set(mapping_client).symmetric_difference(mapping_server_conversion),
+ ))
+
+ # Check for conversion difference by argument name.
+ # It is preferable for API consistency that arguments with the same name
+ # have the same conversion, so bin by argument name.
+ all_methods_by_argname = defaultdict(list)
+ converts_by_argname = defaultdict(list)
+ for m in mapping_server:
+ all_methods_by_argname[m[2]].append(m[0])
+ converts_by_argname[m[2]].append(m[3])
+
+ for argname, convert in converts_by_argname.items():
+ if all(convert) != any(convert):
+ # Only allow dummy to fail consistency check
+ assert argname == 'dummy', ('WARNING: conversion mismatch for argument named %s (%s)' % (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
+
def test_categories(self):
node = self.nodes[0]
diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py
new file mode 100755
index 0000000000..469d6bdb05
--- /dev/null
+++ b/test/functional/rpc_invalid_address_message.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3
+# Copyright (c) 2020 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 error messages for 'getaddressinfo' and 'validateaddress' RPC commands."""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+BECH32_VALID = 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv'
+BECH32_INVALID_SIZE = 'bcrt1sqqpl9r5c'
+BECH32_INVALID_PREFIX = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
+
+BASE58_VALID = 'mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn'
+BASE58_INVALID_PREFIX = '17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem'
+
+INVALID_ADDRESS = 'asfah14i8fajz0123f'
+
+class InvalidAddressErrorMessageTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def test_validateaddress(self):
+ node = self.nodes[0]
+
+ # Bech32
+ info = node.validateaddress(BECH32_INVALID_SIZE)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid Bech32 address data size')
+
+ info = node.validateaddress(BECH32_INVALID_PREFIX)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid prefix for Bech32 address')
+
+ info = node.validateaddress(BECH32_VALID)
+ assert info['isvalid']
+ assert 'error' not in info
+
+ # Base58
+ info = node.validateaddress(BASE58_INVALID_PREFIX)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid prefix for Base58-encoded address')
+
+ info = node.validateaddress(BASE58_VALID)
+ assert info['isvalid']
+ assert 'error' not in info
+
+ # Invalid address format
+ info = node.validateaddress(INVALID_ADDRESS)
+ assert not info['isvalid']
+ assert_equal(info['error'], 'Invalid address format')
+
+ def test_getaddressinfo(self):
+ node = self.nodes[0]
+
+ assert_raises_rpc_error(-5, "Invalid Bech32 address data size", node.getaddressinfo, BECH32_INVALID_SIZE)
+
+ assert_raises_rpc_error(-5, "Invalid prefix for Bech32 address", node.getaddressinfo, BECH32_INVALID_PREFIX)
+
+ assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", node.getaddressinfo, BASE58_INVALID_PREFIX)
+
+ assert_raises_rpc_error(-5, "Invalid address format", node.getaddressinfo, INVALID_ADDRESS)
+
+ def run_test(self):
+ self.test_validateaddress()
+ self.test_getaddressinfo()
+
+
+if __name__ == '__main__':
+ InvalidAddressErrorMessageTest().main()
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index f884b8d293..114bd5e7e9 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 invalidateblock RPC."""
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index 0493ceeb64..1398d1237f 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 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 RPC misc output."""
diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py
index 2efd090733..de0b7f303f 100755
--- a/test/functional/rpc_net.py
+++ b/test/functional/rpc_net.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 RPC calls related to net.
diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py
index 04d55b103f..7d3a5cc9ce 100755
--- a/test/functional/rpc_preciousblock.py
+++ b/test/functional/rpc_preciousblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 preciousblock RPC."""
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 60e66a27c9..86c7b3fbcc 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 rawtransaction RPCs.
diff --git a/test/functional/rpc_setban.py b/test/functional/rpc_setban.py
index bc48449084..fd5f8aa098 100755
--- a/test/functional/rpc_setban.py
+++ b/test/functional/rpc_setban.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 setban rpc call."""
@@ -15,6 +15,9 @@ class SetBanTests(BitcoinTestFramework):
self.setup_clean_chain = True
self.extra_args = [[],[]]
+ def is_banned(self, node, addr):
+ return any(e['address'] == addr for e in node.listbanned())
+
def run_test(self):
# Node 0 connects to Node 1, check that the noban permission is not granted
self.connect_nodes(0, 1)
@@ -42,5 +45,18 @@ class SetBanTests(BitcoinTestFramework):
peerinfo = self.nodes[1].getpeerinfo()[0]
assert(not 'noban' in peerinfo['permissions'])
+ self.log.info("Test that a non-IP address can be banned/unbanned")
+ node = self.nodes[1]
+ tor_addr = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"
+ ip_addr = "1.2.3.4"
+ assert(not self.is_banned(node, tor_addr))
+ assert(not self.is_banned(node, ip_addr))
+ node.setban(tor_addr, "add")
+ assert(self.is_banned(node, tor_addr))
+ assert(not self.is_banned(node, ip_addr))
+ node.setban(tor_addr, "remove")
+ assert(not self.is_banned(self.nodes[1], tor_addr))
+ assert(not self.is_banned(node, ip_addr))
+
if __name__ == '__main__':
SetBanTests().main()
diff --git a/test/functional/rpc_txoutproof.py b/test/functional/rpc_txoutproof.py
index 2d6ce77613..528da0cbfc 100755
--- a/test/functional/rpc_txoutproof.py
+++ b/test/functional/rpc_txoutproof.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 gettxoutproof and verifytxoutproof RPCs."""
diff --git a/test/functional/rpc_users.py b/test/functional/rpc_users.py
index 108af2cac8..7cedb4336b 100755
--- a/test/functional/rpc_users.py
+++ b/test/functional/rpc_users.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 multiple RPC users."""
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 6b7214f03a..e691b63df6 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Utilities for manipulating blocks and transactions."""
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index f3d13c049b..e0cbab45ce 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -27,7 +27,7 @@ def xor_bytes(b0, b1):
def jacobi_symbol(n, k):
"""Compute the Jacobi symbol of n modulo k
- See http://en.wikipedia.org/wiki/Jacobi_symbol
+ See https://en.wikipedia.org/wiki/Jacobi_symbol
For our application k is always prime, so this is the same as the Legendre symbol."""
assert k > 0 and k & 1, "jacobi symbol is only defined for positive odd k"
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index bab4ad0008..6ad4e13db2 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -564,6 +564,9 @@ class CTransaction:
def serialize(self):
return self.serialize_with_witness()
+ def getwtxid(self):
+ return hash256(self.serialize())[::-1].hex()
+
# Recalculate the txid (transaction hash without witness)
def rehash(self):
self.sha256 = None
@@ -579,7 +582,7 @@ class CTransaction:
if self.sha256 is None:
self.sha256 = uint256_from_str(hash256(self.serialize_without_witness()))
- self.hash = encode(hash256(self.serialize_without_witness())[::-1], 'hex_codec').decode('ascii')
+ self.hash = hash256(self.serialize_without_witness())[::-1].hex()
def is_valid(self):
self.calc_sha256()
diff --git a/test/functional/test_framework/muhash.py b/test/functional/test_framework/muhash.py
index 97d02359cb..183548f71f 100644
--- a/test/functional/test_framework/muhash.py
+++ b/test/functional/test_framework/muhash.py
@@ -78,11 +78,13 @@ class MuHash3072:
def insert(self, data):
"""Insert a byte array data in the set."""
- self.numerator = (self.numerator * data_to_num3072(data)) % self.MODULUS
+ data_hash = hashlib.sha256(data).digest()
+ self.numerator = (self.numerator * data_to_num3072(data_hash)) % self.MODULUS
def remove(self, data):
"""Remove a byte array from the set."""
- self.denominator = (self.denominator * data_to_num3072(data)) % self.MODULUS
+ data_hash = hashlib.sha256(data).digest()
+ self.denominator = (self.denominator * data_to_num3072(data_hash)) % self.MODULUS
def digest(self):
"""Extract the final hash. Does not modify this object."""
@@ -93,12 +95,12 @@ class MuHash3072:
class TestFrameworkMuhash(unittest.TestCase):
def test_muhash(self):
muhash = MuHash3072()
- muhash.insert([0]*32)
- muhash.insert([1] + [0]*31)
- muhash.remove([2] + [0]*31)
+ muhash.insert(b'\x00' * 32)
+ muhash.insert((b'\x01' + b'\x00' * 31))
+ muhash.remove((b'\x02' + b'\x00' * 31))
finalized = muhash.digest()
# This mirrors the result in the C++ MuHash3072 unit test
- self.assertEqual(finalized[::-1].hex(), "a44e16d5e34d259b349af21c06e65d653915d2e208e4e03f389af750dc0bfdc3")
+ self.assertEqual(finalized[::-1].hex(), "10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")
def test_chacha20(self):
def chacha_check(key, result):
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index c98424e8e2..e047e7fa14 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -84,7 +84,7 @@ def get_bind_addrs(pid):
bind_addrs.append(conn[1])
return bind_addrs
-# from: http://code.activestate.com/recipes/439093/
+# from: https://code.activestate.com/recipes/439093/
def all_interfaces():
'''
Return all interfaces that are up
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index ea769ddfa2..fa4a567aac 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -71,7 +71,11 @@ from test_framework.messages import (
NODE_WITNESS,
sha256,
)
-from test_framework.util import wait_until_helper
+from test_framework.util import (
+ MAX_NODES,
+ p2p_port,
+ wait_until_helper,
+)
logger = logging.getLogger("TestFramework.p2p")
@@ -139,7 +143,7 @@ class P2PConnection(asyncio.Protocol):
def is_connected(self):
return self._transport is not None
- def peer_connect(self, dstaddr, dstport, *, net, timeout_factor):
+ def peer_connect_helper(self, dstaddr, dstport, net, timeout_factor):
assert not self.is_connected
self.timeout_factor = timeout_factor
self.dstaddr = dstaddr
@@ -148,12 +152,20 @@ class P2PConnection(asyncio.Protocol):
self.on_connection_send_msg = None
self.recvbuf = b""
self.magic_bytes = MAGIC_BYTES[net]
- logger.debug('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport))
+
+ def peer_connect(self, dstaddr, dstport, *, net, timeout_factor):
+ self.peer_connect_helper(dstaddr, dstport, net, timeout_factor)
loop = NetworkThread.network_event_loop
- conn_gen_unsafe = loop.create_connection(lambda: self, host=self.dstaddr, port=self.dstport)
- conn_gen = lambda: loop.call_soon_threadsafe(loop.create_task, conn_gen_unsafe)
- return conn_gen
+ logger.debug('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport))
+ coroutine = loop.create_connection(lambda: self, host=self.dstaddr, port=self.dstport)
+ return lambda: loop.call_soon_threadsafe(loop.create_task, coroutine)
+
+ def peer_accept_connection(self, connect_id, connect_cb=lambda: None, *, net, timeout_factor):
+ self.peer_connect_helper('0', 0, net, timeout_factor)
+
+ logger.debug('Listening for Bitcoin Node with id: {}'.format(connect_id))
+ return lambda: NetworkThread.listen(self, connect_cb, idx=connect_id)
def peer_disconnect(self):
# Connection could have already been closed by other end.
@@ -312,18 +324,27 @@ class P2PInterface(P2PConnection):
# If the peer supports wtxid-relay
self.wtxidrelay = wtxidrelay
- def peer_connect(self, *args, services=NODE_NETWORK|NODE_WITNESS, send_version=True, **kwargs):
+ def peer_connect_send_version(self, services):
+ # Send a version msg
+ vt = msg_version()
+ vt.nServices = services
+ vt.addrTo.ip = self.dstaddr
+ vt.addrTo.port = self.dstport
+ vt.addrFrom.ip = "0.0.0.0"
+ vt.addrFrom.port = 0
+ self.on_connection_send_msg = vt # Will be sent in connection_made callback
+
+ def peer_connect(self, *args, services=NODE_NETWORK | NODE_WITNESS, send_version=True, **kwargs):
create_conn = super().peer_connect(*args, **kwargs)
if send_version:
- # Send a version msg
- vt = msg_version()
- vt.nServices = services
- vt.addrTo.ip = self.dstaddr
- vt.addrTo.port = self.dstport
- vt.addrFrom.ip = "0.0.0.0"
- vt.addrFrom.port = 0
- self.on_connection_send_msg = vt # Will be sent soon after connection_made
+ self.peer_connect_send_version(services)
+
+ return create_conn
+
+ def peer_accept_connection(self, *args, services=NODE_NETWORK | NODE_WITNESS, **kwargs):
+ create_conn = super().peer_accept_connection(*args, **kwargs)
+ self.peer_connect_send_version(services)
return create_conn
@@ -414,6 +435,10 @@ class P2PInterface(P2PConnection):
wait_until_helper(test_function, timeout=timeout, lock=p2p_lock, timeout_factor=self.timeout_factor)
+ def wait_for_connect(self, timeout=60):
+ test_function = lambda: self.is_connected
+ wait_until_helper(test_function, timeout=timeout, lock=p2p_lock)
+
def wait_for_disconnect(self, timeout=60):
test_function = lambda: not self.is_connected
self.wait_until(test_function, timeout=timeout, check_connected=False)
@@ -527,6 +552,8 @@ class NetworkThread(threading.Thread):
# There is only one event loop and no more than one thread must be created
assert not self.network_event_loop
+ NetworkThread.listeners = {}
+ NetworkThread.protos = {}
NetworkThread.network_event_loop = asyncio.new_event_loop()
def run(self):
@@ -542,6 +569,48 @@ class NetworkThread(threading.Thread):
# Safe to remove event loop.
NetworkThread.network_event_loop = None
+ @classmethod
+ def listen(cls, p2p, callback, port=None, addr=None, idx=1):
+ """ Ensure a listening server is running on the given port, and run the
+ protocol specified by `p2p` on the next connection to it. Once ready
+ for connections, call `callback`."""
+
+ if port is None:
+ assert 0 < idx <= MAX_NODES
+ port = p2p_port(MAX_NODES - idx)
+ if addr is None:
+ addr = '127.0.0.1'
+
+ coroutine = cls.create_listen_server(addr, port, callback, p2p)
+ cls.network_event_loop.call_soon_threadsafe(cls.network_event_loop.create_task, coroutine)
+
+ @classmethod
+ async def create_listen_server(cls, addr, port, callback, proto):
+ def peer_protocol():
+ """Returns a function that does the protocol handling for a new
+ connection. To allow different connections to have different
+ behaviors, the protocol function is first put in the cls.protos
+ dict. When the connection is made, the function removes the
+ protocol function from that dict, and returns it so the event loop
+ can start executing it."""
+ response = cls.protos.get((addr, port))
+ cls.protos[(addr, port)] = None
+ return response
+
+ if (addr, port) not in cls.listeners:
+ # When creating a listener on a given (addr, port) we only need to
+ # do it once. If we want different behaviors for different
+ # connections, we can accomplish this by providing different
+ # `proto` functions
+
+ listener = await cls.network_event_loop.create_server(peer_protocol, addr, port)
+ logger.debug("Listening server on %s:%d should be started" % (addr, port))
+ cls.listeners[(addr, port)] = listener
+
+ cls.protos[(addr, port)] = proto
+ callback(addr, port)
+
+
class P2PDataStore(P2PInterface):
"""A P2P data store class.
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 26ccab3039..be0e9f24e2 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -787,7 +787,7 @@ def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpa
def taproot_tree_helper(scripts):
if len(scripts) == 0:
- return ([], bytes(0 for _ in range(32)))
+ return ([], bytes())
if len(scripts) == 1:
# One entry: treat as a leaf
script = scripts[0]
diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py
index 318a438705..457be6b0e6 100755
--- a/test/functional/test_framework/script_util.py
+++ b/test/functional/test_framework/script_util.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Useful Script constants and utils."""
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index bf047c5f68..7c5317480c 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Base class for RPC testing."""
@@ -332,7 +332,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Methods to override in subclass test scripts.
def set_test_params(self):
- """Tests must this method to change default values for number of nodes, topology, etc"""
+ """Tests must override this method to change default values for number of nodes, topology, etc"""
raise NotImplementedError
def add_options(self, parser):
@@ -517,13 +517,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def stop_node(self, i, expected_stderr='', wait=0):
"""Stop a bitcoind test node"""
self.nodes[i].stop_node(expected_stderr, wait=wait)
- self.nodes[i].wait_until_stopped()
def stop_nodes(self, wait=0):
"""Stop multiple bitcoind test nodes"""
for node in self.nodes:
# Issue RPC to stop nodes
- node.stop_node(wait=wait)
+ node.stop_node(wait=wait, wait_until_stopped=False)
for node in self.nodes:
# Wait for nodes to stop
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index a618706a77..b61d433652 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -71,6 +71,7 @@ class TestNode():
"""
self.index = i
+ self.p2p_conn_index = 1
self.datadir = datadir
self.bitcoinconf = os.path.join(self.datadir, "bitcoin.conf")
self.stdout_dir = os.path.join(self.datadir, "stdout")
@@ -308,7 +309,7 @@ class TestNode():
def version_is_at_least(self, ver):
return self.version is None or self.version >= ver
- def stop_node(self, expected_stderr='', wait=0):
+ def stop_node(self, expected_stderr='', *, wait=0, wait_until_stopped=True):
"""Stop the node."""
if not self.running:
return
@@ -337,6 +338,9 @@ class TestNode():
del self.p2ps[:]
+ if wait_until_stopped:
+ self.wait_until_stopped()
+
def is_node_stopped(self):
"""Checks whether the node has stopped.
@@ -514,7 +518,7 @@ class TestNode():
self._raise_assertion_error(assert_msg)
def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):
- """Add a p2p connection to the node.
+ """Add an inbound p2p connection to the node.
This method adds the p2p connection to the self.p2ps list and also
returns the connection to the caller."""
@@ -543,6 +547,29 @@ class TestNode():
return p2p_conn
+ def add_outbound_p2p_connection(self, p2p_conn, *, p2p_idx, connection_type="outbound-full-relay", **kwargs):
+ """Add an outbound p2p connection from node. Either
+ full-relay("outbound-full-relay") or
+ block-relay-only("block-relay-only") connection.
+
+ This method adds the p2p connection to the self.p2ps list and returns
+ the connection to the caller.
+ """
+
+ def addconnection_callback(address, port):
+ self.log.debug("Connecting to %s:%d %s" % (address, port, connection_type))
+ self.addconnection('%s:%d' % (address, port), connection_type)
+
+ p2p_conn.peer_accept_connection(connect_cb=addconnection_callback, connect_id=p2p_idx + 1, net=self.chain, timeout_factor=self.timeout_factor, **kwargs)()
+
+ p2p_conn.wait_for_connect()
+ self.p2ps.append(p2p_conn)
+
+ p2p_conn.wait_for_verack()
+ p2p_conn.sync_with_ping()
+
+ return p2p_conn
+
def num_test_p2p_connections(self):
"""Return number of test framework p2p connections to the node."""
return len([peer for peer in self.getpeerinfo() if peer['subver'] == MY_SUBVERSION.decode("utf-8")])
@@ -552,6 +579,7 @@ class TestNode():
for p in self.p2ps:
p.peer_disconnect()
del self.p2ps[:]
+
wait_until_helper(lambda: self.num_test_p2p_connections() == 0, timeout_factor=self.timeout_factor)
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 62ff5c6e33..123c48852c 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -342,16 +342,25 @@ def initialize_datadir(dirname, n, chain):
datadir = get_datadir_path(dirname, n)
if not os.path.isdir(datadir):
os.makedirs(datadir)
- # Translate chain name to config name
+ write_config(os.path.join(datadir, "bitcoin.conf"), n=n, chain=chain)
+ os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
+ os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
+ return datadir
+
+
+def write_config(config_path, *, n, chain, extra_config=""):
+ # Translate chain subdirectory name to config name
if chain == 'testnet3':
chain_name_conf_arg = 'testnet'
chain_name_conf_section = 'test'
else:
chain_name_conf_arg = chain
chain_name_conf_section = chain
- with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
- f.write("{}=1\n".format(chain_name_conf_arg))
- f.write("[{}]\n".format(chain_name_conf_section))
+ with open(config_path, 'w', encoding='utf8') as f:
+ if chain_name_conf_arg:
+ f.write("{}=1\n".format(chain_name_conf_arg))
+ if chain_name_conf_section:
+ f.write("[{}]\n".format(chain_name_conf_section))
f.write("port=" + str(p2p_port(n)) + "\n")
f.write("rpcport=" + str(rpc_port(n)) + "\n")
f.write("fallbackfee=0.0002\n")
@@ -362,10 +371,9 @@ def initialize_datadir(dirname, n, chain):
f.write("listenonion=0\n")
f.write("printtoconsole=0\n")
f.write("upnp=0\n")
+ f.write("natpmp=0\n")
f.write("shrinkdebugfile=0\n")
- os.makedirs(os.path.join(datadir, 'stderr'), exist_ok=True)
- os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
- return datadir
+ f.write(extra_config)
def get_datadir_path(dirname, n):
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index a71f2c69cb..edd7792608 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -71,9 +71,9 @@ class MiniWallet:
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
tx_hex = tx.serialize().hex()
- txid = from_node.sendrawtransaction(tx_hex)
- self._utxos.append({'txid': txid, 'vout': 0, 'value': send_value})
- tx_info = from_node.getmempoolentry(txid)
+ tx_info = from_node.testmempoolaccept([tx_hex])[0]
+ self._utxos.append({'txid': tx_info['txid'], 'vout': 0, 'value': send_value})
+ from_node.sendrawtransaction(tx_hex)
assert_equal(tx_info['vsize'], vsize)
- assert_equal(tx_info['fee'], fee)
- return {'txid': txid, 'wtxid': tx_info['wtxid'], 'hex': tx_hex}
+ assert_equal(tx_info['fees']['base'], fee)
+ return {'txid': tx_info['txid'], 'wtxid': tx_info['wtxid'], 'hex': tx_hex}
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 5b3db282e1..c652ac0a06 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -134,6 +134,7 @@ BASE_SCRIPTS = [
'wallet_keypool_topup.py --descriptors',
'feature_fee_estimation.py',
'interface_zmq.py',
+ 'rpc_invalid_address_message.py',
'interface_bitcoin_cli.py',
'mempool_resurrect.py',
'wallet_txn_doublespend.py --mineblock',
@@ -237,6 +238,7 @@ BASE_SCRIPTS = [
'rpc_named_arguments.py',
'wallet_listsinceblock.py',
'wallet_listsinceblock.py --descriptors',
+ 'wallet_listdescriptors.py --descriptors',
'p2p_leak.py',
'wallet_encryption.py',
'wallet_encryption.py --descriptors',
@@ -261,6 +263,7 @@ BASE_SCRIPTS = [
'feature_filelock.py',
'feature_loadblock.py',
'p2p_dos_header_tree.py',
+ 'p2p_add_connections.py',
'p2p_unrequested_blocks.py',
'p2p_blockfilters.py',
'feature_includeconf.py',
@@ -279,7 +282,6 @@ BASE_SCRIPTS = [
'feature_config_args.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
- 'rpc_getpeerinfo_deprecation.py',
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 1093982929..8a1af24dcf 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -31,7 +31,7 @@ class ToolWalletTest(BitcoinTestFramework):
def bitcoin_wallet_process(self, *args):
binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"]
default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain]
- if self.options.descriptors:
+ if self.options.descriptors and 'create' in args:
default_args.append('-descriptors')
return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
@@ -344,11 +344,13 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_raises_tool_error('Dump file {} does not exist.'.format(non_exist_dump), '-wallet=todump', '-dumpfile={}'.format(non_exist_dump), 'createfromdump')
wallet_path = os.path.join(self.nodes[0].datadir, 'regtest/wallets/todump2')
self.assert_raises_tool_error('Failed to create database path \'{}\'. Database already exists.'.format(wallet_path), '-wallet=todump2', '-dumpfile={}'.format(wallet_dump), 'createfromdump')
+ self.assert_raises_tool_error("The -descriptors option can only be used with the 'create' command.", '-descriptors', '-wallet=todump2', '-dumpfile={}'.format(wallet_dump), 'createfromdump')
self.log.info('Checking createfromdump')
self.do_tool_createfromdump("load", "wallet.dump")
self.do_tool_createfromdump("load-bdb", "wallet.dump", "bdb")
- self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite")
+ if self.is_sqlite_compiled():
+ self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite")
self.log.info('Checking createfromdump handling of magic and versions')
bad_ver_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_ver1.dump")
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 3cbddaf6da..4a589f0393 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 wallet."""
@@ -586,7 +586,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
- assert_raises_rpc_error(-5, "Invalid address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
+ assert_raises_rpc_error(-5, "Invalid prefix for Base58-encoded address", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy")
address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ")
assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac")
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index c8c1f2e374..5fc8438e8f 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -425,6 +425,9 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
original_txid = watcher.sendrawtransaction(psbt_final["hex"])
assert_equal(len(watcher.decodepsbt(psbt)["tx"]["vin"]), 1)
+ # bumpfee can't be used on watchonly wallets
+ assert_raises_rpc_error(-4, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.", watcher.bumpfee, original_txid)
+
# Bump fee, obnoxiously high to add additional watchonly input
bumped_psbt = watcher.psbtbumpfee(original_txid, {"fee_rate": HIGH})
assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1)
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index 0f11aca525..a39a3c8d9b 100755
--- a/test/functional/wallet_create_tx.py
+++ b/test/functional/wallet_create_tx.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/functional/wallet_descriptor.py b/test/functional/wallet_descriptor.py
index 0fec8ea4a4..1de41a5f96 100755
--- a/test/functional/wallet_descriptor.py
+++ b/test/functional/wallet_descriptor.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 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 descriptor wallet function."""
diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py
index c2b30fb35b..78cf378642 100755
--- a/test/functional/wallet_disable.py
+++ b/test/functional/wallet_disable.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 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 a node with the -disablewallet option.
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index 4509c1e0b2..0d702e44f6 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2019 The Bitcoin Core developers
+# Copyright (c) 2016-2020 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 Wallet encryption"""
@@ -78,7 +78,7 @@ class WalletEncryptionTest(BitcoinTestFramework):
MAX_VALUE = 100000000
expected_time = int(time.time()) + MAX_VALUE - 600
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)
- # give buffer for walletpassphrase, since it iterates over all crypted keys
+ # give buffer for walletpassphrase, since it iterates over all encrypted keys
expected_time_with_buffer = time.time() + MAX_VALUE - 600
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time)
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index dbf853b35c..78eef4b790 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2018 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 wallet replace-by-fee capabilities in conjunction with the fallbackfee."""
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index aad112b499..59089456e9 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 wallet import RPCs.
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index 2903a84998..ed62ef0e9d 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 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 importdescriptors RPC.
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index 30206349ae..13186b9e1d 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 importmulti RPC.
diff --git a/test/functional/wallet_importprunedfunds.py b/test/functional/wallet_importprunedfunds.py
index d10d8ae1c8..7635ce2139 100755
--- a/test/functional/wallet_importprunedfunds.py
+++ b/test/functional/wallet_importprunedfunds.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 importprunedfunds and removeprunedfunds RPCs."""
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 51795aca23..3fe6adeebc 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 wallet keypool and interaction with wallet encryption/locking."""
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index 78e06c5916..5619d57947 100755
--- a/test/functional/wallet_keypool_topup.py
+++ b/test/functional/wallet_keypool_topup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 HD Wallet keypool restore function.
diff --git a/test/functional/wallet_listdescriptors.py b/test/functional/wallet_listdescriptors.py
new file mode 100755
index 0000000000..9f8c341bc7
--- /dev/null
+++ b/test/functional/wallet_listdescriptors.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2021 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 listdescriptors RPC."""
+
+from test_framework.descriptors import (
+ descsum_create
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+
+
+class ListDescriptorsTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+ self.skip_if_no_sqlite()
+
+ # do not create any wallet by default
+ def init_wallet(self, i):
+ return
+
+ def run_test(self):
+ node = self.nodes[0]
+ assert_raises_rpc_error(-18, 'No wallet is loaded.', node.listdescriptors)
+
+ self.log.info('Test that the command is not available for legacy wallets.')
+ node.createwallet(wallet_name='w1', descriptors=False)
+ assert_raises_rpc_error(-4, 'listdescriptors is not available for non-descriptor wallets', node.listdescriptors)
+
+ self.log.info('Test the command for empty descriptors wallet.')
+ node.createwallet(wallet_name='w2', blank=True, descriptors=True)
+ assert_equal(0, len(node.get_wallet_rpc('w2').listdescriptors()))
+
+ self.log.info('Test the command for a default descriptors wallet.')
+ node.createwallet(wallet_name='w3', descriptors=True)
+ result = node.get_wallet_rpc('w3').listdescriptors()
+ assert_equal(6, len(result))
+ assert_equal(6, len([d for d in result if d['active']]))
+ assert_equal(3, len([d for d in result if d['internal']]))
+ for item in result:
+ assert item['desc'] != ''
+ assert item['next'] == 0
+ assert item['range'] == [0, 0]
+ assert item['timestamp'] is not None
+
+ self.log.info('Test non-active non-range combo descriptor')
+ node.createwallet(wallet_name='w4', blank=True, descriptors=True)
+ wallet = node.get_wallet_rpc('w4')
+ wallet.importdescriptors([{
+ 'desc': descsum_create('combo(' + node.get_deterministic_priv_key().key + ')'),
+ 'timestamp': 1296688602,
+ }])
+ expected = [{'active': False,
+ 'desc': 'combo(0227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3f)#np574htj',
+ 'timestamp': 1296688602}]
+ assert_equal(expected, wallet.listdescriptors())
+
+
+if __name__ == '__main__':
+ ListDescriptorsTest().main()
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index 6a1b9097c5..448720530c 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 listsinceblock RPC."""
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 3e98208431..71573964de 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 listtransactions API."""
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index bb89e76a9a..bf24b9c7b3 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -304,12 +304,12 @@ class MultiWalletTest(BitcoinTestFramework):
if self.options.descriptors:
assert_raises_rpc_error(-4, "Wallet file verification failed. SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another bitcoind?", self.nodes[0].loadwallet, wallet_names[0])
else:
- assert_raises_rpc_error(-4, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, wallet_names[0])
+ assert_raises_rpc_error(-35, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, wallet_names[0])
# This tests the default wallet that BDB makes, so SQLite wallet doesn't need to test this
# Fail to load duplicate wallets by different ways (directory and filepath)
path = os.path.join(self.options.tmpdir, "node0", "regtest", "wallets", "wallet.dat")
- assert_raises_rpc_error(-4, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, 'wallet.dat')
+ assert_raises_rpc_error(-35, "Wallet file verification failed. Refusing to load database. Data file '{}' is already loaded.".format(path), self.nodes[0].loadwallet, 'wallet.dat')
# Only BDB doesn't open duplicate wallet files. SQLite does not have this limitation. While this may be desired in the future, it is not necessary
# Fail to load if one wallet is a copy of another
diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py
index a1d6b098ad..9a5866a361 100755
--- a/test/functional/wallet_reorgsrestore.py
+++ b/test/functional/wallet_reorgsrestore.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2019 The Bitcoin Core developers
+# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py
index d3119925f7..d96c2da686 100755
--- a/test/functional/wallet_startup.py
+++ b/test/functional/wallet_startup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 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 wallet load on startup.
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index bdbbb3e530..893a2d9617 100755
--- a/test/functional/wallet_txn_clone.py
+++ b/test/functional/wallet_txn_clone.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 wallet accounts properly when there are cloned transactions with malleated scriptsigs."""
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index 42de131354..c7f7a8546a 100755
--- a/test/functional/wallet_txn_doublespend.py
+++ b/test/functional/wallet_txn_doublespend.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2019 The Bitcoin Core developers
+# Copyright (c) 2014-2020 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 wallet accounts properly when there is a double-spend conflict."""
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 3a2cefbe2b..aa0aa11d15 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -14,6 +14,16 @@ import subprocess
import sys
+def get_fuzz_env(*, target, source_dir):
+ return {
+ 'FUZZ': target,
+ 'UBSAN_OPTIONS':
+ f'suppressions={source_dir}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1',
+ 'ASAN_OPTIONS': # symbolizer disabled due to https://github.com/google/sanitizers/issues/1364#issuecomment-761072085
+ 'symbolize=0:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1',
+ }
+
+
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
@@ -54,7 +64,7 @@ def main():
)
parser.add_argument(
'--m_dir',
- help='Merge inputs from this directory into the seed_dir. Needs /target subdirectory.',
+ help='Merge inputs from this directory into the seed_dir.',
)
parser.add_argument(
'-g',
@@ -129,9 +139,7 @@ def main():
os.path.join(config["environment"]["BUILDDIR"], 'src', 'test', 'fuzz', 'fuzz'),
'-help=1',
],
- env={
- 'FUZZ': test_list_selection[0]
- },
+ env=get_fuzz_env(target=test_list_selection[0], source_dir=config['environment']['SRCDIR']),
timeout=20,
check=True,
stderr=subprocess.PIPE,
@@ -148,6 +156,7 @@ def main():
if args.generate:
return generate_corpus_seeds(
fuzz_pool=fuzz_pool,
+ src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
seed_dir=args.seed_dir,
targets=test_list_selection,
@@ -158,6 +167,7 @@ def main():
fuzz_pool=fuzz_pool,
corpus=args.seed_dir,
test_list=test_list_selection,
+ src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
merge_dir=args.m_dir,
)
@@ -167,12 +177,13 @@ def main():
fuzz_pool=fuzz_pool,
corpus=args.seed_dir,
test_list=test_list_selection,
+ src_dir=config['environment']['SRCDIR'],
build_dir=config["environment"]["BUILDDIR"],
use_valgrind=args.valgrind,
)
-def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets):
+def generate_corpus_seeds(*, fuzz_pool, src_dir, build_dir, seed_dir, targets):
"""Generates new corpus seeds.
Run {targets} without input, and outputs the generated corpus seeds to
@@ -186,9 +197,7 @@ def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets):
' '.join(command),
subprocess.run(
command,
- env={
- 'FUZZ': t
- },
+ env=get_fuzz_env(target=t, source_dir=src_dir),
check=True,
stderr=subprocess.PIPE,
universal_newlines=True,
@@ -209,8 +218,8 @@ def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets):
future.result()
-def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir):
- logging.info("Merge the inputs in the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
+def merge_inputs(*, fuzz_pool, corpus, test_list, src_dir, build_dir, merge_dir):
+ logging.info("Merge the inputs from the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
jobs = []
for t in test_list:
args = [
@@ -227,9 +236,7 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir):
output = 'Run {} with args {}\n'.format(t, " ".join(args))
output += subprocess.run(
args,
- env={
- 'FUZZ': t
- },
+ env=get_fuzz_env(target=t, source_dir=src_dir),
check=True,
stderr=subprocess.PIPE,
universal_newlines=True,
@@ -242,7 +249,7 @@ def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir):
future.result()
-def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind):
+def run_once(*, fuzz_pool, corpus, test_list, src_dir, build_dir, use_valgrind):
jobs = []
for t in test_list:
corpus_path = os.path.join(corpus, t)
@@ -257,7 +264,12 @@ def run_once(*, fuzz_pool, corpus, test_list, build_dir, use_valgrind):
def job(t, args):
output = 'Run {} with args {}'.format(t, args)
- result = subprocess.run(args, env={'FUZZ': t}, stderr=subprocess.PIPE, universal_newlines=True)
+ result = subprocess.run(
+ args,
+ env=get_fuzz_env(target=t, source_dir=src_dir),
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
output += result.stderr
return output, result
diff --git a/test/get_previous_releases.py b/test/get_previous_releases.py
index 1348b8246b..b177fbb4b2 100755
--- a/test/get_previous_releases.py
+++ b/test/get_previous_releases.py
@@ -175,6 +175,7 @@ def check_host(args) -> int:
'./depends/config.guess').decode())
if args.download_binary:
platforms = {
+ 'aarch64-*-linux*': 'aarch64-linux-gnu',
'x86_64-*-linux*': 'x86_64-linux-gnu',
'x86_64-apple-darwin*': 'osx64',
}
diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py
index f77242d335..feaebc68e9 100755
--- a/test/lint/check-doc.py
+++ b/test/lint/check-doc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/check-rpc-mappings.py b/test/lint/check-rpc-mappings.py
deleted file mode 100755
index 0a4cc875d0..0000000000
--- a/test/lint/check-rpc-mappings.py
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2017-2019 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Check RPC argument consistency."""
-
-from collections import defaultdict
-import os
-import re
-import sys
-
-# Source files (relative to root) to scan for dispatch tables
-SOURCES = [
- "src/rpc/server.cpp",
- "src/rpc/blockchain.cpp",
- "src/rpc/mining.cpp",
- "src/rpc/misc.cpp",
- "src/rpc/net.cpp",
- "src/rpc/rawtransaction.cpp",
- "src/wallet/rpcwallet.cpp",
-]
-# Source file (relative to root) containing conversion mapping
-SOURCE_CLIENT = 'src/rpc/client.cpp'
-# Argument names that should be ignored in consistency checks
-IGNORE_DUMMY_ARGS = {'dummy', 'arg0', 'arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6', 'arg7', 'arg8', 'arg9'}
-
-class RPCCommand:
- def __init__(self, name, args):
- self.name = name
- self.args = args
-
-class RPCArgument:
- def __init__(self, names, idx):
- self.names = names
- self.idx = idx
- self.convert = False
-
-def parse_string(s):
- assert s[0] == '"'
- assert s[-1] == '"'
- return s[1:-1]
-
-def process_commands(fname):
- """Find and parse dispatch table in implementation file `fname`."""
- cmds = []
- in_rpcs = False
- with open(fname, "r", encoding="utf8") as f:
- for line in f:
- line = line.rstrip()
- if not in_rpcs:
- if re.match(r"static const CRPCCommand .*\[\] =", line):
- in_rpcs = True
- else:
- if line.startswith('};'):
- in_rpcs = False
- elif '{' in line and '"' in line:
- m = re.search(r'{ *("[^"]*"), *("[^"]*"), *&([^,]*), *{([^}]*)} *},', line)
- assert m, 'No match to table expression: %s' % line
- name = parse_string(m.group(2))
- args_str = m.group(4).strip()
- if args_str:
- args = [RPCArgument(parse_string(x.strip()).split('|'), idx) for idx, x in enumerate(args_str.split(','))]
- else:
- args = []
- cmds.append(RPCCommand(name, args))
- assert not in_rpcs and cmds, "Something went wrong with parsing the C++ file: update the regexps"
- return cmds
-
-def process_mapping(fname):
- """Find and parse conversion table in implementation file `fname`."""
- cmds = []
- in_rpcs = False
- with open(fname, "r", encoding="utf8") as f:
- for line in f:
- line = line.rstrip()
- if not in_rpcs:
- if line == 'static const CRPCConvertParam vRPCConvertParams[] =':
- in_rpcs = True
- else:
- if line.startswith('};'):
- in_rpcs = False
- elif '{' in line and '"' in line:
- m = re.search(r'{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *},', line)
- assert m, 'No match to table expression: %s' % line
- name = parse_string(m.group(1))
- idx = int(m.group(2))
- argname = parse_string(m.group(3))
- cmds.append((name, idx, argname))
- assert not in_rpcs and cmds
- return cmds
-
-def main():
- if len(sys.argv) != 2:
- print('Usage: {} ROOT-DIR'.format(sys.argv[0]), file=sys.stderr)
- sys.exit(1)
-
- root = sys.argv[1]
-
- # Get all commands from dispatch tables
- cmds = []
- for fname in SOURCES:
- cmds += process_commands(os.path.join(root, fname))
-
- cmds_by_name = {}
- for cmd in cmds:
- cmds_by_name[cmd.name] = cmd
-
- # Get current convert mapping for client
- client = SOURCE_CLIENT
- mapping = set(process_mapping(os.path.join(root, client)))
-
- print('* Checking consistency between dispatch tables and vRPCConvertParams')
-
- # Check mapping consistency
- errors = 0
- for (cmdname, argidx, argname) in mapping:
- try:
- rargnames = cmds_by_name[cmdname].args[argidx].names
- except IndexError:
- print('ERROR: %s argument %i (named %s in vRPCConvertParams) is not defined in dispatch table' % (cmdname, argidx, argname))
- errors += 1
- continue
- if argname not in rargnames:
- print('ERROR: %s argument %i is named %s in vRPCConvertParams but %s in dispatch table' % (cmdname, argidx, argname, rargnames), file=sys.stderr)
- errors += 1
-
- # Check for conflicts in vRPCConvertParams conversion
- # All aliases for an argument must either be present in the
- # conversion table, or not. Anything in between means an oversight
- # and some aliases won't work.
- for cmd in cmds:
- for arg in cmd.args:
- convert = [((cmd.name, arg.idx, argname) in mapping) for argname in arg.names]
- if any(convert) != all(convert):
- print('ERROR: %s argument %s has conflicts in vRPCConvertParams conversion specifier %s' % (cmd.name, arg.names, convert))
- errors += 1
- arg.convert = all(convert)
-
- # Check for conversion difference by argument name.
- # It is preferable for API consistency that arguments with the same name
- # have the same conversion, so bin by argument name.
- all_methods_by_argname = defaultdict(list)
- converts_by_argname = defaultdict(list)
- for cmd in cmds:
- for arg in cmd.args:
- for argname in arg.names:
- all_methods_by_argname[argname].append(cmd.name)
- converts_by_argname[argname].append(arg.convert)
-
- for argname, convert in converts_by_argname.items():
- if all(convert) != any(convert):
- if argname in IGNORE_DUMMY_ARGS:
- # these are testing or dummy, don't warn for them
- continue
- print('WARNING: conversion mismatch for argument named %s (%s)' %
- (argname, list(zip(all_methods_by_argname[argname], converts_by_argname[argname]))))
-
- sys.exit(errors > 0)
-
-
-if __name__ == '__main__':
- main()
diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh
index 827c978bed..e66adfc3ce 100755
--- a/test/lint/commit-script-check.sh
+++ b/test/lint/commit-script-check.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh
index 46aa6e7157..3556e49e08 100755
--- a/test/lint/git-subtree-check.sh
+++ b/test/lint/git-subtree-check.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2015-2019 The Bitcoin Core developers
+# Copyright (c) 2015-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/lint-assertions.sh b/test/lint/lint-assertions.sh
index d30a8ca231..2860f5621b 100755
--- a/test/lint/lint-assertions.sh
+++ b/test/lint/lint-assertions.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh
index ecaad215c4..2b3a9b87c2 100755
--- a/test/lint/lint-git-commit-check.sh
+++ b/test/lint/lint-git-commit-check.sh
@@ -23,13 +23,6 @@ while getopts "?" opt; do
esac
done
-# TRAVIS_BRANCH will be present in a Travis environment. For builds triggered
-# by a pull request this is the name of the branch targeted by the pull request.
-# https://docs.travis-ci.com/user/environment-variables/
-if [ -n "${TRAVIS_BRANCH}" ]; then
- COMMIT_RANGE="$TRAVIS_BRANCH..HEAD"
-fi
-
if [ -z "${COMMIT_RANGE}" ]; then
if [ -n "$1" ]; then
COMMIT_RANGE="HEAD~$1...HEAD"
diff --git a/test/lint/lint-include-guards.sh b/test/lint/lint-include-guards.sh
index 5d5a150db8..5cfa41537f 100755
--- a/test/lint/lint-include-guards.sh
+++ b/test/lint/lint-include-guards.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index fde77aea2d..262e9d4c79 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -60,7 +60,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/multi_index/ordered_index.hpp
boost/multi_index/sequenced_index.hpp
boost/multi_index_container.hpp
- boost/optional.hpp
boost/preprocessor/cat.hpp
boost/preprocessor/stringize.hpp
boost/process.hpp
@@ -69,12 +68,8 @@ EXPECTED_BOOST_INCLUDES=(
boost/signals2/signal.hpp
boost/test/unit_test.hpp
boost/thread/condition_variable.hpp
- boost/thread/mutex.hpp
boost/thread/shared_mutex.hpp
boost/thread/thread.hpp
- boost/variant.hpp
- boost/variant/apply_visitor.hpp
- boost/variant/static_visitor.hpp
)
for BOOST_INCLUDE in $(git grep '^#include <boost/' -- "*.cpp" "*.h" | cut -f2 -d: | cut -f2 -d'<' | cut -f1 -d'>' | sort -u); do
diff --git a/test/lint/lint-python-utf8-encoding.sh b/test/lint/lint-python-utf8-encoding.sh
index 7257919c98..6e5b18fc23 100755
--- a/test/lint/lint-python-utf8-encoding.sh
+++ b/test/lint/lint-python-utf8-encoding.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index 4fc130497b..51815963f6 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
@@ -102,7 +102,7 @@ if ! PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; e
EXIT_CODE=1
fi
-if ! mypy --ignore-missing-imports $(git ls-files "test/functional/*.py"); then
+if ! mypy --ignore-missing-imports $(git ls-files "test/functional/*.py" "contrib/devtools/*.py"); then
EXIT_CODE=1
fi
diff --git a/test/lint/lint-shebang.sh b/test/lint/lint-shebang.sh
index a5c8aa42b2..13ebdfd78a 100755
--- a/test/lint/lint-shebang.sh
+++ b/test/lint/lint-shebang.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-# Copyright (c) 2018-2019 The Bitcoin Core developers
+# Copyright (c) 2018-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 351b65dea6..4dbf5ed28e 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -8,14 +8,6 @@
export LC_ALL=C
-# The shellcheck binary segfault/coredumps in Travis with LC_ALL=C
-# It does not do so in Ubuntu 14.04, 16.04, 18.04 in versions 0.3.3, 0.3.7, 0.4.6
-# respectively. So export LC_ALL=C is set as required by lint-shell-locale.sh
-# but unset here in case of running in Travis.
-if [ "$TRAVIS" = "true" ]; then
- unset LC_ALL
-fi
-
# Disabled warnings:
disabled=(
SC2046 # Quote this to prevent word splitting.
diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt
index 34f54325b3..78ffe4def3 100644
--- a/test/lint/lint-spelling.ignore-words.txt
+++ b/test/lint/lint-spelling.ignore-words.txt
@@ -1,17 +1,15 @@
+asend
+blockin
+cachable
+fo
+fpr
hights
+hist
+inout
mor
-mut
-objext
+nin
+ser
+unparseable
+unser
useable
wit
-unparseable
-copyable
-cachable
-errorstring
-keyserver
-homogenous
-setban
-hist
-ser
-unselect
-lowercased
diff --git a/test/lint/lint-spelling.sh b/test/lint/lint-spelling.sh
index cb84727ba5..fbdf3c59c1 100755
--- a/test/lint/lint-spelling.sh
+++ b/test/lint/lint-spelling.sh
@@ -15,6 +15,6 @@ if ! command -v codespell > /dev/null; then
fi
IGNORE_WORDS_FILE=test/lint/lint-spelling.ignore-words.txt
-if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/"); then
+if ! codespell --check-filenames --disable-colors --quiet-level=7 --ignore-words=${IGNORE_WORDS_FILE} $(git ls-files -- ":(exclude)build-aux/m4/" ":(exclude)contrib/seeds/*.txt" ":(exclude)depends/" ":(exclude)doc/release-notes/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/qt/locale/" ":(exclude)src/qt/*.qrc" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)contrib/gitian-keys/keys.txt"); then
echo "^ Warning: codespell identified likely spelling errors. Any false positives? Add them to the list of ignored words in ${IGNORE_WORDS_FILE}"
fi
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index 80af0a439d..37fcf7804a 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2017-2019 The Bitcoin Core developers
+# Copyright (c) 2017-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
@@ -22,13 +22,6 @@ while getopts "?" opt; do
esac
done
-# TRAVIS_BRANCH will be present in a Travis environment. For builds triggered
-# by a pull request this is the name of the branch targeted by the pull request.
-# https://docs.travis-ci.com/user/environment-variables/
-if [ -n "${TRAVIS_BRANCH}" ]; then
- COMMIT_RANGE="$TRAVIS_BRANCH..HEAD"
-fi
-
if [ -z "${COMMIT_RANGE}" ]; then
if [ -n "$1" ]; then
COMMIT_RANGE="HEAD~$1...HEAD"
@@ -40,7 +33,7 @@ if [ -z "${COMMIT_RANGE}" ]; then
fi
showdiff() {
- if ! git diff -U0 "${COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then
+ if ! git diff -U0 "${COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)contrib/guix/patches/" ":(exclude)src/leveldb/" ":(exclude)src/crc32c/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/" ":(exclude)src/qt/locale/"; then
echo "Failed to get a diff"
exit 1
fi
diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan
index 986e096056..3a04418e8b 100644
--- a/test/sanitizer_suppressions/tsan
+++ b/test/sanitizer_suppressions/tsan
@@ -1,5 +1,7 @@
# ThreadSanitizer suppressions
# ============================
+#
+# https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
# double locks (TODO fix)
mutex:g_genesis_wait_mutex
@@ -11,8 +13,9 @@ mutex:CConnman::ThreadOpenConnections
mutex:CConnman::ThreadOpenAddedConnections
mutex:CConnman::SocketHandler
mutex:UpdateTip
-mutex:PeerManager::UpdatedBlockTip
+mutex:PeerManagerImpl::UpdatedBlockTip
mutex:g_best_block_mutex
+
# race (TODO fix)
race:CConnman::WakeMessageHandler
race:CConnman::ThreadMessageHandler
@@ -27,14 +30,9 @@ race:DatabaseBatch
race:leveldb::DBImpl::DeleteObsoleteFiles
race:zmq::*
race:bitcoin-qt
+
# deadlock (TODO fix)
-deadlock:CConnman::ForNode
-deadlock:CConnman::GetNodeStats
deadlock:CChainState::ConnectTip
-deadlock:UpdateTip
-
-# WalletBatch (unidentified deadlock)
-deadlock:WalletBatch
# Intentional deadlock in tests
deadlock:TestPotentialDeadLockDetected
@@ -46,4 +44,15 @@ deadlock:src/qt/test/*
# External libraries
deadlock:libdb
race:libzmq
-race:epoll_ctl # https://github.com/bitcoin/bitcoin/pull/20218
+
+# Intermittent issues
+# -------------------
+#
+# Suppressions that follow might only happen intermittently, thus they are not
+# reproducible. Make sure to include a link to a full trace.
+
+# https://github.com/bitcoin/bitcoin/issues/20618
+race:CZMQAbstractPublishNotifier::SendZmqMessage
+
+# https://github.com/bitcoin/bitcoin/pull/20218, https://github.com/bitcoin/bitcoin/pull/20745
+race:epoll_ctl
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index 291aab0a4a..97f0f45e7f 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -1,3 +1,7 @@
+# -fsanitize=undefined suppressions
+# =================================
+# No suppressions at the moment. Hooray!
+
# -fsanitize=integer suppressions
# ===============================
# Unsigned integer overflow occurs when the result of an unsigned integer
@@ -6,7 +10,8 @@
# contains files in which we expect unsigned integer overflows to occur. The
# list is used to suppress -fsanitize=integer warnings when running our CI UBSan
# job.
-unsigned-integer-overflow:*/include/c++/*/bits/basic_string.tcc
+unsigned-integer-overflow:*/include/c++/
+unsigned-integer-overflow:addrman.cpp
unsigned-integer-overflow:arith_uint256.h
unsigned-integer-overflow:basic_string.h
unsigned-integer-overflow:bench/bench.h
@@ -15,40 +20,41 @@ unsigned-integer-overflow:bloom.cpp
unsigned-integer-overflow:chain.cpp
unsigned-integer-overflow:chain.h
unsigned-integer-overflow:coded_stream.h
+unsigned-integer-overflow:coins.cpp
+unsigned-integer-overflow:compressor.cpp
unsigned-integer-overflow:core_write.cpp
-unsigned-integer-overflow:crypto/chacha20.cpp
-unsigned-integer-overflow:crypto/ctaes/ctaes.c
-unsigned-integer-overflow:crypto/poly1305.cpp
-unsigned-integer-overflow:crypto/ripemd160.cpp
-unsigned-integer-overflow:crypto/sha1.cpp
-unsigned-integer-overflow:crypto/sha256.cpp
-unsigned-integer-overflow:crypto/sha512.cpp
+unsigned-integer-overflow:crypto/
+# unsigned-integer-overflow in FuzzedDataProvider's ConsumeIntegralInRange
+unsigned-integer-overflow:FuzzedDataProvider.h
unsigned-integer-overflow:hash.cpp
-unsigned-integer-overflow:leveldb/db/log_reader.cc
-unsigned-integer-overflow:leveldb/util/bloom.cc
-unsigned-integer-overflow:leveldb/util/crc32c.h
-unsigned-integer-overflow:leveldb/util/hash.cc
+unsigned-integer-overflow:leveldb/
unsigned-integer-overflow:policy/fees.cpp
unsigned-integer-overflow:prevector.h
+unsigned-integer-overflow:pubkey.h
unsigned-integer-overflow:script/interpreter.cpp
unsigned-integer-overflow:stl_bvector.h
unsigned-integer-overflow:txmempool.cpp
unsigned-integer-overflow:util/strencodings.cpp
unsigned-integer-overflow:validation.cpp
-
-implicit-integer-sign-change:*/include/c++/*/bits/*.h
+implicit-integer-sign-change:*/include/boost/
+implicit-integer-sign-change:*/include/c++/
implicit-integer-sign-change:*/new_allocator.h
-implicit-integer-sign-change:/usr/include/boost/date_time/format_date_parser.hpp
+implicit-integer-sign-change:addrman.h
implicit-integer-sign-change:arith_uint256.cpp
implicit-integer-sign-change:bech32.cpp
implicit-integer-sign-change:bloom.cpp
-implicit-integer-sign-change:chain.*
+implicit-integer-sign-change:chain.cpp
+implicit-integer-sign-change:chain.h
implicit-integer-sign-change:coins.h
implicit-integer-sign-change:compat/stdin.cpp
implicit-integer-sign-change:compressor.h
-implicit-integer-sign-change:crypto/*
+implicit-integer-sign-change:crc32c/
+implicit-integer-sign-change:crypto/
+# implicit-integer-sign-change in FuzzedDataProvider's ConsumeIntegralInRange
+implicit-integer-sign-change:FuzzedDataProvider.h
implicit-integer-sign-change:key.cpp
implicit-integer-sign-change:noui.cpp
+implicit-integer-sign-change:policy/fees.cpp
implicit-integer-sign-change:prevector.h
implicit-integer-sign-change:protocol.cpp
implicit-integer-sign-change:script/bitcoinconsensus.cpp
@@ -59,22 +65,38 @@ implicit-integer-sign-change:test/coins_tests.cpp
implicit-integer-sign-change:test/pow_tests.cpp
implicit-integer-sign-change:test/prevector_tests.cpp
implicit-integer-sign-change:test/sighash_tests.cpp
+implicit-integer-sign-change:test/skiplist_tests.cpp
implicit-integer-sign-change:test/streams_tests.cpp
implicit-integer-sign-change:test/transaction_tests.cpp
implicit-integer-sign-change:txmempool.cpp
-implicit-integer-sign-change:util/strencodings.*
+implicit-integer-sign-change:util/strencodings.cpp
+implicit-integer-sign-change:util/strencodings.h
implicit-integer-sign-change:validation.cpp
implicit-integer-sign-change:zmq/zmqpublishnotifier.cpp
implicit-signed-integer-truncation,implicit-integer-sign-change:chain.h
implicit-signed-integer-truncation,implicit-integer-sign-change:test/skiplist_tests.cpp
+implicit-signed-integer-truncation:addrman.cpp
+implicit-signed-integer-truncation:addrman.h
implicit-signed-integer-truncation:chain.h
-implicit-signed-integer-truncation:crypto/*
+implicit-signed-integer-truncation:crypto/
implicit-signed-integer-truncation:cuckoocache.h
-implicit-signed-integer-truncation:leveldb/*
+implicit-signed-integer-truncation:leveldb/
+implicit-signed-integer-truncation:net.cpp
+implicit-signed-integer-truncation:net_processing.cpp
implicit-signed-integer-truncation:streams.h
implicit-signed-integer-truncation:test/arith_uint256_tests.cpp
implicit-signed-integer-truncation:test/skiplist_tests.cpp
implicit-signed-integer-truncation:torcontrol.cpp
-implicit-unsigned-integer-truncation:crypto/*
-implicit-unsigned-integer-truncation:leveldb/*
-implicit-integer-sign-change:crc32c/*
+implicit-unsigned-integer-truncation:*/include/c++/
+implicit-unsigned-integer-truncation:crypto/
+implicit-unsigned-integer-truncation:leveldb/
+# std::variant warning fixed in https://github.com/gcc-mirror/gcc/commit/074436cf8cdd2a9ce75cadd36deb8301f00e55b9
+implicit-unsigned-integer-truncation:std::__detail::__variant::_Variant_storage
+shift-base:*/include/c++/
+shift-base:arith_uint256.cpp
+shift-base:crypto/
+shift-base:hash.cpp
+shift-base:leveldb/
+shift-base:net_processing.cpp
+shift-base:streams.h
+shift-base:util/bip32.cpp