aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml10
-rw-r--r--.cirrus.yml11
-rw-r--r--.gitignore9
-rw-r--r--.python-version2
-rw-r--r--.style.yapf2
-rw-r--r--.travis.yml54
-rwxr-xr-x.travis/lint_04_install.sh2
-rwxr-xr-x.travis/lint_06_script.sh4
-rwxr-xr-x.travis/test_04_install.sh4
-rwxr-xr-x.travis/test_06_script_b.sh4
-rw-r--r--CONTRIBUTING.md37
-rw-r--r--Makefile.am3
-rw-r--r--README.md2
-rw-r--r--SECURITY.md20
-rw-r--r--build-aux/m4/ax_boost_base.m4252
-rw-r--r--build-aux/m4/ax_boost_system.m47
-rw-r--r--build_msvc/.gitignore1
-rw-r--r--build_msvc/README.md17
-rw-r--r--build_msvc/bench_bitcoin/bench_bitcoin.vcxproj175
-rw-r--r--build_msvc/bitcoin-cli/bitcoin-cli.vcxproj166
-rw-r--r--build_msvc/bitcoin-tx/bitcoin-tx.vcxproj163
-rw-r--r--build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj163
-rw-r--r--build_msvc/bitcoin.sln11
-rw-r--r--build_msvc/bitcoin_config.h10
-rw-r--r--build_msvc/bitcoind/bitcoind.vcxproj177
-rw-r--r--build_msvc/common.init.vcxproj131
-rw-r--r--build_msvc/common.vcxproj30
-rw-r--r--build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in157
-rw-r--r--build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in165
-rw-r--r--build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in148
-rw-r--r--build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in162
-rw-r--r--build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in171
-rw-r--r--build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in161
-rw-r--r--build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in161
-rw-r--r--build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in161
-rw-r--r--build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj179
-rw-r--r--build_msvc/libleveldb/libleveldb.vcxproj168
-rw-r--r--build_msvc/libsecp256k1/libsecp256k1.vcxproj162
-rw-r--r--build_msvc/libunivalue/libunivalue.vcxproj160
-rw-r--r--build_msvc/msbuild/tasks/replaceinfile.targets35
-rw-r--r--build_msvc/msvc-autogen.py19
-rw-r--r--build_msvc/test_bitcoin/test_bitcoin.vcxproj170
-rw-r--r--build_msvc/testconsensus/testconsensus.vcxproj163
-rw-r--r--configure.ac91
-rw-r--r--contrib/devtools/README.md6
-rwxr-xr-xcontrib/devtools/github-merge.py118
-rw-r--r--contrib/devtools/split-debug.sh.in2
-rwxr-xr-xcontrib/devtools/symbol-check.py2
-rwxr-xr-xcontrib/devtools/test-security-check.py12
-rwxr-xr-xcontrib/devtools/test_deterministic_coverage.sh1
-rwxr-xr-xcontrib/gitian-build.py118
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml20
-rw-r--r--contrib/gitian-descriptors/gitian-osx-signer.yml3
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml21
-rw-r--r--contrib/gitian-descriptors/gitian-win-signer.yml3
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml19
-rw-r--r--contrib/gitian-keys/keys.txt1
-rwxr-xr-xcontrib/install_db4.sh14
-rw-r--r--contrib/linearize/README.md3
-rwxr-xr-xcontrib/linearize/linearize-data.py6
-rwxr-xr-xcontrib/seeds/makeseeds.py27
-rw-r--r--contrib/verify-commits/trusted-keys1
-rwxr-xr-xcontrib/verify-commits/verify-commits.py10
-rw-r--r--contrib/windeploy/win-codesign.cert187
-rw-r--r--contrib/zmq/zmq_sub3.4.py90
-rw-r--r--depends/Makefile9
-rw-r--r--depends/README.md8
-rw-r--r--depends/config.site.in6
-rw-r--r--depends/funcs.mk17
-rw-r--r--depends/packages.md40
-rw-r--r--depends/packages/bdb.mk2
-rw-r--r--depends/packages/boost.mk6
-rw-r--r--depends/packages/dbus.mk6
-rw-r--r--depends/packages/expat.mk7
-rw-r--r--depends/packages/fontconfig.mk6
-rw-r--r--depends/packages/freetype.mk6
-rw-r--r--depends/packages/libX11.mk11
-rw-r--r--depends/packages/libXau.mk6
-rw-r--r--depends/packages/libXext.mk35
-rw-r--r--depends/packages/libevent.mk1
-rw-r--r--depends/packages/libxcb.mk4
-rw-r--r--depends/packages/miniupnpc.mk2
-rw-r--r--depends/packages/native_biplist.mk6
-rw-r--r--depends/packages/native_cctools.mk6
-rw-r--r--depends/packages/native_cdrkit.mk2
-rw-r--r--depends/packages/native_ds_store.mk6
-rw-r--r--depends/packages/native_mac_alias.mk6
-rw-r--r--depends/packages/native_protobuf.mk2
-rw-r--r--depends/packages/packages.mk4
-rw-r--r--depends/packages/protobuf.mk2
-rw-r--r--depends/packages/qrencode.mk4
-rw-r--r--depends/packages/qt.mk8
-rw-r--r--depends/packages/rapidcheck.mk25
-rw-r--r--depends/packages/xcb_proto.mk2
-rw-r--r--depends/packages/xextproto.mk2
-rw-r--r--depends/packages/xproto.mk2
-rw-r--r--depends/packages/xtrans.mk4
-rw-r--r--depends/packages/zeromq.mk2
-rw-r--r--depends/packages/zlib.mk2
-rw-r--r--doc/JSON-RPC-interface.md12
-rw-r--r--doc/README.md1
-rw-r--r--doc/REST-interface.md1
-rw-r--r--doc/bips.md8
-rw-r--r--doc/build-osx.md261
-rw-r--r--doc/build-windows.md39
-rw-r--r--doc/dependencies.md8
-rw-r--r--doc/descriptors.md19
-rw-r--r--doc/developer-notes.md18
-rw-r--r--doc/man/Makefile.am6
-rw-r--r--doc/man/bitcoin-qt.13
-rw-r--r--doc/man/bitcoind.14
-rw-r--r--doc/productivity.md62
-rw-r--r--doc/psbt.md11
-rw-r--r--doc/reduce-traffic.md13
-rw-r--r--doc/release-notes-0.18.1-16257.md6
-rw-r--r--doc/release-notes-13756.md41
-rw-r--r--doc/release-notes-14021.md11
-rw-r--r--doc/release-notes-14054.md7
-rw-r--r--doc/release-notes-14481.md9
-rw-r--r--doc/release-notes-14491.md5
-rw-r--r--doc/release-notes-14667.md4
-rw-r--r--doc/release-notes-14802.md3
-rw-r--r--doc/release-notes-14954.md3
-rw-r--r--doc/release-notes-15006.md4
-rw-r--r--doc/release-notes-15226.md8
-rw-r--r--doc/release-notes-15393.md4
-rw-r--r--doc/release-notes-15492.md11
-rw-r--r--doc/release-notes-15566.md3
-rw-r--r--doc/release-notes-15620.md13
-rw-r--r--doc/release-notes-15637.md3
-rw-r--r--doc/release-notes-15730.md5
-rw-r--r--doc/release-notes-15849.md6
-rw-r--r--doc/release-notes.md80
-rw-r--r--doc/release-notes/release-notes-0.12.0.md2
-rw-r--r--doc/release-notes/release-notes-0.18.0.md1224
-rw-r--r--doc/release-process.md77
-rw-r--r--doc/shared-libraries.md4
-rw-r--r--doc/tor.md7
-rw-r--r--doc/travis-ci.md42
-rw-r--r--share/setup.nsi.in11
-rw-r--r--src/Makefile.am66
-rw-r--r--src/Makefile.bench.include16
-rw-r--r--src/Makefile.qt.include3
-rw-r--r--src/Makefile.qttest.include4
-rw-r--r--src/Makefile.test.include307
-rw-r--r--src/addrdb.cpp20
-rw-r--r--src/addrman.cpp14
-rw-r--r--src/addrman.h3
-rw-r--r--src/arith_uint256.cpp1
-rw-r--r--src/bench/base58.cpp1
-rw-r--r--src/bench/bech32.cpp1
-rw-r--r--src/bench/bench.cpp20
-rw-r--r--src/bench/bench_bitcoin.cpp32
-rw-r--r--src/bench/block_assemble.cpp75
-rw-r--r--src/bench/ccoins_caching.cpp4
-rw-r--r--src/bench/chacha20.cpp45
-rw-r--r--src/bench/checkqueue.cpp1
-rw-r--r--src/bench/coin_selection.cpp4
-rw-r--r--src/bench/crypto_hash.cpp2
-rw-r--r--src/bench/duplicate_inputs.cpp42
-rw-r--r--src/bench/examples.cpp1
-rw-r--r--src/bench/poly1305.cpp41
-rw-r--r--src/bench/rollingbloom.cpp9
-rw-r--r--src/bench/rpc_mempool.cpp42
-rw-r--r--src/bench/util_time.cpp42
-rw-r--r--src/bench/verify_script.cpp1
-rw-r--r--src/bench/wallet_balance.cpp52
-rw-r--r--src/bitcoin-cli.cpp22
-rw-r--r--src/bitcoin-tx.cpp23
-rw-r--r--src/bitcoin-wallet.cpp13
-rw-r--r--src/bitcoind.cpp25
-rw-r--r--src/blockencodings.cpp2
-rw-r--r--src/blockfilter.cpp60
-rw-r--r--src/blockfilter.h18
-rw-r--r--src/bloom.cpp5
-rw-r--r--src/chain.cpp7
-rw-r--r--src/chain.h4
-rw-r--r--src/checkpoints.cpp32
-rw-r--r--src/checkpoints.h27
-rw-r--r--src/coins.h4
-rw-r--r--src/compat/assumptions.h18
-rw-r--r--src/consensus/merkle.cpp1
-rw-r--r--src/consensus/tx_check.cpp57
-rw-r--r--src/consensus/tx_check.h20
-rw-r--r--src/consensus/tx_verify.cpp60
-rw-r--r--src/consensus/tx_verify.h3
-rw-r--r--src/consensus/validation.h106
-rw-r--r--src/core_io.h6
-rw-r--r--src/core_read.cpp29
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/crypto/aes.cpp63
-rw-r--r--src/crypto/aes.h51
-rw-r--r--src/crypto/chacha20.cpp132
-rw-r--r--src/crypto/chacha20.h18
-rw-r--r--src/crypto/hkdf_sha256_32.cpp21
-rw-r--r--src/crypto/hkdf_sha256_32.h25
-rw-r--r--src/crypto/poly1305.cpp141
-rw-r--r--src/crypto/poly1305.h17
-rw-r--r--src/crypto/ripemd160.cpp2
-rw-r--r--src/crypto/sha1.cpp2
-rw-r--r--src/crypto/sha256_avx2.cpp1
-rw-r--r--src/crypto/sha256_sse41.cpp1
-rw-r--r--src/crypto/sha512.cpp2
-rw-r--r--src/dbwrapper.cpp2
-rw-r--r--src/dummywallet.cpp32
-rw-r--r--src/fs.cpp2
-rw-r--r--src/fs.h1
-rw-r--r--src/httprpc.cpp1
-rw-r--r--src/httpserver.cpp31
-rw-r--r--src/httpserver.h2
-rw-r--r--src/index/base.cpp77
-rw-r--r--src/index/base.h21
-rw-r--r--src/index/blockfilterindex.cpp467
-rw-r--r--src/index/blockfilterindex.h94
-rw-r--r--src/index/txindex.cpp2
-rw-r--r--src/init.cpp212
-rw-r--r--src/interfaces/README.md4
-rw-r--r--src/interfaces/chain.cpp218
-rw-r--r--src/interfaces/chain.h160
-rw-r--r--src/interfaces/node.cpp13
-rw-r--r--src/interfaces/node.h3
-rw-r--r--src/interfaces/wallet.cpp47
-rw-r--r--src/interfaces/wallet.h10
-rw-r--r--src/key.cpp7
-rw-r--r--src/key.h3
-rw-r--r--src/key_io.cpp8
-rw-r--r--src/keystore.cpp9
-rw-r--r--src/logging.cpp98
-rw-r--r--src/logging.h23
-rw-r--r--src/merkleblock.cpp1
-rw-r--r--src/miner.cpp6
-rw-r--r--src/net.cpp17
-rw-r--r--src/net.h18
-rw-r--r--src/net_processing.cpp656
-rw-r--r--src/netaddress.cpp128
-rw-r--r--src/netaddress.h11
-rw-r--r--src/netbase.cpp3
-rw-r--r--src/node/README.md22
-rw-r--r--src/node/coin.cpp22
-rw-r--r--src/node/coin.h22
-rw-r--r--src/node/psbt.cpp134
-rw-r--r--src/node/psbt.h43
-rw-r--r--src/node/transaction.cpp27
-rw-r--r--src/node/transaction.h15
-rw-r--r--src/noui.cpp36
-rw-r--r--src/outputtype.cpp18
-rw-r--r--src/policy/fees.cpp39
-rw-r--r--src/policy/fees.h5
-rw-r--r--src/policy/policy.cpp28
-rw-r--r--src/policy/policy.h24
-rw-r--r--src/policy/rbf.cpp13
-rw-r--r--src/policy/rbf.h8
-rw-r--r--src/policy/settings.cpp14
-rw-r--r--src/policy/settings.h35
-rw-r--r--src/prevector.h31
-rw-r--r--src/primitives/block.cpp1
-rw-r--r--src/primitives/transaction.h4
-rw-r--r--src/psbt.cpp42
-rw-r--r--src/psbt.h18
-rw-r--r--src/qt/addressbookpage.cpp3
-rw-r--r--src/qt/addresstablemodel.cpp1
-rw-r--r--src/qt/bantablemodel.cpp2
-rw-r--r--src/qt/bitcoin.cpp14
-rw-r--r--src/qt/bitcoingui.cpp58
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/bitcoinunits.cpp2
-rw-r--r--src/qt/clientmodel.cpp7
-rw-r--r--src/qt/coincontroldialog.cpp8
-rw-r--r--src/qt/forms/coincontroldialog.ui6
-rw-r--r--src/qt/forms/debugwindow.ui16
-rw-r--r--src/qt/forms/receivecoinsdialog.ui10
-rw-r--r--src/qt/forms/receiverequestdialog.ui2
-rw-r--r--src/qt/guiconstants.h6
-rw-r--r--src/qt/guiutil.cpp20
-rw-r--r--src/qt/guiutil.h5
-rw-r--r--src/qt/intro.cpp13
-rw-r--r--src/qt/intro.h5
-rw-r--r--src/qt/optionsdialog.cpp8
-rw-r--r--src/qt/optionsmodel.cpp7
-rw-r--r--src/qt/paymentserver.cpp2
-rw-r--r--src/qt/peertablemodel.cpp1
-rw-r--r--src/qt/platformstyle.cpp2
-rw-r--r--src/qt/qrimagewidget.cpp141
-rw-r--r--src/qt/qrimagewidget.h45
-rw-r--r--src/qt/receivecoinsdialog.cpp8
-rw-r--r--src/qt/receiverequestdialog.cpp119
-rw-r--r--src/qt/receiverequestdialog.h30
-rw-r--r--src/qt/rpcconsole.cpp6
-rw-r--r--src/qt/sendcoinsdialog.cpp46
-rw-r--r--src/qt/sendcoinsdialog.h2
-rw-r--r--src/qt/signverifymessagedialog.cpp12
-rw-r--r--src/qt/test/addressbooktests.cpp7
-rw-r--r--src/qt/test/apptests.cpp9
-rw-r--r--src/qt/test/rpcnestedtests.cpp10
-rw-r--r--src/qt/test/rpcnestedtests.h3
-rw-r--r--src/qt/test/test_main.cpp15
-rw-r--r--src/qt/test/wallettests.cpp14
-rw-r--r--src/qt/transactiondesc.cpp3
-rw-r--r--src/qt/transactionrecord.cpp4
-rw-r--r--src/qt/transactiontablemodel.cpp4
-rw-r--r--src/qt/transactionview.cpp1
-rw-r--r--src/qt/utilitydialog.cpp7
-rw-r--r--src/qt/walletcontroller.cpp14
-rw-r--r--src/qt/walletframe.cpp24
-rw-r--r--src/qt/walletframe.h6
-rw-r--r--src/qt/walletmodel.cpp8
-rw-r--r--src/qt/walletmodel.h11
-rw-r--r--src/qt/walletmodeltransaction.cpp3
-rw-r--r--src/qt/walletview.cpp1
-rw-r--r--src/qt/winshutdownmonitor.cpp2
-rw-r--r--src/random.cpp60
-rw-r--r--src/random.h4
-rw-r--r--src/rest.cpp24
-rw-r--r--src/rpc/blockchain.cpp295
-rw-r--r--src/rpc/blockchain.h17
-rw-r--r--src/rpc/client.cpp6
-rw-r--r--src/rpc/mining.cpp50
-rw-r--r--src/rpc/mining.h15
-rw-r--r--src/rpc/misc.cpp48
-rw-r--r--src/rpc/net.cpp5
-rw-r--r--src/rpc/protocol.cpp1
-rw-r--r--src/rpc/rawtransaction.cpp672
-rw-r--r--src/rpc/rawtransaction.h22
-rw-r--r--src/rpc/rawtransaction_util.cpp282
-rw-r--r--src/rpc/rawtransaction_util.h32
-rw-r--r--src/rpc/server.cpp183
-rw-r--r--src/rpc/server.h73
-rw-r--r--src/rpc/util.cpp181
-rw-r--r--src/rpc/util.h47
-rw-r--r--src/script/descriptor.cpp58
-rw-r--r--src/script/descriptor.h8
-rw-r--r--src/script/ismine.h30
-rw-r--r--src/script/script.cpp1
-rw-r--r--src/script/script.h9
-rw-r--r--src/script/sigcache.cpp1
-rw-r--r--src/script/sign.cpp8
-rw-r--r--src/script/sign.h2
-rw-r--r--src/script/standard.cpp18
-rw-r--r--src/script/standard.h25
-rw-r--r--src/secp256k1/.gitignore1
-rw-r--r--src/secp256k1/.travis.yml9
-rw-r--r--src/secp256k1/Makefile.am13
-rw-r--r--src/secp256k1/build-aux/m4/ax_jni_include_dir.m447
-rw-r--r--src/secp256k1/build-aux/m4/bitcoin_secp.m41
-rw-r--r--src/secp256k1/configure.ac89
-rw-r--r--src/secp256k1/include/secp256k1.h49
-rw-r--r--src/secp256k1/include/secp256k1_ecdh.h32
-rw-r--r--src/secp256k1/libsecp256k1.pc.in2
-rw-r--r--src/secp256k1/src/bench.h16
-rw-r--r--src/secp256k1/src/bench_ecdh.c10
-rw-r--r--src/secp256k1/src/bench_ecmult.c207
-rw-r--r--src/secp256k1/src/bench_internal.c83
-rw-r--r--src/secp256k1/src/bench_recover.c8
-rw-r--r--src/secp256k1/src/bench_sign.c12
-rw-r--r--src/secp256k1/src/eckey_impl.h2
-rw-r--r--src/secp256k1/src/ecmult.h19
-rw-r--r--src/secp256k1/src/ecmult_const.h4
-rw-r--r--src/secp256k1/src/ecmult_const_impl.h97
-rw-r--r--src/secp256k1/src/ecmult_gen_impl.h4
-rw-r--r--src/secp256k1/src/ecmult_impl.h929
-rw-r--r--src/secp256k1/src/field_10x26.h4
-rw-r--r--src/secp256k1/src/field_10x26_impl.h5
-rw-r--r--src/secp256k1/src/field_5x52.h4
-rw-r--r--src/secp256k1/src/field_5x52_impl.h2
-rw-r--r--src/secp256k1/src/field_5x52_int128_impl.h4
-rw-r--r--src/secp256k1/src/field_impl.h3
-rw-r--r--src/secp256k1/src/gen_context.c2
-rw-r--r--src/secp256k1/src/group.h10
-rw-r--r--src/secp256k1/src/group_impl.h75
-rw-r--r--src/secp256k1/src/hash.h26
-rw-r--r--src/secp256k1/src/hash_impl.h49
-rw-r--r--src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java2
-rw-r--r--src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c6
-rw-r--r--src/secp256k1/src/modules/ecdh/main_impl.h41
-rw-r--r--src/secp256k1/src/modules/ecdh/tests_impl.h59
-rw-r--r--src/secp256k1/src/scalar_4x64_impl.h6
-rw-r--r--src/secp256k1/src/scratch.h39
-rw-r--r--src/secp256k1/src/scratch_impl.h86
-rw-r--r--src/secp256k1/src/secp256k1.c51
-rw-r--r--src/secp256k1/src/testrand_impl.h2
-rw-r--r--src/secp256k1/src/tests.c668
-rw-r--r--src/secp256k1/src/tests_exhaustive.c43
-rw-r--r--src/secp256k1/src/util.h10
-rw-r--r--src/serialize.h17
-rw-r--r--src/sync.cpp39
-rw-r--r--src/sync.h24
-rw-r--r--src/test/README.md2
-rw-r--r--src/test/addrman_tests.cpp4
-rw-r--r--src/test/allocator_tests.cpp6
-rw-r--r--src/test/amount_tests.cpp4
-rw-r--r--src/test/arith_uint256_tests.cpp5
-rw-r--r--src/test/base32_tests.cpp4
-rw-r--r--src/test/base58_tests.cpp4
-rw-r--r--src/test/base64_tests.cpp4
-rw-r--r--src/test/bech32_tests.cpp2
-rw-r--r--src/test/bip32_tests.cpp7
-rw-r--r--src/test/blockchain_tests.cpp3
-rw-r--r--src/test/blockencodings_tests.cpp7
-rw-r--r--src/test/blockfilter_index_tests.cpp306
-rw-r--r--src/test/blockfilter_tests.cpp35
-rw-r--r--src/test/bloom_tests.cpp4
-rw-r--r--src/test/bswap_tests.cpp4
-rw-r--r--src/test/checkqueue_tests.cpp8
-rw-r--r--src/test/coins_tests.cpp15
-rw-r--r--src/test/compilerbug_tests.cpp43
-rw-r--r--src/test/compress_tests.cpp4
-rw-r--r--src/test/crypto_tests.cpp263
-rw-r--r--src/test/cuckoocache_tests.cpp4
-rw-r--r--src/test/data/blockfilters.json10
-rw-r--r--src/test/dbwrapper_tests.cpp20
-rw-r--r--src/test/denialofservice_tests.cpp17
-rw-r--r--src/test/descriptor_tests.cpp8
-rw-r--r--src/test/flatfile_tests.cpp13
-rw-r--r--src/test/fs_tests.cpp7
-rw-r--r--src/test/fuzz/deserialize.cpp7
-rw-r--r--src/test/fuzz/fuzz.h3
-rw-r--r--src/test/fuzz/script_flags.cpp1
-rw-r--r--src/test/getarg_tests.cpp4
-rw-r--r--src/test/hash_tests.cpp7
-rw-r--r--src/test/key_io_tests.cpp4
-rw-r--r--src/test/key_properties.cpp8
-rw-r--r--src/test/key_tests.cpp45
-rw-r--r--src/test/limitedmap_tests.cpp4
-rw-r--r--src/test/main.cpp7
-rw-r--r--src/test/mempool_tests.cpp6
-rw-r--r--src/test/merkle_tests.cpp4
-rw-r--r--src/test/merkleblock_tests.cpp4
-rw-r--r--src/test/miner_tests.cpp75
-rw-r--r--src/test/multisig_tests.cpp6
-rw-r--r--src/test/net_tests.cpp11
-rw-r--r--src/test/netbase_tests.cpp5
-rw-r--r--src/test/pmt_tests.cpp4
-rw-r--r--src/test/policyestimator_tests.cpp5
-rw-r--r--src/test/pow_tests.cpp5
-rw-r--r--src/test/prevector_tests.cpp32
-rw-r--r--src/test/raii_event_tests.cpp6
-rw-r--r--src/test/random_tests.cpp4
-rw-r--r--src/test/reverselock_tests.cpp4
-rw-r--r--src/test/rpc_tests.cpp13
-rw-r--r--src/test/sanity_tests.cpp4
-rw-r--r--src/test/scheduler_tests.cpp4
-rw-r--r--src/test/script_p2sh_tests.cpp43
-rw-r--r--src/test/script_standard_tests.cpp404
-rw-r--r--src/test/script_tests.cpp12
-rw-r--r--src/test/scriptnum10.h1
-rw-r--r--src/test/scriptnum_tests.cpp4
-rw-r--r--src/test/serialize_tests.cpp5
-rw-r--r--src/test/setup_common.cpp (renamed from src/test/test_bitcoin.cpp)109
-rw-r--r--src/test/setup_common.h (renamed from src/test/test_bitcoin.h)19
-rw-r--r--src/test/sighash_tests.cpp6
-rw-r--r--src/test/sigopcount_tests.cpp16
-rw-r--r--src/test/skiplist_tests.cpp50
-rw-r--r--src/test/streams_tests.cpp5
-rw-r--r--src/test/sync_tests.cpp4
-rw-r--r--src/test/test_bitcoin_main.cpp30
-rw-r--r--src/test/timedata_tests.cpp4
-rw-r--r--src/test/torcontrol_tests.cpp6
-rw-r--r--src/test/transaction_tests.cpp38
-rw-r--r--src/test/txindex_tests.cpp7
-rw-r--r--src/test/txvalidation_tests.cpp11
-rw-r--r--src/test/txvalidationcache_tests.cpp36
-rw-r--r--src/test/uint256_tests.cpp10
-rw-r--r--src/test/util.cpp87
-rw-r--r--src/test/util.h70
-rw-r--r--src/test/util_tests.cpp380
-rw-r--r--src/test/util_threadnames_tests.cpp73
-rw-r--r--src/test/validation_block_tests.cpp12
-rw-r--r--src/test/validation_tests.cpp (renamed from src/test/main_tests.cpp)8
-rw-r--r--src/test/versionbits_tests.cpp34
-rw-r--r--src/threadsafety.h11
-rw-r--r--src/timedata.cpp1
-rw-r--r--src/tinyformat.h1
-rw-r--r--src/torcontrol.cpp10
-rw-r--r--src/txdb.cpp3
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp19
-rw-r--r--src/txmempool.h14
-rw-r--r--src/ui_interface.cpp18
-rw-r--r--src/ui_interface.h10
-rw-r--r--src/util/error.cpp45
-rw-r--r--src/util/error.h39
-rw-r--r--src/util/fees.cpp41
-rw-r--r--src/util/fees.h16
-rw-r--r--src/util/rbf.cpp17
-rw-r--r--src/util/rbf.h18
-rw-r--r--src/util/strencodings.h12
-rw-r--r--src/util/system.cpp55
-rw-r--r--src/util/system.h11
-rw-r--r--src/util/threadnames.cpp62
-rw-r--r--src/util/threadnames.h21
-rw-r--r--src/util/time.cpp16
-rw-r--r--src/util/time.h27
-rw-r--r--src/util/url.cpp21
-rw-r--r--src/util/url.h12
-rw-r--r--src/util/validation.cpp20
-rw-r--r--src/util/validation.h18
-rw-r--r--src/validation.cpp1078
-rw-r--r--src/validation.h235
-rw-r--r--src/validationinterface.cpp9
-rw-r--r--src/validationinterface.h5
-rw-r--r--src/wallet/coincontrol.cpp1
-rw-r--r--src/wallet/coincontrol.h6
-rw-r--r--src/wallet/crypter.cpp2
-rw-r--r--src/wallet/db.cpp25
-rw-r--r--src/wallet/db.h5
-rw-r--r--src/wallet/feebumper.cpp177
-rw-r--r--src/wallet/feebumper.h15
-rw-r--r--src/wallet/fees.cpp16
-rw-r--r--src/wallet/init.cpp114
-rw-r--r--src/wallet/ismine.cpp (renamed from src/script/ismine.cpp)15
-rw-r--r--src/wallet/ismine.h53
-rw-r--r--src/wallet/load.cpp112
-rw-r--r--src/wallet/load.h38
-rw-r--r--src/wallet/psbtwallet.cpp2
-rw-r--r--src/wallet/rpcdump.cpp178
-rw-r--r--src/wallet/rpcwallet.cpp519
-rw-r--r--src/wallet/rpcwallet.h17
-rw-r--r--src/wallet/test/coinselector_tests.cpp12
-rw-r--r--src/wallet/test/db_tests.cpp16
-rw-r--r--src/wallet/test/init_test_fixture.cpp5
-rw-r--r--src/wallet/test/init_test_fixture.h4
-rw-r--r--src/wallet/test/init_tests.cpp10
-rw-r--r--src/wallet/test/ismine_tests.cpp398
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp7
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp4
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp20
-rw-r--r--src/wallet/test/wallet_test_fixture.h6
-rw-r--r--src/wallet/test/wallet_tests.cpp117
-rw-r--r--src/wallet/wallet.cpp991
-rw-r--r--src/wallet/wallet.h355
-rw-r--r--src/wallet/walletdb.cpp15
-rw-r--r--src/wallet/walletdb.h14
-rw-r--r--src/wallet/wallettool.cpp50
-rw-r--r--src/wallet/wallettool.h4
-rw-r--r--src/wallet/walletutil.cpp17
-rw-r--r--src/warnings.cpp9
-rw-r--r--src/zmq/zmqabstractnotifier.cpp1
-rw-r--r--src/zmq/zmqnotificationinterface.cpp1
-rw-r--r--test/README.md3
-rw-r--r--test/config.ini.in1
-rwxr-xr-xtest/functional/combine_logs.py54
-rw-r--r--test/functional/data/invalid_txs.py10
-rw-r--r--test/functional/data/rpc_getblockstats.json276
-rwxr-xr-xtest/functional/example_test.py6
-rwxr-xr-xtest/functional/feature_assumevalid.py10
-rwxr-xr-xtest/functional/feature_bip68_sequence.py38
-rwxr-xr-xtest/functional/feature_block.py232
-rwxr-xr-xtest/functional/feature_cltv.py5
-rwxr-xr-xtest/functional/feature_config_args.py23
-rwxr-xr-xtest/functional/feature_csv_activation.py68
-rwxr-xr-xtest/functional/feature_dbcrash.py17
-rwxr-xr-xtest/functional/feature_dersig.py5
-rwxr-xr-xtest/functional/feature_fee_estimation.py14
-rwxr-xr-xtest/functional/feature_filelock.py2
-rwxr-xr-xtest/functional/feature_notifications.py2
-rwxr-xr-xtest/functional/feature_nulldummy.py22
-rwxr-xr-xtest/functional/feature_proxy.py10
-rwxr-xr-xtest/functional/feature_pruning.py227
-rwxr-xr-xtest/functional/feature_rbf.py108
-rwxr-xr-xtest/functional/feature_segwit.py114
-rwxr-xr-xtest/functional/feature_versionbits_warning.py10
-rwxr-xr-xtest/functional/interface_bitcoin_cli.py10
-rwxr-xr-xtest/functional/interface_http.py28
-rwxr-xr-xtest/functional/interface_rest.py6
-rwxr-xr-xtest/functional/interface_rpc.py19
-rwxr-xr-xtest/functional/interface_zmq.py15
-rwxr-xr-xtest/functional/mempool_accept.py63
-rwxr-xr-xtest/functional/mempool_limit.py6
-rwxr-xr-xtest/functional/mempool_packages.py34
-rwxr-xr-xtest/functional/mempool_persist.py17
-rwxr-xr-xtest/functional/mempool_resurrect.py8
-rwxr-xr-xtest/functional/mining_basic.py47
-rwxr-xr-xtest/functional/mining_getblocktemplate_longpoll.py12
-rwxr-xr-xtest/functional/mining_prioritisetransaction.py28
-rwxr-xr-xtest/functional/p2p_blocksonly.py58
-rwxr-xr-xtest/functional/p2p_compactblocks.py269
-rwxr-xr-xtest/functional/p2p_feefilter.py16
-rwxr-xr-xtest/functional/p2p_invalid_messages.py14
-rwxr-xr-xtest/functional/p2p_leak.py8
-rwxr-xr-xtest/functional/p2p_node_network_limited.py18
-rwxr-xr-xtest/functional/p2p_segwit.py232
-rwxr-xr-xtest/functional/p2p_sendheaders.py7
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py18
-rwxr-xr-xtest/functional/rpc_bind.py2
-rwxr-xr-xtest/functional/rpc_blockchain.py8
-rwxr-xr-xtest/functional/rpc_createmultisig.py76
-rwxr-xr-xtest/functional/rpc_decodescript.py18
-rwxr-xr-xtest/functional/rpc_deprecated.py2
-rwxr-xr-xtest/functional/rpc_deriveaddresses.py2
-rwxr-xr-xtest/functional/rpc_fundrawtransaction.py33
-rwxr-xr-xtest/functional/rpc_getblockfilter.py59
-rwxr-xr-xtest/functional/rpc_getblockstats.py47
-rwxr-xr-xtest/functional/rpc_getchaintips.py5
-rwxr-xr-xtest/functional/rpc_invalidateblock.py7
-rwxr-xr-xtest/functional/rpc_misc.py8
-rwxr-xr-xtest/functional/rpc_named_arguments.py4
-rwxr-xr-xtest/functional/rpc_preciousblock.py13
-rwxr-xr-xtest/functional/rpc_psbt.py42
-rwxr-xr-xtest/functional/rpc_rawtransaction.py71
-rwxr-xr-xtest/functional/rpc_scantxoutset.py11
-rwxr-xr-xtest/functional/rpc_signmessage.py10
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py7
-rwxr-xr-xtest/functional/rpc_uptime.py4
-rw-r--r--test/functional/test_framework/address.py18
-rw-r--r--test/functional/test_framework/authproxy.py33
-rw-r--r--test/functional/test_framework/blocktools.py7
-rw-r--r--test/functional/test_framework/key.py574
-rwxr-xr-xtest/functional/test_framework/messages.py29
-rwxr-xr-xtest/functional/test_framework/mininode.py19
-rw-r--r--test/functional/test_framework/netutil.py10
-rw-r--r--test/functional/test_framework/script.py9
-rw-r--r--test/functional/test_framework/socks5.py4
-rwxr-xr-xtest/functional/test_framework/test_framework.py126
-rwxr-xr-xtest/functional/test_framework/test_node.py31
-rw-r--r--test/functional/test_framework/util.py25
-rwxr-xr-xtest/functional/test_runner.py39
-rwxr-xr-xtest/functional/wallet_abandonconflict.py10
-rwxr-xr-xtest/functional/wallet_address_types.py68
-rwxr-xr-xtest/functional/wallet_avoidreuse.py241
-rwxr-xr-xtest/functional/wallet_backup.py25
-rwxr-xr-xtest/functional/wallet_balance.py146
-rwxr-xr-xtest/functional/wallet_basic.py60
-rwxr-xr-xtest/functional/wallet_bumpfee.py92
-rwxr-xr-xtest/functional/wallet_create_tx.py2
-rwxr-xr-xtest/functional/wallet_createwallet.py31
-rwxr-xr-xtest/functional/wallet_disable.py6
-rwxr-xr-xtest/functional/wallet_dump.py6
-rwxr-xr-xtest/functional/wallet_hd.py2
-rwxr-xr-xtest/functional/wallet_import_rescan.py38
-rwxr-xr-xtest/functional/wallet_importmulti.py53
-rwxr-xr-xtest/functional/wallet_keypool.py10
-rwxr-xr-xtest/functional/wallet_keypool_topup.py11
-rwxr-xr-xtest/functional/wallet_listreceivedby.py5
-rwxr-xr-xtest/functional/wallet_listsinceblock.py5
-rwxr-xr-xtest/functional/wallet_listtransactions.py32
-rwxr-xr-xtest/functional/wallet_multiwallet.py2
-rwxr-xr-xtest/functional/wallet_resendwallettransactions.py71
-rwxr-xr-xtest/functional/wallet_txn_clone.py10
-rwxr-xr-xtest/functional/wallet_txn_doublespend.py7
-rwxr-xr-xtest/fuzz/test_runner.py4
-rwxr-xr-xtest/lint/check-doc.py36
-rwxr-xr-xtest/lint/lint-all.sh8
-rwxr-xr-xtest/lint/lint-circular-dependencies.sh12
-rwxr-xr-xtest/lint/lint-format-strings.py56
-rwxr-xr-xtest/lint/lint-format-strings.sh1
-rwxr-xr-xtest/lint/lint-locale-dependence.sh6
-rwxr-xr-xtest/lint/lint-python-dead-code.sh2
-rwxr-xr-xtest/lint/lint-python.sh8
-rw-r--r--test/lint/lint-spelling.ignore-words.txt7
-rw-r--r--test/sanitizer_suppressions/lsan3
-rw-r--r--test/sanitizer_suppressions/ubsan1
651 files changed, 17954 insertions, 12043 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index ac39fe235b..ea587b78d4 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -38,16 +38,6 @@ after_build:
- ps: fsutil behavior set disablelastaccess 1 # Disable Access time feature on Windows (better performance)
- ps: clcache -z
before_test:
-- ps: ${conf_ini} = (Get-Content([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini.in")))
-- ps: ${conf_ini} = ${conf_ini}.Replace("@abs_top_srcdir@", ${env:APPVEYOR_BUILD_FOLDER})
-- ps: ${conf_ini} = ${conf_ini}.Replace("@abs_top_builddir@", ${env:APPVEYOR_BUILD_FOLDER})
-- ps: ${conf_ini} = ${conf_ini}.Replace("@EXEEXT@", ".exe")
-- ps: ${conf_ini} = ${conf_ini}.Replace("@ENABLE_WALLET_TRUE@", "")
-- ps: ${conf_ini} = ${conf_ini}.Replace("@BUILD_BITCOIN_CLI_TRUE@", "")
-- ps: ${conf_ini} = ${conf_ini}.Replace("@BUILD_BITCOIND_TRUE@", "")
-- ps: ${conf_ini} = ${conf_ini}.Replace("@ENABLE_ZMQ_TRUE@", "")
-- ps: ${utf8} = New-Object System.Text.UTF8Encoding ${false}
-- ps: '[IO.File]::WriteAllLines([IO.Path]::Combine(${env:APPVEYOR_BUILD_FOLDER}, "test", "config.ini"), ${conf_ini}, ${utf8})'
- ps: move "build_msvc\${env:PLATFORM}\${env:CONFIGURATION}\*.exe" src
test_script:
- cmd: src\test_bitcoin.exe -k stdout -e stdout 2> NUL
diff --git a/.cirrus.yml b/.cirrus.yml
index 9104a0a3d1..ce17a223b1 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -2,15 +2,18 @@ task:
name: "FreeBsd 12.0 amd64 [GOAL: install] [no depends, only system libs]"
freebsd_instance:
image: freebsd-12-0-release-amd64
- ccache_cache:
- folder: "/tmp/ccache_dir"
+ cpu: 8
+ memory: 8G
+ timeout_in: 60m
env:
- MAKEJOBS: "-j3"
+ MAKEJOBS: "-j9"
CONFIGURE_OPTS: "--disable-dependency-tracking"
GOAL: "install"
CCACHE_SIZE: "200M"
CCACHE_COMPRESS: 1
CCACHE_DIR: "/tmp/ccache_dir"
+ ccache_cache:
+ folder: "/tmp/ccache_dir"
install_script:
- pkg install -y autoconf automake boost-libs git gmake libevent libtool openssl pkgconf python3 ccache
- ./contrib/install_db4.sh $(pwd)
@@ -23,4 +26,4 @@ task:
check_script:
- gmake check ${MAKEJOBS} VERBOSE=1
functional_test_script:
- - ./test/functional/test_runner.py --ci --combinedlogslen=1000 --quiet --failfast
+ - ./test/functional/test_runner.py --jobs 9 --ci --extended --exclude feature_dbcrash --combinedlogslen=1000 --quiet --failfast
diff --git a/.gitignore b/.gitignore
index 994d67402f..3ebf00ed52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,10 +62,10 @@ src/qt/bitcoin-qt.includes
*.pyc
*.o
*.o-*
-*.patch
*.a
*.pb.cc
*.pb.h
+*.dat
*.log
*.trs
@@ -74,6 +74,10 @@ src/qt/bitcoin-qt.includes
*.json.h
*.raw.h
+# Only ignore unexpected patches
+*.patch
+!depends/patches/*.patch
+
#libtool object files
*.lo
*.la
@@ -120,3 +124,6 @@ contrib/devtools/split-debug.sh
# Output from running db4 installation
db4/
+
+# clang-check
+*.plist
diff --git a/.python-version b/.python-version
index 7bcbb3808b..c49282585a 100644
--- a/.python-version
+++ b/.python-version
@@ -1 +1 @@
-3.4.9
+3.5.6
diff --git a/.style.yapf b/.style.yapf
index fe6227baf6..69d8c6aee4 100644
--- a/.style.yapf
+++ b/.style.yapf
@@ -55,7 +55,7 @@ blank_line_before_nested_class_or_def=False
coalesce_brackets=False
# The column limit.
-column_limit=79
+column_limit=160
# The style for continuation alignment. Possible values are:
#
diff --git a/.travis.yml b/.travis.yml
index 0ede31b4a6..adf2140642 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,38 @@
+# The test build matrix (stage: test) is constructed to test a wide range of
+# configurations, rather than a single pass/fail. This helps to catch build
+# failures and logic errors that present on platforms other than the ones the
+# author has tested.
+#
+# Some builders use the dependency-generator in `./depends`, rather than using
+# apt-get to install build dependencies. This guarantees that the tester is
+# using the same versions as Gitian, so the build results are nearly identical
+# to what would be found in a final release.
+#
+# In order to avoid rebuilding all dependencies for each build, the binaries
+# are cached and re-used when possible. Changes in the dependency-generator
+# will trigger cache-invalidation and rebuilds as necessary.
+#
+# These caches can be manually removed if necessary. This is one of the very
+# few manual operations that is possible with Travis, and it can be done by a
+# Bitcoin Core GitHub member via the Travis web interface [0].
+#
+# Travis CI uploads the cache after the script phase of the build [1].
+# However, the build is terminated without saving the chache if it takes over
+# 50 minutes [2]. Thus, if we spent too much time in early build stages, fail
+# with an error and save the cache.
+#
+# [0] https://travis-ci.org/bitcoin/bitcoin/caches
+# [1] https://docs.travis-ci.com/user/caching/#build-phases
+# [2] https://docs.travis-ci.com/user/customizing-the-build#build-timeouts
+
dist: xenial
os: linux
language: minimal
cache:
ccache: true
directories:
- - depends/built
- - depends/sdk-sources
+ - $TRAVIS_BUILD_DIR/depends/built
+ - $TRAVIS_BUILD_DIR/depends/sdk-sources
- $HOME/.ccache
stages:
- lint
@@ -26,6 +53,7 @@ env:
- SDK_URL=https://bitcoincore.org/depends-sources/sdks
- WINEDEBUG=fixme-all
- DOCKER_PACKAGES="build-essential libtool autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache"
+ - CACHE_ERR_MSG="Error! Initial build successful, but not enough time remains to run later build stages and tests. Please manually re-run this job by using the travis restart button or asking a bitcoin maintainer to restart. The next run should not time out because the build cache has been saved."
before_install:
- set -o errexit; source .travis/test_03_before_install.sh
install:
@@ -33,8 +61,11 @@ install:
before_script:
- set -o errexit; source .travis/test_05_before_script.sh
script:
- - if [ $SECONDS -gt 1200 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script_a.sh; fi
- - if [ $SECONDS -gt 1800 ]; then set +o errexit; echo "Travis early exit to cache current state"; false; else set -o errexit; source .travis/test_06_script_b.sh; fi
+ - export CONTINUE=1
+ - if [ $SECONDS -gt 1200 ]; then export CONTINUE=0; fi # Likely the depends build took very long
+ - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_a.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
+ - if [ $SECONDS -gt 2000 ]; then export CONTINUE=0; fi # Likely the build took very long; The tests take about 1000s, so we should abort if we have less than 50*60-1000=2000s left
+ - if [ $CONTINUE = "1" ]; then set -o errexit; source .travis/test_06_script_b.sh; else set +o errexit; echo "$CACHE_ERR_MSG"; false; fi
after_script:
- echo $TRAVIS_COMMIT_RANGE
- echo $TRAVIS_COMMIT_LOG
@@ -46,7 +77,7 @@ jobs:
env:
cache: false
language: python
- python: '3.4' # Oldest supported version according to doc/dependencies.md
+ python: '3.5' # Oldest supported version according to doc/dependencies.md
install:
- set -o errexit; source .travis/lint_04_install.sh
before_script:
@@ -67,16 +98,6 @@ jobs:
BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi"
- stage: test
- name: 'Win32 [GOAL: deploy] [no gui or functional tests]'
- env: >-
- HOST=i686-w64-mingw32
- DPKG_ADD_ARCH="i386"
- PACKAGES="python3 nsis g++-mingw-w64-i686 wine-binfmt wine32"
- RUN_FUNCTIONAL_TESTS=false
- GOAL="deploy"
- BITCOIN_CONFIG="--enable-reduce-exports --disable-gui-tests"
-
- - stage: test
name: 'Win64 [GOAL: deploy] [no gui or functional tests]'
env: >-
HOST=x86_64-w64-mingw32
@@ -100,6 +121,7 @@ jobs:
HOST=x86_64-unknown-linux-gnu
PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev"
DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
+ TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
GOAL="install"
BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CXXFLAGS=\"-g0 -O2\""
@@ -158,7 +180,7 @@ jobs:
name: 'macOS 10.10 [GOAL: deploy] [no functional tests]'
env: >-
HOST=x86_64-apple-darwin14
- PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
+ PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools"
OSX_SDK=10.11
RUN_UNIT_TESTS=false
RUN_FUNCTIONAL_TESTS=false
diff --git a/.travis/lint_04_install.sh b/.travis/lint_04_install.sh
index 9a22773e57..62174620f2 100755
--- a/.travis/lint_04_install.sh
+++ b/.travis/lint_04_install.sh
@@ -6,7 +6,7 @@
export LC_ALL=C
-travis_retry pip install codespell==1.13.0
+travis_retry pip install codespell==1.15.0
travis_retry pip install flake8==3.5.0
travis_retry pip install vulture==0.29
diff --git a/.travis/lint_06_script.sh b/.travis/lint_06_script.sh
index 701e6d8005..eeebc80ec0 100755
--- a/.travis/lint_06_script.sh
+++ b/.travis/lint_06_script.sh
@@ -20,6 +20,6 @@ test/lint/lint-all.sh
if [ "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_EVENT_TYPE" = "cron" ]; then
git log --merges --before="2 days ago" -1 --format='%H' > ./contrib/verify-commits/trusted-sha512-root-commit
- while read -r LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys &&
- travis_wait 50 contrib/verify-commits/verify-commits.py --clean-merge=2;
+ travis_retry gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys $(<contrib/verify-commits/trusted-keys) &&
+ ./contrib/verify-commits/verify-commits.py --clean-merge=2;
fi
diff --git a/.travis/test_04_install.sh b/.travis/test_04_install.sh
index 8055bbdd19..b589ee7a16 100755
--- a/.travis/test_04_install.sh
+++ b/.travis/test_04_install.sh
@@ -29,10 +29,6 @@ DOCKER_EXEC () {
docker exec $DOCKER_ID bash -c "cd $PWD && $*"
}
-if [ -n "$DPKG_ADD_ARCH" ]; then
- DOCKER_EXEC dpkg --add-architecture "$DPKG_ADD_ARCH"
-fi
-
travis_retry DOCKER_EXEC apt-get update
travis_retry DOCKER_EXEC apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES $DOCKER_PACKAGES
diff --git a/.travis/test_06_script_b.sh b/.travis/test_06_script_b.sh
index e13abfd52f..e40055a6ee 100755
--- a/.travis/test_06_script_b.sh
+++ b/.travis/test_06_script_b.sh
@@ -16,7 +16,7 @@ fi
if [ "$RUN_FUNCTIONAL_TESTS" = "true" ]; then
BEGIN_FOLD functional-tests
- DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 --coverage --quiet --failfast
+ DOCKER_EXEC test/functional/test_runner.py --ci --combinedlogslen=4000 ${TEST_RUNNER_EXTRA} --quiet --failfast
END_FOLD
fi
@@ -25,3 +25,5 @@ if [ "$RUN_FUZZ_TESTS" = "true" ]; then
DOCKER_EXEC test/fuzz/test_runner.py -l DEBUG ${DIR_FUZZ_IN}
END_FOLD
fi
+
+cd ${TRAVIS_BUILD_DIR} || (echo "could not enter travis build dir $TRAVIS_BUILD_DIR"; exit 1)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 139fe7dc52..a2456f5b8c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -62,7 +62,7 @@ Commit messages should be verbose by default consisting of a short subject line
paragraph(s), unless the title alone is self-explanatory (like "Corrected typo
in init.cpp") in which case a single title line is sufficient. Commit messages should be
helpful to people reading your code in the future, so explain the reasoning for
-your decisions. Further explanation [here](http://chris.beams.io/posts/git-commit/).
+your decisions. Further explanation [here](https://chris.beams.io/posts/git-commit/).
If a particular commit references another issue, please add the reference. For
example: `refs #1234` or `fixes #4321`. Using the `fixes` or `closes` keywords
@@ -220,6 +220,7 @@ In general, all pull requests must:
- Not break the existing test suite;
- Where bugs are fixed, where possible, there should be unit tests
demonstrating the bug and also proving the fix. This helps prevent regression.
+ - Change relevant comments and documentation when behaviour of code changes.
Patches that change Bitcoin consensus rules are considerably more involved than
normal because they affect the entire ecosystem and so must be preceded by
@@ -236,21 +237,35 @@ request. Typically reviewers will review the code for obvious errors, as well as
test out the patch set and opine on the technical merits of the patch. Project
maintainers take into account the peer review when determining if there is
consensus to merge a pull request (remember that discussions may have been
-spread out over GitHub, mailing list and IRC discussions). The following
+spread out over GitHub, mailing list and IRC discussions).
+
+#### Conceptual Review
+
+A review can be a conceptual review, where the reviewer leaves a comment
+ * `Concept (N)ACK`, meaning "I do (not) agree in the general goal of this pull
+ request",
+ * `Approach (N)ACK`, meaning `Concept ACK`, but "I do (not) agree with the
+ approach of this change".
+
+A `NACK` needs to include a rationale why the change is not worthwhile.
+NACKs without accompanying reasoning may be disregarded.
+
+#### Code Review
+
+After conceptual agreement on the change, code review can be provided. It is
+starting with `ACK BRANCH_COMMIT`, where `BRANCH_COMMIT` is the top of the
+topic branch. The review is followed by a description of how the reviewer did
+the review. The following
language is used within pull-request comments:
- - ACK means "I have tested the code and I agree it should be merged";
- - NACK means "I disagree this should be merged", and must be accompanied by
- sound technical justification (or in certain cases of copyright/patent/licensing
- issues, legal justification). NACKs without accompanying reasoning may be
- disregarded;
- - utACK means "I have not tested the code, but I have reviewed it and it looks
+ - "I have tested the code", involving
+ change-specific manual testing in addition to running the unit and functional
+ tests, and in case it is not obvious how the manual testing was done, it should
+ be described;
+ - "I have not tested the code, but I have reviewed it and it looks
OK, I agree it can be merged";
- - Concept ACK means "I agree in the general principle of this pull request";
- Nit refers to trivial, often non-blocking issues.
-Reviewers should include the commit hash which they reviewed in their comments.
-
Project maintainers reserve the right to weigh the opinions of peer reviewers
using common sense judgement and also may weight based on meritocracy: Those
that have demonstrated a deeper commitment and understanding towards the project
diff --git a/Makefile.am b/Makefile.am
index 85674f819a..712f2a454d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,6 +43,7 @@ DIST_DOCS = $(wildcard doc/*.md) $(wildcard doc/release-notes/*.md)
DIST_CONTRIB = $(top_srcdir)/contrib/bitcoin-cli.bash-completion \
$(top_srcdir)/contrib/bitcoin-tx.bash-completion \
$(top_srcdir)/contrib/bitcoind.bash-completion \
+ $(top_srcdir)/contrib/debian/copyright \
$(top_srcdir)/contrib/init \
$(top_srcdir)/contrib/install_db4.sh
DIST_SHARE = \
@@ -197,7 +198,7 @@ test_bitcoin_filtered.info: test_bitcoin.info
$(LCOV) -a $@ $(LCOV_OPTS) -o $@
functional_test.info: test_bitcoin_filtered.info
- -@TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)
+ @TIMEOUT=15 test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS)
$(LCOV) -c $(LCOV_OPTS) -d $(abs_builddir)/src --t functional-tests -o $@
$(LCOV) -z $(LCOV_OPTS) -d $(abs_builddir)/src
diff --git a/README.md b/README.md
index db79043665..28ee95ee7c 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,6 @@
Bitcoin Core integration/staging tree
=====================================
-[![Build Status](https://travis-ci.org/bitcoin/bitcoin.svg?branch=master)](https://travis-ci.org/bitcoin/bitcoin)
-
https://bitcoincore.org
What is Bitcoin?
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000000..7ed96c7cea
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,20 @@
+# Security Policy
+
+## Supported Versions
+
+See our website for versions of Bitcoin Core that are currently supported with
+security updates: https://bitcoincore.org/en/lifecycle/#schedule
+
+## Reporting a Vulnerability
+
+To report security issues send an email to security@bitcoincore.org (not for support).
+
+The following keys may be used to communicate sensitive information to developers:
+
+| Name | Fingerprint |
+|------|-------------|
+| Wladimir van der Laan | 71A3 B167 3540 5025 D447 E8F2 7481 0B01 2346 C9A6 |
+| Jonas Schnelli | 32EE 5C4C 3FA1 5CCA DB46 ABE5 29D4 BCB6 416F 53EC |
+| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
+
+You can import a key by running the following command with that individual’s fingerprint: `gpg --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.
diff --git a/build-aux/m4/ax_boost_base.m4 b/build-aux/m4/ax_boost_base.m4
index 650c94fa64..d540395763 100644
--- a/build-aux/m4/ax_boost_base.m4
+++ b/build-aux/m4/ax_boost_base.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html
+# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html
# ===========================================================================
#
# SYNOPSIS
@@ -33,7 +33,15 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 27
+#serial 45
+
+# example boost program (need to pass version)
+m4_define([_AX_BOOST_BASE_PROGRAM],
+ [AC_LANG_PROGRAM([[
+#include <boost/version.hpp>
+]],[[
+(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))]));
+]])])
AC_DEFUN([AX_BOOST_BASE],
[
@@ -44,110 +52,121 @@ AC_ARG_WITH([boost],
or disable it (ARG=no)
@<:@ARG=yes@:>@ ])],
[
- if test "$withval" = "no"; then
- want_boost="no"
- elif test "$withval" = "yes"; then
- want_boost="yes"
- ac_boost_path=""
- else
- want_boost="yes"
- ac_boost_path="$withval"
- fi
+ AS_CASE([$withval],
+ [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""],
+ [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""],
+ [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"])
],
[want_boost="yes"])
AC_ARG_WITH([boost-libdir],
- AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
- [Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]),
- [
- if test -d "$withval"
- then
- ac_boost_lib_path="$withval"
- else
- AC_MSG_ERROR(--with-boost-libdir expected directory name)
- fi
- ],
- [ac_boost_lib_path=""]
-)
+ [AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
+ [Force given directory for boost libraries.
+ Note that this will override library path detection,
+ so use this parameter only if default library detection fails
+ and you know exactly where your boost libraries are located.])],
+ [
+ AS_IF([test -d "$withval"],
+ [_AX_BOOST_BASE_boost_lib_path="$withval"],
+ [AC_MSG_ERROR([--with-boost-libdir expected directory name])])
+ ],
+ [_AX_BOOST_BASE_boost_lib_path=""])
-if test "x$want_boost" = "xyes"; then
- boost_lib_version_req=ifelse([$1], ,1.20.0,$1)
- boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'`
- boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'`
- boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'`
- boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
- if test "x$boost_lib_version_req_sub_minor" = "x" ; then
- boost_lib_version_req_sub_minor="0"
- fi
- WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor`
- AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req)
+BOOST_LDFLAGS=""
+BOOST_CPPFLAGS=""
+AS_IF([test "x$want_boost" = "xyes"],
+ [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])])
+AC_SUBST(BOOST_CPPFLAGS)
+AC_SUBST(BOOST_LDFLAGS)
+])
+
+
+# convert a version string in $2 to numeric and affect to polymorphic var $1
+AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[
+ AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"])
+ _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'`
+ _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'`
+ AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"],
+ [AC_MSG_ERROR([You should at least specify libboost major version])])
+ _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'`
+ AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"],
+ [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"])
+ _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
+ AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"],
+ [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"])
+ _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor`
+ AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET)
+])
+
+dnl Run the detection of boost should be run only if $want_boost
+AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
+ _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1])
succeeded=no
+
+ AC_REQUIRE([AC_CANONICAL_HOST])
dnl On 64-bit systems check for system libraries in both lib64 and lib.
dnl The former is specified by FHS, but e.g. Debian does not adhere to
dnl this (as it rises problems for generic multi-arch support).
dnl The last entry in the list is chosen by default when no libraries
dnl are found, e.g. when only header-only libraries are installed!
- libsubdirs="lib"
- ax_arch=`uname -m`
- case $ax_arch in
- x86_64)
- libsubdirs="lib64 libx32 lib lib64"
- ;;
- ppc64|s390x|sparc64|aarch64|ppc64le)
- libsubdirs="lib64 lib lib64"
- ;;
- esac
+ AS_CASE([${host_cpu}],
+ [x86_64],[libsubdirs="lib64 libx32 lib lib64"],
+ [ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64],[libsubdirs="lib64 lib lib64"],
+ [libsubdirs="lib"]
+ )
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
dnl them priority over the other paths since, if libs are found there, they
dnl are almost assuredly the ones desired.
- AC_REQUIRE([AC_CANONICAL_HOST])
- libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs"
-
- case ${host_cpu} in
- i?86)
- libsubdirs="lib/i386-${host_os} $libsubdirs"
- ;;
- esac
-
- dnl some arches may advertise a cpu type that doesn't line up with their
- dnl prefix's cpu type. For example, uname may report armv7l while libs are
- dnl installed to /usr/lib/arm-linux-gnueabihf. Try getting the compiler's
- dnl value for an extra chance of finding the correct path.
- libsubdirs="lib/`$CXX -dumpmachine 2>/dev/null` $libsubdirs"
+ AS_CASE([${host_cpu}],
+ [i?86],[multiarch_libsubdir="lib/i386-${host_os}"],
+ [multiarch_libsubdir="lib/${host_cpu}-${host_os}"]
+ )
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
- if test "$ac_boost_path" != ""; then
- BOOST_CPPFLAGS="-I$ac_boost_path/include"
- for ac_boost_path_tmp in $libsubdirs; do
- if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then
- BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp"
- break
- fi
- done
- elif test "$cross_compiling" != yes; then
- for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
- if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then
- for libsubdir in $libsubdirs ; do
- if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
+ AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[
+ AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"])
+ AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[
+ AC_MSG_RESULT([yes])
+ BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include"
+ for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do
+ AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"])
+ AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[
+ AC_MSG_RESULT([yes])
+ BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp";
+ break;
+ ],
+ [AC_MSG_RESULT([no])])
+ done],[
+ AC_MSG_RESULT([no])])
+ ],[
+ if test X"$cross_compiling" = Xyes; then
+ search_libsubdirs=$multiarch_libsubdir
+ else
+ search_libsubdirs="$multiarch_libsubdir $libsubdirs"
+ fi
+ for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do
+ if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then
+ for libsubdir in $search_libsubdirs ; do
+ if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
- BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir"
- BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include"
+ BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir"
+ BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include"
break;
fi
done
- fi
+ ])
dnl overwrite ld flags if we have required special directory with
dnl --with-boost-libdir parameter
- if test "$ac_boost_lib_path" != ""; then
- BOOST_LDFLAGS="-L$ac_boost_lib_path"
- fi
+ AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"],
+ [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"])
+ AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)])
CPPFLAGS_SAVED="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
export CPPFLAGS
@@ -158,15 +177,7 @@ if test "x$want_boost" = "xyes"; then
AC_REQUIRE([AC_PROG_CXX])
AC_LANG_PUSH(C++)
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- @%:@include <boost/version.hpp>
- ]], [[
- #if BOOST_VERSION >= $WANT_BOOST_VERSION
- // Everything is okay
- #else
- # error Boost version is too old
- #endif
- ]])],[
+ AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
@@ -178,40 +189,50 @@ if test "x$want_boost" = "xyes"; then
dnl if we found no boost with system layout we search for boost libraries
dnl built and installed without the --layout=system option or for a staged(not installed) version
- if test "x$succeeded" != "xyes"; then
+ if test "x$succeeded" != "xyes" ; then
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
BOOST_CPPFLAGS=
- BOOST_LDFLAGS=
+ if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
+ BOOST_LDFLAGS=
+ fi
_version=0
- if test "$ac_boost_path" != ""; then
- if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
- for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
- _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
+ if test -n "$_AX_BOOST_BASE_boost_path" ; then
+ if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then
+ for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
+ _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
- if test "$V_CHECK" = "1" ; then
+ if test "x$V_CHECK" = "x1" ; then
_version=$_version_tmp
fi
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
- BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
+ BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE"
done
dnl if nothing found search for layout used in Windows distributions
if test -z "$BOOST_CPPFLAGS"; then
- if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
- BOOST_CPPFLAGS="-I$ac_boost_path"
+ if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then
+ BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path"
fi
fi
+ dnl if we found something and BOOST_LDFLAGS was unset before
+ dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here.
+ if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then
+ for libsubdir in $libsubdirs ; do
+ if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
+ done
+ BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir"
+ fi
fi
else
- if test "$cross_compiling" != yes; then
- for ac_boost_path in /usr /usr/local /opt /opt/local ; do
- if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
- for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do
- _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
+ if test "x$cross_compiling" != "xyes" ; then
+ for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do
+ if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then
+ for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
+ _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
V_CHECK=`expr $_version_tmp \> $_version`
- if test "$V_CHECK" = "1" ; then
+ if test "x$V_CHECK" = "x1" ; then
_version=$_version_tmp
- best_path=$ac_boost_path
+ best_path=$_AX_BOOST_BASE_boost_path
fi
done
fi
@@ -219,7 +240,7 @@ if test "x$want_boost" = "xyes"; then
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
- if test "$ac_boost_lib_path" = ""; then
+ if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
for libsubdir in $libsubdirs ; do
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
@@ -227,7 +248,7 @@ if test "x$want_boost" = "xyes"; then
fi
fi
- if test "x$BOOST_ROOT" != "x"; then
+ if test -n "$BOOST_ROOT" ; then
for libsubdir in $libsubdirs ; do
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
done
@@ -236,7 +257,7 @@ if test "x$want_boost" = "xyes"; then
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
V_CHECK=`expr $stage_version_shorten \>\= $_version`
- if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then
+ if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
BOOST_CPPFLAGS="-I$BOOST_ROOT"
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
@@ -251,15 +272,7 @@ if test "x$want_boost" = "xyes"; then
export LDFLAGS
AC_LANG_PUSH(C++)
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- @%:@include <boost/version.hpp>
- ]], [[
- #if BOOST_VERSION >= $WANT_BOOST_VERSION
- // Everything is okay
- #else
- # error Boost version is too old
- #endif
- ]])],[
+ AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
AC_MSG_RESULT(yes)
succeeded=yes
found_system=yes
@@ -268,17 +281,15 @@ if test "x$want_boost" = "xyes"; then
AC_LANG_POP([C++])
fi
- if test "$succeeded" != "yes" ; then
- if test "$_version" = "0" ; then
- AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
+ if test "x$succeeded" != "xyes" ; then
+ if test "x$_version" = "x0" ; then
+ AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
else
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
fi
# execute ACTION-IF-NOT-FOUND (if present):
ifelse([$3], , :, [$3])
else
- AC_SUBST(BOOST_CPPFLAGS)
- AC_SUBST(BOOST_LDFLAGS)
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
# execute ACTION-IF-FOUND (if present):
ifelse([$2], , :, [$2])
@@ -286,6 +297,5 @@ if test "x$want_boost" = "xyes"; then
CPPFLAGS="$CPPFLAGS_SAVED"
LDFLAGS="$LDFLAGS_SAVED"
-fi
])
diff --git a/build-aux/m4/ax_boost_system.m4 b/build-aux/m4/ax_boost_system.m4
index 1c05450cbe..207d7be8de 100644
--- a/build-aux/m4/ax_boost_system.m4
+++ b/build-aux/m4/ax_boost_system.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html
+# https://www.gnu.org/software/autoconf-archive/ax_boost_system.html
# ===========================================================================
#
# SYNOPSIS
@@ -31,7 +31,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 18
+#serial 19
AC_DEFUN([AX_BOOST_SYSTEM],
[
@@ -84,7 +84,6 @@ AC_DEFUN([AX_BOOST_SYSTEM],
LDFLAGS_SAVE=$LDFLAGS
if test "x$ax_boost_user_system_lib" = "x"; then
- ax_lib=
for libextension in `ls -r $BOOSTLIBDIR/libboost_system* 2>/dev/null | sed 's,.*/lib,,' | sed 's,\..*,,'` ; do
ax_lib=${libextension}
AC_CHECK_LIB($ax_lib, exit,
@@ -109,7 +108,7 @@ AC_DEFUN([AX_BOOST_SYSTEM],
fi
if test "x$ax_lib" = "x"; then
- AC_MSG_ERROR(Could not find a version of the boost_system library!)
+ AC_MSG_ERROR(Could not find a version of the library!)
fi
if test "x$link_system" = "xno"; then
AC_MSG_ERROR(Could not link against $ax_lib !)
diff --git a/build_msvc/.gitignore b/build_msvc/.gitignore
index d5aa22c05e..8ba65dda8f 100644
--- a/build_msvc/.gitignore
+++ b/build_msvc/.gitignore
@@ -9,3 +9,4 @@ packages/*
*/x64
*.vcxproj.user
*.vcxproj
+*/Win32
diff --git a/build_msvc/README.md b/build_msvc/README.md
index 63c5babf35..d6543e6d67 100644
--- a/build_msvc/README.md
+++ b/build_msvc/README.md
@@ -17,16 +17,17 @@ Options for installing the dependencies in a Visual Studio compatible manner are
- Download the source code, build each dependency, add the required include paths, link libraries and binary tools to the Visual Studio project files.
- Use [nuget](https://www.nuget.org/) packages with the understanding that any binary files have been compiled by an untrusted third party.
-The external dependencies required for the Visual Studio build are (see the [dependencies doc](https://github.com/bitcoin/bitcoin/blob/master/doc/dependencies.md) for versions):
+The external dependencies required for the Visual Studio build are (see [dependencies.md](https://github.com/bitcoin/bitcoin/blob/master/doc/dependencies.md) for more info):
-- Berkeley DB,
-- OpenSSL,
-- Boost,
-- libevent,
+- Berkeley DB
+- OpenSSL
+- Boost
+- libevent
- ZeroMQ
+- RapidCheck
-Additional dependencies required from the [bitcoin-core](https://github.com/bitcoin-core) github repository are:
-- SECP256K1,
+Additional dependencies required from the [bitcoin-core](https://github.com/bitcoin-core) GitHub repository are:
+- libsecp256k1
- LevelDB
Building
@@ -37,7 +38,7 @@ The instructions below use `vcpkg` to install the dependencies.
- Install the required packages (replace x64 with x86 as required):
```
- PS >.\vcpkg install --triplet x64-windows-static boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb
+ PS >.\vcpkg install --triplet x64-windows-static boost-filesystem boost-signals2 boost-test libevent openssl zeromq berkeleydb secp256k1 leveldb rapidcheck
```
- Use Python to generate *.vcxproj from Makefile
diff --git a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
index 368fe7ead5..6ded6895cd 100644
--- a/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
+++ b/build_msvc/bench_bitcoin/bench_bitcoin.vcxproj
@@ -1,25 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{1125654E-E1B2-4431-8B5C-62EA9A2FEECB}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup>
+ <ConfigurationType>Application</ConfigurationType>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
<ItemGroup>
+ <ClCompile Include="..\..\src\test\util.cpp" />
+ <ClCompile Include="..\..\src\test\setup_common.cpp" />
<ClCompile Include="..\..\src\bench\base58.cpp" />
<ClCompile Include="..\..\src\bench\bech32.cpp" />
<ClCompile Include="..\..\src\bench\bench.cpp" />
@@ -32,8 +23,10 @@
<ClCompile Include="..\..\src\bench\examples.cpp" />
<ClCompile Include="..\..\src\bench\lockedpool.cpp" />
<ClCompile Include="..\..\src\bench\mempool_eviction.cpp" />
+ <ClCompile Include="..\..\src\bench\rpc_mempool.cpp" />
<ClCompile Include="..\..\src\bench\merkle_root.cpp" />
<ClCompile Include="..\..\src\bench\rollingbloom.cpp" />
+ <ClCompile Include="..\..\src\bench\wallet_balance.cpp" />
<ClCompile Include="..\..\src\bench\verify_script.cpp" />
</ItemGroup>
<ItemGroup>
@@ -68,143 +61,6 @@
<Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
</ProjectReference>
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{1125654E-E1B2-4431-8B5C-62EA9A2FEECB}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>bench_bitcoin</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NOMINMAX;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
<Target Name="RawBenchHeaderGen" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>There was an error executing the raw bench header generation task.</ErrorText>
@@ -214,6 +70,7 @@
</ItemGroup>
<HeaderFromHexdump RawFilePath="%(RawBenchFile.FullPath)" HeaderFilePath="%(RawBenchFile.FullPath).h" SourceHeader="static unsigned const char %(RawBenchFile.Filename)[] = {" SourceFooter="};" />
</Target>
- <Import Label="configTarget" Project="..\common.vcxproj" />
<Import Label="hexdumpTarget" Project="..\msbuild\tasks\hexdump.targets" />
-</Project>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj
index 6b668054a3..72c55e47cc 100644
--- a/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj
+++ b/build_msvc/bitcoin-cli/bitcoin-cli.vcxproj
@@ -1,31 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{0B2D7431-F876-4A58-87BF-F748338CD3BF}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup>
+ <ConfigurationType>Application</ConfigurationType>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bitcoin-cli.cpp" />
</ItemGroup>
<ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <ItemGroup>
<ProjectReference Include="..\libbitcoin_cli\libbitcoin_cli.vcxproj">
<Project>{0667528c-d734-4009-adf9-c0d6c4a5a5a6}</Project>
</ProjectReference>
@@ -39,138 +25,6 @@
<Project>{5724ba7d-a09a-4ba8-800b-c4c1561b3d69}</Project>
</ProjectReference>
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{0B2D7431-F876-4A58-87BF-F748338CD3BF}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>bitcoincli</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
index 1d0174e319..6891a3e5ad 100644
--- a/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
+++ b/build_msvc/bitcoin-tx/bitcoin-tx.vcxproj
@@ -1,24 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bitcoin-tx.cpp" />
</ItemGroup>
@@ -42,138 +31,6 @@
<Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
</ProjectReference>
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{D3022AF6-AD33-4CE3-B358-87CB6A1B29CF}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>bitcointx</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
index fa86da7bae..996676baf9 100644
--- a/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
+++ b/build_msvc/bitcoin-wallet/bitcoin-wallet.vcxproj
@@ -1,24 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{84DE8790-EDE3-4483-81AC-C32F15E861F4}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bitcoin-wallet.cpp" />
</ItemGroup>
@@ -60,138 +49,6 @@
<Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
</ProjectReference>
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{84DE8790-EDE3-4483-81AC-C32F15E861F4}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>bitcointx</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/bitcoin.sln b/build_msvc/bitcoin.sln
index 45bc934d77..5a6eaf54ad 100644
--- a/build_msvc/bitcoin.sln
+++ b/build_msvc/bitcoin.sln
@@ -1,10 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2027
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28803.452
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoin_consensus", "libbitcoinconsensus\libbitcoinconsensus.vcxproj", "{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbitcoinconsensus", "libbitcoinconsensus\libbitcoinconsensus.vcxproj", "{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_libbitcoinconsensus", "testconsensus\testconsensus.vcxproj", "{E78473E9-B850-456C-9120-276301E04C06}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testconsensus", "testconsensus\testconsensus.vcxproj", "{E78473E9-B850-456C-9120-276301E04C06}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bitcoind", "bitcoind\bitcoind.vcxproj", "{D4513DDF-6013-44DC-ADCC-12EAF6D1F038}"
EndProject
@@ -205,9 +205,6 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {4ABD1207-9A90-4EC9-A8EB-203638A2605D}
- SolutionGuid = {2FB733C9-24CB-4BA5-A26B-F43DAD7996B7}
- SolutionGuid = {D0CAE2D0-8DB1-4A0B-80EE-800AA6C64323}
SolutionGuid = {DA7D16A6-E5F0-45B3-B194-C3FE64F1BFCD}
EndGlobalSection
EndGlobal
diff --git a/build_msvc/bitcoin_config.h b/build_msvc/bitcoin_config.h
index 4ac27dae3f..ab13f73539 100644
--- a/build_msvc/bitcoin_config.h
+++ b/build_msvc/bitcoin_config.h
@@ -11,10 +11,10 @@
#define CLIENT_VERSION_IS_RELEASE false
/* Major version */
-#define CLIENT_VERSION_MAJOR 1
+#define CLIENT_VERSION_MAJOR 0
/* Minor version */
-#define CLIENT_VERSION_MINOR 17
+#define CLIENT_VERSION_MINOR 18
/* Build revision */
#define CLIENT_VERSION_REVISION 99
@@ -29,7 +29,7 @@
#define COPYRIGHT_HOLDERS_SUBSTITUTION "Bitcoin Core"
/* Copyright year */
-#define COPYRIGHT_YEAR 2018
+#define COPYRIGHT_YEAR 2019
/* Define to 1 to enable wallet functions */
#define ENABLE_WALLET 1
@@ -346,7 +346,7 @@
#define PACKAGE_NAME "Bitcoin Core"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "Bitcoin Core 0.17.99"
+#define PACKAGE_STRING "Bitcoin Core 0.18.99"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "bitcoin"
@@ -355,7 +355,7 @@
#define PACKAGE_URL "https://bitcoincore.org/"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.17.99"
+#define PACKAGE_VERSION "0.18.99"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
diff --git a/build_msvc/bitcoind/bitcoind.vcxproj b/build_msvc/bitcoind/bitcoind.vcxproj
index bb212af52e..c5cddfdbb2 100644
--- a/build_msvc/bitcoind/bitcoind.vcxproj
+++ b/build_msvc/bitcoind/bitcoind.vcxproj
@@ -1,153 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D4513DDF-6013-44DC-ADCC-12EAF6D1F038}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>bitcoind</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </Link>
- </ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\src\bitcoind.cpp" />
</ItemGroup>
@@ -183,5 +43,32 @@
<Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
</ProjectReference>
</ItemGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <Import Label="ReplaceInFile" Project="..\msbuild\tasks\replaceinfile.targets" />
+ <PropertyGroup>
+ <ConfigIniIn>..\..\test\config.ini.in</ConfigIniIn>
+ <ConfigIniOut>..\..\test\config.ini</ConfigIniOut>
+ </PropertyGroup>
+ <Target Name="AfterBuild">
+ <Copy SourceFiles="$(ConfigIniIn)" DestinationFiles="$(ConfigIniOut)" ></Copy>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@PACKAGE_NAME@" By="Bitcoin Core"></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@abs_top_srcdir@" By="..\.." ToFullPath="true"></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@abs_top_builddir@" By="..\.." ToFullPath="true"></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@EXEEXT@" By=".exe"></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@ENABLE_WALLET_TRUE@" By=""></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@BUILD_BITCOIN_CLI_TRUE@" By=""></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@BUILD_BITCOIND_TRUE@" By=""></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@ENABLE_FUZZ_TRUE@" By=""></ReplaceInFile>
+ <ReplaceInFile FilePath="$(ConfigIniOut)"
+ Replace="@ENABLE_ZMQ_TRUE@" By=""></ReplaceInFile>
+ </Target>
</Project>
diff --git a/build_msvc/common.init.vcxproj b/build_msvc/common.init.vcxproj
index c3c0f665c2..f08ac78b21 100644
--- a/build_msvc/common.init.vcxproj
+++ b/build_msvc/common.init.vcxproj
@@ -1,14 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' and !Exists('$(WindowsSdkDir)\DesignTime\CommonConfiguration\Neutral\Windows.props')">
- <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</WindowsTargetPlatformVersion_10>
- <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</WindowsTargetPlatformVersion_10>
- <!-- Sometimes the version in the registry has to .0 suffix, and sometimes it doesn't. Check and add it -->
- <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' != '' and !$(WindowsTargetPlatformVersion_10.EndsWith('.0'))">$(WindowsTargetPlatformVersion_10).0</WindowsTargetPlatformVersion_10>
-
- <WindowsTargetPlatformVersion>$(WindowsTargetPlatformVersion_10)</WindowsTargetPlatformVersion>
- </PropertyGroup>
- <PropertyGroup>
- <Platform Condition="'$(Platform)' == ''">Win32</Platform>
- </PropertyGroup>
-</Project> \ No newline at end of file
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
+ <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
+</PropertyGroup>
+
+ <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'=='' and !Exists('$(WindowsSdkDir)\DesignTime\CommonConfiguration\Neutral\Windows.props')">
+ <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</WindowsTargetPlatformVersion_10>
+ <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0@ProductVersion)</WindowsTargetPlatformVersion_10>
+ <!-- Sometimes the version in the registry has to .0 suffix, and sometimes it doesn't. Check and add it -->
+ <WindowsTargetPlatformVersion_10 Condition="'$(WindowsTargetPlatformVersion_10)' != '' and !$(WindowsTargetPlatformVersion_10.EndsWith('.0'))">$(WindowsTargetPlatformVersion_10).0</WindowsTargetPlatformVersion_10>
+ <WindowsTargetPlatformVersion>$(WindowsTargetPlatformVersion_10)</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+ <LinkIncremental>true</LinkIncremental>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <LinkIncremental>false</LinkIncremental>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
+ <IntDir>$(Platform)\$(Configuration)\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+
+<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
+ <DisableSpecificWarnings>4018;4221;4244;4267;4715;4805;</DisableSpecificWarnings>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <PreprocessorDefinitions>ZMQ_STATIC;NOMINMAX;WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;_WIN32_WINNT=0x0601;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="common.init.vcxproj.user" Condition="Exists('common.init.vcxproj.user')" />
+</Project>
diff --git a/build_msvc/common.vcxproj b/build_msvc/common.vcxproj
deleted file mode 100644
index 889dc6c2ad..0000000000
--- a/build_msvc/common.vcxproj
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <PropertyGroup>
- <BuildDependsOn>
- CopyBitcoinConfig;
- CopySecp256k1Config;
- $(BuildDependsOn);
- </BuildDependsOn>
- </PropertyGroup>
- <Target Name="CopyBitcoinConfig"
- Inputs="$(MSBuildThisFileDirectory)bitcoin_config.h"
- Outputs="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h">
- <Copy SourceFiles="$(MSBuildThisFileDirectory)bitcoin_config.h" DestinationFiles="$(MSBuildThisFileDirectory)..\src\config\bitcoin-config.h" />
- </Target>
- <Target Name="CopySecp256k1Config"
- Inputs="$(MSBuildThisFileDirectory)libsecp256k1_config.h"
- Outputs="$(MSBuildThisFileDirectory)..\src\secp256k1\src\libsecp256k1-config.h">
- <Copy SourceFiles="$(MSBuildThisFileDirectory)libsecp256k1_config.h" DestinationFiles="$(MSBuildThisFileDirectory)..\src\secp256k1\src\libsecp256k1-config.h" />
- </Target>
- <ItemDefinitionGroup>
- <ClCompile>
- <AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
- <DisableSpecificWarnings>4018;4244;4267;4715;4805;</DisableSpecificWarnings>
- <TreatWarningAsError>true</TreatWarningAsError>
- <PreprocessorDefinitions>_WIN32_WINNT=0x0601;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>..\..\src;..\..\src\univalue\include;..\..\src\secp256k1\include;..\..\src\leveldb\include;..\..\src\leveldb\helpers\memenv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- </ClCompile>
- </ItemDefinitionGroup>
-</Project>
diff --git a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in
index 5849e463a6..5f6cf608af 100644
--- a/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in
+++ b/build_msvc/libbitcoin_cli/libbitcoin_cli.vcxproj.in
@@ -1,158 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <ItemGroup>
-@SOURCE_FILES@
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{0667528C-D734-4009-ADF9-C0D6C4A5A5A6}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_cli</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup>
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
+ <ItemGroup>
+@SOURCE_FILES@
+ </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
index 292e193f5d..0bd9b3cd89 100644
--- a/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
+++ b/build_msvc/libbitcoin_common/libbitcoin_common.vcxproj.in
@@ -1,170 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{7C87E378-DF58-482E-AA2F-1BC129BC19CE}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_common</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- </ItemDefinitionGroup>
<ItemGroup>
@SOURCE_FILES@
</ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in
index e7002036ad..abf1a7ac02 100644
--- a/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in
+++ b/build_msvc/libbitcoin_crypto/libbitcoin_crypto.vcxproj.in
@@ -1,153 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{6190199C-6CF4-4DAD-BFBD-93FA72A760C1}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_crypto</RootNamespace>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
<ItemGroup>
@SOURCE_FILES@
</ItemGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
index 48a117bcfe..8e2ed394f8 100644
--- a/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
+++ b/build_msvc/libbitcoin_server/libbitcoin_server.vcxproj.in
@@ -1,162 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{460FEE33-1FE1-483F-B3BF-931FF8E969A5}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_server</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;HAVE_CONFIG_H;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemGroup>
+ <ItemGroup>
@SOURCE_FILES@
+ <ClCompile Include="..\..\src\wallet\init.cpp">
+ <ObjectFileName>$(IntDir)wallet_init.obj</ObjectFileName>
+ </ClCompile>
</ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\srcpcegister.h" />
- </ItemGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project> \ No newline at end of file
diff --git a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
index dbd91cf4db..71364d96b1 100644
--- a/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
+++ b/build_msvc/libbitcoin_util/libbitcoin_util.vcxproj.in
@@ -1,176 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_util</RootNamespace>
- <ProjectName>libbitcoin_util</ProjectName>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- <ProjectReference>
- <LinkLibraryDependencies>false</LinkLibraryDependencies>
- </ProjectReference>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- <ProjectReference>
- <LinkLibraryDependencies>false</LinkLibraryDependencies>
- </ProjectReference>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- <ProjectReference>
- <LinkLibraryDependencies>false</LinkLibraryDependencies>
- </ProjectReference>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalLibraryDirectories>
- </AdditionalLibraryDirectories>
- </Link>
- <ProjectReference>
- <LinkLibraryDependencies>false</LinkLibraryDependencies>
- </ProjectReference>
- </ItemDefinitionGroup>
<ItemGroup>
@SOURCE_FILES@
</ItemGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in
index 33f4054546..b67f3904a4 100644
--- a/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in
+++ b/build_msvc/libbitcoin_wallet/libbitcoin_wallet.vcxproj.in
@@ -1,162 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <ItemGroup>
-@SOURCE_FILES@
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{93B86837-B543-48A5-A89B-7C87ABB77DF2}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_wallet</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
+ <ItemGroup>
+@SOURCE_FILES@
+ </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in
index 187d955687..b8d0f4b442 100644
--- a/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in
+++ b/build_msvc/libbitcoin_wallet_tool/libbitcoin_wallet_tool.vcxproj.in
@@ -1,162 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <ItemGroup>
-@SOURCE_FILES@
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{F91AC55E-6F5E-4C58-9AC5-B40DB7DEEF93}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_zmq</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
+ <ItemGroup>
+@SOURCE_FILES@
+ </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in
index c877a280c0..1b2c27e53f 100644
--- a/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in
+++ b/build_msvc/libbitcoin_zmq/libbitcoin_zmq.vcxproj.in
@@ -1,162 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <ItemGroup>
-@SOURCE_FILES@
- </ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{792D487F-F14C-49FC-A9DE-3FC150F31C3F}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libbitcoin_zmq</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
+ <ItemGroup>
+@SOURCE_FILES@
+ </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>NOMINMAX;ZMQ_STATIC;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
index a32aafbd74..9c8931021b 100644
--- a/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
+++ b/build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
@@ -1,27 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\arith_uint256.cpp" />
<ClCompile Include="..\..\src\consensus\merkle.cpp" />
+ <ClCompile Include="..\..\src\consensus\tx_check.cpp" />
<ClCompile Include="..\..\src\crypto\aes.cpp" />
<ClCompile Include="..\..\src\crypto\chacha20.cpp" />
<ClCompile Include="..\..\src\crypto\hmac_sha256.cpp" />
@@ -42,154 +31,6 @@
<ClCompile Include="..\..\src\uint256.cpp" />
<ClCompile Include="..\..\src\util\strencodings.cpp" />
</ItemGroup>
- <ItemGroup>
- <None Include="packages.config" />
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>bitcoind</RootNamespace>
- <ProjectName>libbitcoin_consensus</ProjectName>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>
- </Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>
- </Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>
- </Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>
- </Linkage-secp256k1>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>false</SDLCheck>
- <ExceptionHandling>Sync</ExceptionHandling>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>false</SDLCheck>
- <ExceptionHandling>Sync</ExceptionHandling>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>false</SDLCheck>
- <ExceptionHandling>Sync</ExceptionHandling>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>false</SDLCheck>
- <ExceptionHandling>Sync</ExceptionHandling>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project> \ No newline at end of file
diff --git a/build_msvc/libleveldb/libleveldb.vcxproj b/build_msvc/libleveldb/libleveldb.vcxproj
index 545508001e..4689bdc45e 100644
--- a/build_msvc/libleveldb/libleveldb.vcxproj
+++ b/build_msvc/libleveldb/libleveldb.vcxproj
@@ -1,24 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{18430FEF-6B61-4C53-B396-718E02850F1B}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\leveldb\db\builder.cc" />
<ClCompile Include="..\..\src\leveldb\db\c.cc" />
@@ -62,141 +50,13 @@
<ClCompile Include="..\..\src\leveldb\util\options.cc" />
<ClCompile Include="..\..\src\leveldb\util\status.cc" />
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{18430FEF-6B61-4C53-B396-718E02850F1B}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libunivalue</RootNamespace>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;NOMINMAX;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
<ItemDefinitionGroup>
<ClCompile>
- <TreatWarningAsError>false</TreatWarningAsError>
- </ClCompile>
+ <PreprocessorDefinitions>_CRT_NONSTDC_NO_DEPRECATE;LEVELDB_PLATFORM_WINDOWS;LEVELDB_ATOMIC_PRESENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <DisableSpecificWarnings>4244;4267;4312;</DisableSpecificWarnings>
+ <AdditionalIncludeDirectories>..\..\src\leveldb;..\..\src\leveldb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
</ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/libsecp256k1/libsecp256k1.vcxproj b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
index b4c9ec28ee..644f44350e 100644
--- a/build_msvc/libsecp256k1/libsecp256k1.vcxproj
+++ b/build_msvc/libsecp256k1/libsecp256k1.vcxproj
@@ -1,157 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" />
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libunivalue</RootNamespace>
</PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ItemGroup>
+ <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c" />
+ </ItemGroup>
+ <ItemDefinitionGroup>
<ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;HAVE_CONFIG_H;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\secp256k1;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
+ <PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
</ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
-</Project>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/build_msvc/libunivalue/libunivalue.vcxproj b/build_msvc/libunivalue/libunivalue.vcxproj
index c3799b6408..92a9115711 100644
--- a/build_msvc/libunivalue/libunivalue.vcxproj
+++ b/build_msvc/libunivalue/libunivalue.vcxproj
@@ -1,160 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{5724BA7D-A09A-4BA8-800B-C4C1561B3D69}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\univalue\lib\univalue.cpp" />
<ClCompile Include="..\..\src\univalue\lib\univalue_get.cpp" />
<ClCompile Include="..\..\src\univalue\lib\univalue_read.cpp" />
<ClCompile Include="..\..\src\univalue\lib\univalue_write.cpp" />
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{5724BA7D-A09A-4BA8-800B-C4C1561B3D69}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>libunivalue</RootNamespace>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\univalue\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\univalue\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\univalue\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <AdditionalIncludeDirectories>..\..\src\univalue\include;</AdditionalIncludeDirectories>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/build_msvc/msbuild/tasks/replaceinfile.targets b/build_msvc/msbuild/tasks/replaceinfile.targets
new file mode 100644
index 0000000000..2ccb8b30e0
--- /dev/null
+++ b/build_msvc/msbuild/tasks/replaceinfile.targets
@@ -0,0 +1,35 @@
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <UsingTask
+ TaskName="ReplaceInFile"
+ TaskFactory="CodeTaskFactory"
+ AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
+ <ParameterGroup>
+ <FilePath Required="true" />
+ <Replace Required="true" />
+ <By Required="false" />
+ <ToFullPath Required="false" />
+ </ParameterGroup>
+ <Task>
+ <Using Namespace="System"/>
+ <Using Namespace="System.IO"/>
+ <Code Type="Fragment" Language="cs">
+<![CDATA[
+if(File.Exists(FilePath) == false) {
+ Log.LogError("replaceinfile task could not locate " + FilePath + ".");
+}
+else {
+ var data = File.ReadAllText(FilePath);
+ var by = By;
+ if (ToFullPath == "true")
+ {
+ by = Path.GetFullPath(by);
+ }
+ data = data.Replace(Replace, by);
+ Log.LogMessage("Replace '" + Replace + "' by '" + by + "' in " + FilePath);
+ File.WriteAllText(FilePath, data, new System.Text.UTF8Encoding(false));
+}
+]]>
+ </Code>
+ </Task>
+ </UsingTask>
+</Project> \ No newline at end of file
diff --git a/build_msvc/msvc-autogen.py b/build_msvc/msvc-autogen.py
index c8df29eecb..b612467bf3 100644
--- a/build_msvc/msvc-autogen.py
+++ b/build_msvc/msvc-autogen.py
@@ -2,8 +2,11 @@
import os
import re
+import argparse
+from shutil import copyfile
SOURCE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src'))
+DEFAULT_PLATFORM_TOOLSET = R'v141'
libs = [
'libbitcoin_cli',
@@ -42,8 +45,21 @@ def parse_makefile(makefile):
lib_sources[current_lib] = []
break
+def set_common_properties(toolset):
+ with open(os.path.join(SOURCE_DIR, '../build_msvc/common.init.vcxproj'), 'r', encoding='utf-8') as rfile:
+ s = rfile.read()
+ s = re.sub('<PlatformToolset>.*?</PlatformToolset>', '<PlatformToolset>'+toolset+'</PlatformToolset>', s)
+ with open(os.path.join(SOURCE_DIR, '../build_msvc/common.init.vcxproj'), 'w', encoding='utf-8',newline='\n') as wfile:
+ wfile.write(s)
def main():
+ parser = argparse.ArgumentParser(description='Bitcoin-core msbuild configuration initialiser.')
+ parser.add_argument('-toolset', nargs='?',help='Optionally sets the msbuild platform toolset, e.g. v142 for Visual Studio 2019.'
+ ' default is %s.'%DEFAULT_PLATFORM_TOOLSET)
+ args = parser.parse_args()
+ if args.toolset:
+ set_common_properties(args.toolset)
+
for makefile_name in os.listdir(SOURCE_DIR):
if 'Makefile' in makefile_name:
parse_makefile(os.path.join(SOURCE_DIR, makefile_name))
@@ -58,7 +74,8 @@ def main():
with open(vcxproj_filename, 'w', encoding='utf-8') as vcxproj_file:
vcxproj_file.write(vcxproj_in_file.read().replace(
'@SOURCE_FILES@\n', content))
-
+ copyfile(os.path.join(SOURCE_DIR,'../build_msvc/bitcoin_config.h'), os.path.join(SOURCE_DIR, 'config/bitcoin-config.h'))
+ copyfile(os.path.join(SOURCE_DIR,'../build_msvc/libsecp256k1_config.h'), os.path.join(SOURCE_DIR, 'secp256k1/src/libsecp256k1-config.h'))
if __name__ == '__main__':
main()
diff --git a/build_msvc/test_bitcoin/test_bitcoin.vcxproj b/build_msvc/test_bitcoin/test_bitcoin.vcxproj
index d05a03699f..64bdb5f492 100644
--- a/build_msvc/test_bitcoin/test_bitcoin.vcxproj
+++ b/build_msvc/test_bitcoin/test_bitcoin.vcxproj
@@ -1,31 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{A56B73DB-D46D-4882-8374-1FE3FFA08F07}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\src\test\*_tests.cpp" />
<ClCompile Include="..\..\src\test\*_properties.cpp" />
<ClCompile Include="..\..\src\test\gen\*_gen.cpp" />
<ClCompile Include="..\..\src\wallet\test\*_tests.cpp" />
- <ClCompile Include="..\..\src\test\test_bitcoin.cpp" />
- <ClCompile Include="..\..\src\test\test_bitcoin_main.cpp" />
+ <ClCompile Include="..\..\src\test\setup_common.cpp" />
+ <ClCompile Include="..\..\src\test\main.cpp" />
<ClCompile Include="..\..\src\wallet\test\*_fixture.cpp" />
</ItemGroup>
<ItemGroup>
@@ -63,140 +52,6 @@
<Project>{18430fef-6b61-4c53-b396-718e02850f1b}</Project>
</ProjectReference>
</ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
- <ProjectGuid>{A56B73DB-D46D-4882-8374-1FE3FFA08F07}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>test_bitcoin</RootNamespace>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <SuppressStartupBanner>false</SuppressStartupBanner>
- <AdditionalDependencies>boost_test_exec_monitor-vc140-mt-gd.lib;crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>boost_test_exec_monitor-vc140-mt-gd.lib;crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>boost_test_exec_monitor-vc140-mt.lib;crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NOMINMAX;WIN32;HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>boost_test_exec_monitor-vc140-mt.lib;crypt32.lib;Iphlpapi.lib;ws2_32.lib;Shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
<Target Name="RawBenchHeaderGen" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>There was an error executing the JSON test header generation task.</ErrorText>
@@ -206,6 +61,7 @@
</ItemGroup>
<HeaderFromHexdump RawFilePath="%(JsonTestFile.FullPath)" HeaderFilePath="%(JsonTestFile.FullPath).h" SourceHeader="namespace json_tests{ static unsigned const char %(JsonTestFile.Filename)[] = {" SourceFooter="};}" />
</Target>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Label="hexdumpTarget" Project="..\msbuild\tasks\hexdump.targets" />
</Project>
diff --git a/build_msvc/testconsensus/testconsensus.vcxproj b/build_msvc/testconsensus/testconsensus.vcxproj
index a2f5659049..9a6da3ecae 100644
--- a/build_msvc/testconsensus/testconsensus.vcxproj
+++ b/build_msvc/testconsensus/testconsensus.vcxproj
@@ -1,172 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <Import Label="configInitTarget" Project="..\common.init.vcxproj" />
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\common.init.vcxproj" />
<PropertyGroup Label="Globals">
- <VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{E78473E9-B850-456C-9120-276301E04C06}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>testconsensus</RootNamespace>
- <ProjectName>test_libbitcoinconsensus</ProjectName>
- <VcpkgTriplet Condition="'$(Platform)'=='Win32'">x86-windows-static</VcpkgTriplet>
- <VcpkgTriplet Condition="'$(Platform)'=='x64'">x64-windows-static</VcpkgTriplet>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v141</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
+ <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- <Linkage-secp256k1>static</Linkage-secp256k1>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_SCL_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>Disabled</Optimization>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <DataExecutionPrevention>true</DataExecutionPrevention>
- <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;_SCL_SECURE_NO_WARNINGS;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <ClCompile>
- <PrecompiledHeader>NotUsing</PrecompiledHeader>
- <WarningLevel>Level3</WarningLevel>
- <Optimization>MaxSpeed</Optimization>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <PreprocessorDefinitions>HAVE_CONFIG_H;WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <SDLCheck>true</SDLCheck>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- </Link>
- </ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="testconsensus.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\libbitcoinconsensus\libbitcoinconsensus.vcxproj">
- <Project>{2b384fa8-9ee1-4544-93cb-0d733c25e8ce}</Project>
+ <Project>{2B384FA8-9EE1-4544-93CB-0D733C25E8CE}</Project>
</ProjectReference>
<ProjectReference Include="..\libbitcoin_util\libbitcoin_util.vcxproj">
- <Project>{b53a5535-ee9d-4c6f-9a26-f79ee3bc3754}</Project>
+ <Project>{B53A5535-EE9D-4C6F-9A26-F79EE3BC3754}</Project>
</ProjectReference>
<ProjectReference Include="..\libsecp256k1\libsecp256k1.vcxproj">
- <Project>{bb493552-3b8c-4a8c-bf69-a6e7a51d2ea6}</Project>
+ <Project>{BB493552-3B8C-4A8C-BF69-A6E7A51D2EA6}</Project>
</ProjectReference>
</ItemGroup>
- <Import Label="configTarget" Project="..\common.vcxproj" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
diff --git a/configure.ac b/configure.ac
index 984c595ead..5e1a5e14a1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,8 +85,8 @@ AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AC_PATH_TOOL(GCOV, gcov)
AC_PATH_PROG(LCOV, lcov)
-dnl Python 3.4 is specified in .python-version and should be used if available, see doc/dependencies.md
-AC_PATH_PROGS([PYTHON], [python3.4 python3.5 python3.6 python3.7 python3 python])
+dnl Python 3.5 is specified in .python-version and should be used if available, see doc/dependencies.md
+AC_PATH_PROGS([PYTHON], [python3.5 python3.6 python3.7 python3.8 python3 python])
AC_PATH_PROG(GENHTML, genhtml)
AC_PATH_PROG([GIT], [git])
AC_PATH_PROG(CCACHE,ccache)
@@ -194,9 +194,15 @@ AC_ARG_ENABLE([glibc-back-compat],
[use_glibc_compat=$enableval],
[use_glibc_compat=no])
+AC_ARG_ENABLE([threadlocal],
+ [AS_HELP_STRING([--enable-threadlocal],
+ [enable features that depend on the c++ thread_local keyword (currently just thread names in debug logs). (default is to enabled if there is platform support and glibc-back-compat is not enabled)])],
+ [use_thread_local=$enableval],
+ [use_thread_local=auto])
+
AC_ARG_ENABLE([asm],
- [AS_HELP_STRING([--enable-asm],
- [Enable assembly routines (default is yes)])],
+ [AS_HELP_STRING([--disable-asm],
+ [disable assembly routines (enabled by default)])],
[use_asm=$enableval],
[use_asm=yes])
@@ -339,6 +345,13 @@ if test "x$CXXFLAGS_overridden" = "xno"; then
AX_CHECK_COMPILE_FLAG([-Wimplicit-fallthrough],[NOWARN_CXXFLAGS="$NOWARN_CXXFLAGS -Wno-implicit-fallthrough"],,[[$CXXFLAG_WERROR]])
fi
+enable_hwcrc32=no
+enable_sse41=no
+enable_avx2=no
+enable_shani=no
+
+if test "x$use_asm" = "xyes"; then
+
# Check for optional instruction set support. Enabling these does _not_ imply that all code will
# be compiled with them, rather that specific objects/libs may use them after checking for runtime
# compatibility.
@@ -416,6 +429,8 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
)
CXXFLAGS="$TEMP_CXXFLAGS"
+fi
+
CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS"
AC_ARG_WITH([utils],
@@ -725,6 +740,10 @@ if test x$TARGET_OS != xwindows; then
AX_CHECK_COMPILE_FLAG([-fPIC],[PIC_FLAGS="-fPIC"])
fi
+# All versions of gcc that we commonly use for building are subject to bug
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90348. To work around that, set
+# -fstack-reuse=none for all gcc builds. (Only gcc understands this flag)
+AX_CHECK_COMPILE_FLAG([-fstack-reuse=none],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-reuse=none"])
if test x$use_hardening != xno; then
use_hardening=yes
AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"])
@@ -814,27 +833,49 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([
]
)
-TEMP_LDFLAGS="$LDFLAGS"
-LDFLAGS="$TEMP_LDFLAGS $PTHREAD_CFLAGS"
-AC_MSG_CHECKING([for thread_local support])
-AC_LINK_IFELSE([AC_LANG_SOURCE([
- #include <thread>
- static thread_local int foo = 0;
- static void run_thread() { foo++;}
- int main(){
- for(int i = 0; i < 10; i++) { std::thread(run_thread).detach();}
- return foo;
- }
- ])],
- [
- AC_DEFINE(HAVE_THREAD_LOCAL,1,[Define if thread_local is supported.])
- AC_MSG_RESULT(yes)
- ],
- [
- AC_MSG_RESULT(no)
- ]
-)
-LDFLAGS="$TEMP_LDFLAGS"
+if test "x$use_thread_local" = xyes || { test "x$use_thread_local" = xauto && test "x$use_glibc_compat" = xno; }; then
+ TEMP_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$TEMP_LDFLAGS $PTHREAD_CFLAGS"
+ AC_MSG_CHECKING([for thread_local support])
+ AC_LINK_IFELSE([AC_LANG_SOURCE([
+ #include <thread>
+ static thread_local int foo = 0;
+ static void run_thread() { foo++;}
+ int main(){
+ for(int i = 0; i < 10; i++) { std::thread(run_thread).detach();}
+ return foo;
+ }
+ ])],
+ [
+ case $host in
+ *mingw*)
+ # mingw32's implementation of thread_local has also been shown to behave
+ # erroneously under concurrent usage; see:
+ # https://gist.github.com/jamesob/fe9a872051a88b2025b1aa37bfa98605
+ AC_MSG_RESULT(no)
+ ;;
+ *darwin*)
+ # TODO enable thread_local on later versions of Darwin where it is
+ # supported (per https://stackoverflow.com/a/29929949)
+ AC_MSG_RESULT(no)
+ ;;
+ *freebsd*)
+ # FreeBSD's implementation of thread_local is also buggy (per
+ # https://groups.google.com/d/msg/bsdmailinglist/22ncTZAbDp4/Dii_pII5AwAJ)
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_DEFINE(HAVE_THREAD_LOCAL,1,[Define if thread_local is supported.])
+ AC_MSG_RESULT(yes)
+ ;;
+ esac
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ]
+ )
+ LDFLAGS="$TEMP_LDFLAGS"
+fi
# Check for different ways of gathering OS randomness
AC_MSG_CHECKING(for Linux getrandom syscall)
diff --git a/contrib/devtools/README.md b/contrib/devtools/README.md
index 6ee65f40be..4994d7f0a5 100644
--- a/contrib/devtools/README.md
+++ b/contrib/devtools/README.md
@@ -7,6 +7,8 @@ clang-format-diff.py
A script to format unified git diffs according to [.clang-format](../../src/.clang-format).
+Requires `clang-format`, installed e.g. via `brew install clang-format` on macOS.
+
For instance, to format the last commit with 0 lines of context,
the script should be called from the git root folder as follows.
@@ -142,7 +144,7 @@ Then do:
Create and verify timestamps of merge commits
---------------------------------------------
To create or verify timestamps on the merge commits, install the OpenTimestamps
-client via `pip3 install opentimestamps-client`. Then, dowload the gpg wrapper
+client via `pip3 install opentimestamps-client`. Then, download the gpg wrapper
`ots-git-gpg-wrapper.sh` and set it as git's `gpg.program`. See
[the ots git integration documentation](https://github.com/opentimestamps/opentimestamps-client/blob/master/doc/git-integration.md#usage)
for further details.
@@ -167,7 +169,7 @@ still compatible with the minimum supported Linux distribution versions.
Example usage after a gitian build:
- find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
+ find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
If only supported symbols are used the return value will be 0 and the output will be empty.
diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py
index ab834b7623..cd7a271e83 100755
--- a/contrib/devtools/github-merge.py
+++ b/contrib/devtools/github-merge.py
@@ -32,11 +32,15 @@ BASH = os.getenv('BASH','bash')
# OS specific configuration for terminal attributes
ATTR_RESET = ''
ATTR_PR = ''
-COMMIT_FORMAT = '%h %s (%an)%d'
+ATTR_NAME = ''
+ATTR_WARN = ''
+COMMIT_FORMAT = '%H %s (%an)%d'
if os.name == 'posix': # if posix, assume we can use basic terminal escapes
ATTR_RESET = '\033[0m'
ATTR_PR = '\033[1;36m'
- COMMIT_FORMAT = '%C(bold blue)%h%Creset %s %C(cyan)(%an)%Creset%C(green)%d%Creset'
+ ATTR_NAME = '\033[0;36m'
+ ATTR_WARN = '\033[1;31m'
+ COMMIT_FORMAT = '%C(bold blue)%H%Creset %s %C(cyan)(%an)%Creset%C(green)%d%Creset'
def git_config_get(option, default=None):
'''
@@ -47,18 +51,36 @@ def git_config_get(option, default=None):
except subprocess.CalledProcessError:
return default
-def retrieve_pr_info(repo,pull,ghtoken):
+def get_response(req_url, ghtoken):
+ req = Request(req_url)
+ if ghtoken is not None:
+ req.add_header('Authorization', 'token ' + ghtoken)
+ return urlopen(req)
+
+def retrieve_json(req_url, ghtoken, use_pagination=False):
'''
- Retrieve pull request information from github.
- Return None if no title can be found, or an error happens.
+ Retrieve json from github.
+ Return None if an error happens.
'''
try:
- req = Request("https://api.github.com/repos/"+repo+"/pulls/"+pull)
- if ghtoken is not None:
- req.add_header('Authorization', 'token ' + ghtoken)
- result = urlopen(req)
reader = codecs.getreader('utf-8')
- obj = json.load(reader(result))
+ if not use_pagination:
+ return json.load(reader(get_response(req_url, ghtoken)))
+
+ obj = []
+ page_num = 1
+ while True:
+ req_url_page = '{}?page={}'.format(req_url, page_num)
+ result = get_response(req_url_page, ghtoken)
+ obj.extend(json.load(reader(result)))
+
+ link = result.headers.get('link', None)
+ if link is not None:
+ link_next = [l for l in link.split(',') if 'rel="next"' in l]
+ if len(link_next) > 0:
+ page_num = int(link_next[0][link_next[0].find("page=")+5:link_next[0].find(">")])
+ continue
+ break
return obj
except HTTPError as e:
error_message = e.read()
@@ -69,6 +91,18 @@ def retrieve_pr_info(repo,pull,ghtoken):
print('Warning: unable to retrieve pull information from github: %s' % e)
return None
+def retrieve_pr_info(repo,pull,ghtoken):
+ req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull
+ return retrieve_json(req_url,ghtoken)
+
+def retrieve_pr_comments(repo,pull,ghtoken):
+ req_url = "https://api.github.com/repos/"+repo+"/issues/"+pull+"/comments"
+ return retrieve_json(req_url,ghtoken,use_pagination=True)
+
+def retrieve_pr_reviews(repo,pull,ghtoken):
+ req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull+"/reviews"
+ return retrieve_json(req_url,ghtoken,use_pagination=True)
+
def ask_prompt(text):
print(text,end=" ",file=stderr)
stderr.flush()
@@ -133,9 +167,37 @@ def tree_sha512sum(commit='HEAD'):
raise IOError('Non-zero return value executing git cat-file')
return overall.hexdigest()
-def print_merge_details(pull, title, branch, base_branch, head_branch):
+def get_acks_from_comments(head_commit, comments):
+ # Look for abbreviated commit id, because not everyone wants to type/paste
+ # the whole thing and the chance of collisions within a PR is small enough
+ head_abbrev = head_commit[0:6]
+ acks = []
+ for c in comments:
+ review = [l for l in c['body'].split('\r\n') if 'ACK' in l and head_abbrev in l]
+ if review:
+ acks.append((c['user']['login'], review[0]))
+ return acks
+
+def make_acks_message(head_commit, acks):
+ if acks:
+ ack_str ='\n\nACKs for top commit:\n'.format(head_commit)
+ for name, msg in acks:
+ ack_str += ' {}:\n'.format(name)
+ ack_str += ' {}\n'.format(msg)
+ else:
+ ack_str ='\n\nTop commit has no ACKs.\n'
+ return ack_str
+
+def print_merge_details(pull, title, branch, base_branch, head_branch, acks):
print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
+ if acks is not None:
+ if acks:
+ print('{}ACKs:{}'.format(ATTR_PR, ATTR_RESET))
+ for (name, message) in acks:
+ print('* {} {}({}){}'.format(message, ATTR_NAME, name, ATTR_RESET))
+ else:
+ print('{}Top commit has no ACKs!{}'.format(ATTR_WARN, ATTR_RESET))
def parse_arguments():
epilog = '''
@@ -214,6 +276,8 @@ def main():
sys.exit(3)
try:
subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+head_branch], stdout=devnull, stderr=stdout)
+ head_commit = subprocess.check_output([GIT,'log','-1','--pretty=format:%H',head_branch]).decode('utf-8')
+ assert len(head_commit) == 40
except subprocess.CalledProcessError:
print("ERROR: Cannot find head of pull request #%s on %s." % (pull,host_repo), file=stderr)
sys.exit(3)
@@ -236,10 +300,10 @@ def main():
else:
firstline = 'Merge #%s' % (pull,)
message = firstline + '\n\n'
- message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%h %s (%an)',base_branch+'..'+head_branch]).decode('utf-8')
+ message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%H %s (%an)',base_branch+'..'+head_branch]).decode('utf-8')
message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n'
try:
- subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','-m',message.encode('utf-8'),head_branch])
+ subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','--no-gpg-sign','-m',message.encode('utf-8'),head_branch])
except subprocess.CalledProcessError:
print("ERROR: Cannot be merged cleanly.",file=stderr)
subprocess.check_call([GIT,'merge','--abort'])
@@ -255,20 +319,14 @@ def main():
if len(symlink_files) > 0:
sys.exit(4)
- # Put tree SHA512 into the message
+ # Compute SHA512 of git tree (to be able to detect changes before sign-off)
try:
first_sha512 = tree_sha512sum()
- message += '\n\nTree-SHA512: ' + first_sha512
except subprocess.CalledProcessError:
print("ERROR: Unable to compute tree hash")
sys.exit(4)
- try:
- subprocess.check_call([GIT,'commit','--amend','-m',message.encode('utf-8')])
- except subprocess.CalledProcessError:
- print("ERROR: Cannot update message.", file=stderr)
- sys.exit(4)
- print_merge_details(pull, title, branch, base_branch, head_branch)
+ print_merge_details(pull, title, branch, base_branch, head_branch, None)
print()
# Run test command if configured.
@@ -301,8 +359,24 @@ def main():
print("ERROR: Tree hash changed unexpectedly",file=stderr)
sys.exit(8)
+ # Retrieve PR comments and ACKs and add to commit message, store ACKs to print them with commit
+ # description
+ comments = retrieve_pr_comments(repo,pull,ghtoken) + retrieve_pr_reviews(repo,pull,ghtoken)
+ if comments is None:
+ print("ERROR: Could not fetch PR comments and reviews",file=stderr)
+ sys.exit(1)
+ acks = get_acks_from_comments(head_commit=head_commit, comments=comments)
+ message += make_acks_message(head_commit=head_commit, acks=acks)
+ # end message with SHA512 tree hash, then update message
+ message += '\n\nTree-SHA512: ' + first_sha512
+ try:
+ subprocess.check_call([GIT,'commit','--amend','--no-gpg-sign','-m',message.encode('utf-8')])
+ except subprocess.CalledProcessError:
+ print("ERROR: Cannot update message.", file=stderr)
+ sys.exit(4)
+
# Sign the merge commit.
- print_merge_details(pull, title, branch, base_branch, head_branch)
+ print_merge_details(pull, title, branch, base_branch, head_branch, acks)
while True:
reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower()
if reply == 's':
diff --git a/contrib/devtools/split-debug.sh.in b/contrib/devtools/split-debug.sh.in
index deda49cc54..92b72b1446 100644
--- a/contrib/devtools/split-debug.sh.in
+++ b/contrib/devtools/split-debug.sh.in
@@ -1,5 +1,5 @@
#!/bin/sh
-
+set -e
if [ $# -ne 3 ];
then echo "usage: $0 <input> <stripped-binary> <debug-binary>"
fi
diff --git a/contrib/devtools/symbol-check.py b/contrib/devtools/symbol-check.py
index c6158c9422..7729dd7257 100755
--- a/contrib/devtools/symbol-check.py
+++ b/contrib/devtools/symbol-check.py
@@ -9,7 +9,7 @@ still compatible with the minimum supported Linux distribution versions.
Example usage:
- find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
+ find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
'''
import subprocess
import re
diff --git a/contrib/devtools/test-security-check.py b/contrib/devtools/test-security-check.py
index fd374f6328..bb864bfc0c 100755
--- a/contrib/devtools/test-security-check.py
+++ b/contrib/devtools/test-security-check.py
@@ -43,18 +43,6 @@ class TestSecurityChecks(unittest.TestCase):
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']),
(0, ''))
- def test_32bit_PE(self):
- source = 'test1.c'
- executable = 'test1.exe'
- cc = 'i686-w64-mingw32-gcc'
- write_testcode(source)
-
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--no-nxcompat','-Wl,--no-dynamicbase']),
- (1, executable+': failed DYNAMIC_BASE NX'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--no-dynamicbase']),
- (1, executable+': failed DYNAMIC_BASE'))
- self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']),
- (0, ''))
def test_64bit_PE(self):
source = 'test1.c'
executable = 'test1.exe'
diff --git a/contrib/devtools/test_deterministic_coverage.sh b/contrib/devtools/test_deterministic_coverage.sh
index 16d03e1fff..88ac850021 100755
--- a/contrib/devtools/test_deterministic_coverage.sh
+++ b/contrib/devtools/test_deterministic_coverage.sh
@@ -14,6 +14,7 @@ GCOV_EXECUTABLE="gcov"
# Disable tests known to cause non-deterministic behaviour and document the source or point of non-determinism.
NON_DETERMINISTIC_TESTS=(
+ "blockfilter_index_tests/blockfilter_index_initial_sync" # src/checkqueue.h: In CCheckQueue::Loop(): while (queue.empty()) { ... }
"coinselector_tests/knapsack_solver_test" # coinselector_tests.cpp: if (equal_sets(setCoinsRet, setCoinsRet2))
"denialofservice_tests/DoS_mapOrphans" # denialofservice_tests.cpp: it = mapOrphanTransactions.lower_bound(InsecureRand256());
"fs_tests/fsbridge_fstream" # deterministic test failure?
diff --git a/contrib/gitian-build.py b/contrib/gitian-build.py
index fc7fbb764d..570d4906cd 100755
--- a/contrib/gitian-build.py
+++ b/contrib/gitian-build.py
@@ -7,20 +7,20 @@ import sys
def setup():
global args, workdir
- programs = ['ruby', 'git', 'apt-cacher-ng', 'make', 'wget']
+ programs = ['ruby', 'git', 'make', 'wget', 'curl']
if args.kvm:
- programs += ['python-vm-builder', 'qemu-kvm', 'qemu-utils']
- elif args.docker:
+ 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)
- exit(1)
+ print('Cannot find any way to install Docker.', file=sys.stderr)
+ sys.exit(1)
else:
- programs += ['lxc', 'debootstrap']
+ programs += ['apt-cacher-ng', 'lxc', 'debootstrap']
subprocess.check_call(['sudo', 'apt-get', 'install', '-qq'] + programs)
if not os.path.isdir('gitian.sigs'):
subprocess.check_call(['git', 'clone', 'https://github.com/bitcoin-core/gitian.sigs.git'])
@@ -41,7 +41,7 @@ def setup():
if args.is_bionic and not args.kvm and not args.docker:
subprocess.check_call(['sudo', 'sed', '-i', 's/lxcbr0/br0/', '/etc/default/lxc-net'])
print('Reboot is required')
- exit(0)
+ sys.exit(0)
def build():
global args, workdir
@@ -68,14 +68,14 @@ def build():
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-win.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml'])
subprocess.check_call('mv build/out/bitcoin-*-win-unsigned.tar.gz inputs/', shell=True)
- subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe ../bitcoin-binaries/'+args.version, shell=True)
+ subprocess.check_call('mv build/out/bitcoin-*.zip build/out/bitcoin-*.exe build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/'+args.version, shell=True)
if args.macos:
print('\nCompiling ' + args.version + ' MacOS')
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'bitcoin='+args.commit, '--url', 'bitcoin='+args.url, '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-unsigned', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml'])
subprocess.check_call('mv build/out/bitcoin-*-osx-unsigned.tar.gz inputs/', shell=True)
- subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg ../bitcoin-binaries/'+args.version, shell=True)
+ subprocess.check_call('mv build/out/bitcoin-*.tar.gz build/out/bitcoin-*.dmg build/out/src/bitcoin-*.tar.gz ../bitcoin-binaries/'+args.version, shell=True)
os.chdir(workdir)
@@ -95,15 +95,14 @@ def sign():
if args.windows:
print('\nSigning ' + args.version + ' Windows')
subprocess.check_call('cp inputs/bitcoin-' + args.version + '-win-unsigned.tar.gz inputs/bitcoin-win-unsigned.tar.gz', shell=True)
- subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
+ subprocess.check_call(['bin/gbuild', '--skip-image', '--upgrade', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
subprocess.check_call('mv build/out/bitcoin-*win64-setup.exe ../bitcoin-binaries/'+args.version, shell=True)
- subprocess.check_call('mv build/out/bitcoin-*win32-setup.exe ../bitcoin-binaries/'+args.version, shell=True)
if args.macos:
print('\nSigning ' + args.version + ' MacOS')
subprocess.check_call('cp inputs/bitcoin-' + args.version + '-osx-unsigned.tar.gz inputs/bitcoin-osx-unsigned.tar.gz', shell=True)
- subprocess.check_call(['bin/gbuild', '-i', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
+ subprocess.check_call(['bin/gbuild', '--skip-image', '--upgrade', '--commit', 'signature='+args.commit, '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-signed', '--destination', '../gitian.sigs/', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
subprocess.check_call('mv build/out/bitcoin-osx-signed.dmg ../bitcoin-binaries/'+args.version+'/bitcoin-'+args.version+'-osx.dmg', shell=True)
@@ -119,25 +118,41 @@ def sign():
def verify():
global args, workdir
+ rc = 0
os.chdir('gitian-builder')
print('\nVerifying v'+args.version+' Linux\n')
- subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml'])
+ if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../bitcoin/contrib/gitian-descriptors/gitian-linux.yml']):
+ print('Verifying v'+args.version+' Linux FAILED\n')
+ rc = 1
+
print('\nVerifying v'+args.version+' Windows\n')
- subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml'])
+ if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-win.yml']):
+ print('Verifying v'+args.version+' Windows FAILED\n')
+ rc = 1
+
print('\nVerifying v'+args.version+' MacOS\n')
- subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml'])
+ if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-unsigned', '../bitcoin/contrib/gitian-descriptors/gitian-osx.yml']):
+ print('Verifying v'+args.version+' MacOS FAILED\n')
+ rc = 1
+
print('\nVerifying v'+args.version+' Signed Windows\n')
- subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml'])
+ if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml']):
+ print('Verifying v'+args.version+' Signed Windows FAILED\n')
+ rc = 1
+
print('\nVerifying v'+args.version+' Signed MacOS\n')
- subprocess.check_call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml'])
+ if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../bitcoin/contrib/gitian-descriptors/gitian-osx-signer.yml']):
+ print('Verifying v'+args.version+' Signed MacOS FAILED\n')
+ rc = 1
os.chdir(workdir)
+ return rc
def main():
global args, workdir
- parser = argparse.ArgumentParser(usage='%(prog)s [options] signer version')
+ parser = argparse.ArgumentParser(description='Script for running full Gitian builds.')
parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch')
parser.add_argument('-p', '--pull', action='store_true', dest='pull', help='Indicate that the version argument is the number of a github repository pull request')
parser.add_argument('-u', '--url', dest='url', default='https://github.com/bitcoin/bitcoin', help='Specify the URL of the repository. Default is %(default)s')
@@ -150,64 +165,70 @@ def main():
parser.add_argument('-m', '--memory', dest='memory', default='2000', help='Memory to allocate in MiB. Default %(default)s')
parser.add_argument('-k', '--kvm', action='store_true', dest='kvm', help='Use KVM instead of LXC')
parser.add_argument('-d', '--docker', action='store_true', dest='docker', help='Use Docker instead of LXC')
- parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Uses LXC. If you want to use KVM, use the --kvm option. Only works on Debian-based systems (Ubuntu, Debian)')
+ parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Only works on Debian-based systems (Ubuntu, Debian)')
parser.add_argument('-D', '--detach-sign', action='store_true', dest='detach_sign', help='Create the assert file for detached signing. Will not commit anything.')
parser.add_argument('-n', '--no-commit', action='store_false', dest='commit_files', help='Do not commit anything to git')
- parser.add_argument('signer', help='GPG signer to sign each build assert file')
- parser.add_argument('version', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified')
+ parser.add_argument('signer', nargs='?', help='GPG signer to sign each build assert file')
+ parser.add_argument('version', nargs='?', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified')
args = parser.parse_args()
workdir = os.getcwd()
- args.linux = 'l' in args.os
- args.windows = 'w' in args.os
- args.macos = 'm' in args.os
-
args.is_bionic = b'bionic' in subprocess.check_output(['lsb_release', '-cs'])
- if args.buildsign:
- args.build=True
- args.sign=True
-
if args.kvm and args.docker:
raise Exception('Error: cannot have both kvm and docker')
- args.sign_prog = 'true' if args.detach_sign else 'gpg --detach-sign'
-
- # Set environment variable USE_LXC or USE_DOCKER, let gitian-builder know that we use lxc or docker
+ # Ensure no more than one environment variable for gitian-builder (USE_LXC, USE_VBOX, USE_DOCKER) is set as they
+ # can interfere (e.g., USE_LXC being set shadows USE_DOCKER; for details see gitian-builder/libexec/make-clean-vm).
+ os.environ['USE_LXC'] = ''
+ os.environ['USE_VBOX'] = ''
+ os.environ['USE_DOCKER'] = ''
if args.docker:
os.environ['USE_DOCKER'] = '1'
elif not args.kvm:
os.environ['USE_LXC'] = '1'
- if not 'GITIAN_HOST_IP' in os.environ.keys():
+ if 'GITIAN_HOST_IP' not in os.environ.keys():
os.environ['GITIAN_HOST_IP'] = '10.0.3.1'
- if not 'LXC_GUEST_IP' in os.environ.keys():
+ if 'LXC_GUEST_IP' not in os.environ.keys():
os.environ['LXC_GUEST_IP'] = '10.0.3.5'
+ if args.setup:
+ setup()
+
+ if args.buildsign:
+ args.build = True
+ args.sign = True
+
+ if not args.build and not args.sign and not args.verify:
+ sys.exit(0)
+
+ args.linux = 'l' in args.os
+ args.windows = 'w' in args.os
+ args.macos = 'm' in args.os
+
# Disable for MacOS if no SDK found
if args.macos and not os.path.isfile('gitian-builder/inputs/MacOSX10.11.sdk.tar.gz'):
print('Cannot build for MacOS, SDK does not exist. Will build for other OSes')
args.macos = False
+ args.sign_prog = 'true' if args.detach_sign else 'gpg --detach-sign'
+
script_name = os.path.basename(sys.argv[0])
- # Signer and version shouldn't be empty
- if args.signer == '':
- print(script_name+': Missing signer.')
+ if not args.signer:
+ print(script_name+': Missing signer')
print('Try '+script_name+' --help for more information')
- exit(1)
- if args.version == '':
- print(script_name+': Missing version.')
+ sys.exit(1)
+ if not args.version:
+ print(script_name+': Missing version')
print('Try '+script_name+' --help for more information')
- exit(1)
+ sys.exit(1)
# Add leading 'v' for tags
if args.commit and args.pull:
raise Exception('Cannot have both commit and pull')
args.commit = ('' if args.commit else 'v') + args.version
- if args.setup:
- setup()
-
os.chdir('bitcoin')
if args.pull:
subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge'])
@@ -220,6 +241,10 @@ def main():
subprocess.check_call(['git', 'checkout', args.commit])
os.chdir(workdir)
+ os.chdir('gitian-builder')
+ subprocess.check_call(['git', 'pull'])
+ os.chdir(workdir)
+
if args.build:
build()
@@ -227,7 +252,10 @@ def main():
sign()
if args.verify:
- verify()
+ os.chdir('gitian.sigs')
+ subprocess.check_call(['git', 'pull'])
+ os.chdir(workdir)
+ sys.exit(verify())
if __name__ == '__main__':
main()
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index e97072c80a..c50750ed44 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -1,6 +1,7 @@
---
-name: "bitcoin-linux-0.18"
+name: "bitcoin-core-linux-0.19"
enable_cache: true
+distro: "ubuntu"
suites:
- "bionic"
architectures:
@@ -30,12 +31,13 @@ packages:
- "faketime"
- "bsdmainutils"
- "ca-certificates"
-- "python"
+- "python3"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
files: []
script: |
+ set -e -o pipefail
WRAP_DIR=$HOME/wrapped
HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu"
@@ -48,8 +50,6 @@ script: |
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
- export GZIP="-9n"
- export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export TZ="UTC"
export BUILD_DIR=`pwd`
mkdir -p ${WRAP_DIR}
@@ -148,8 +148,8 @@ script: |
# Correct tar file order
mkdir -p temp
pushd temp
- tar xf ../$SOURCEDIST
- find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
+ tar -xf ../$SOURCEDIST
+ find bitcoin-* | sort | tar --mtime="$REFERENCE_DATETIME" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
popd
# Workaround for tarball not building with the bare tag version (prep)
@@ -179,11 +179,11 @@ script: |
find . -name "lib*.la" -delete
find . -name "lib*.a" -delete
rm -rf ${DISTNAME}/lib/pkgconfig
- find ${DISTNAME}/bin -type f -executable -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \;
- find ${DISTNAME}/lib -type f -exec ../contrib/devtools/split-debug.sh {} {} {}.dbg \;
+ find ${DISTNAME}/bin -type f -executable -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg
+ find ${DISTNAME}/lib -type f -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg
cp ../doc/README.md ${DISTNAME}/
- find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz
- find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz
+ find ${DISTNAME} -not -name "*.dbg" | 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}-${i}.tar.gz
+ find ${DISTNAME} -name "*.dbg" | 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}-${i}-debug.tar.gz
cd ../../
rm -rf distsrc-${i}
done
diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml
index 297a136fae..4cfca403b1 100644
--- a/contrib/gitian-descriptors/gitian-osx-signer.yml
+++ b/contrib/gitian-descriptors/gitian-osx-signer.yml
@@ -1,5 +1,6 @@
---
name: "bitcoin-dmg-signer"
+distro: "ubuntu"
suites:
- "bionic"
architectures:
@@ -12,6 +13,8 @@ remotes:
files:
- "bitcoin-osx-unsigned.tar.gz"
script: |
+ set -e -o pipefail
+
WRAP_DIR=$HOME/wrapped
mkdir -p ${WRAP_DIR}
export PATH=`pwd`:$PATH
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 87d8007ccb..8c51ce7159 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -1,6 +1,7 @@
---
-name: "bitcoin-osx-0.18"
+name: "bitcoin-core-osx-0.19"
enable_cache: true
+distro: "ubuntu"
suites:
- "bionic"
architectures:
@@ -23,9 +24,9 @@ packages:
- "libcap-dev"
- "libz-dev"
- "libbz2-dev"
-- "python"
-- "python-dev"
-- "python-setuptools"
+- "python3"
+- "python3-dev"
+- "python3-setuptools"
- "fonts-tuffy"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
@@ -33,6 +34,8 @@ remotes:
files:
- "MacOSX10.11.sdk.tar.gz"
script: |
+ set -e -o pipefail
+
WRAP_DIR=$HOME/wrapped
HOSTS="x86_64-apple-darwin14"
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage"
@@ -41,8 +44,6 @@ script: |
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
- export GZIP="-9n"
- export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export TZ="UTC"
export BUILD_DIR=`pwd`
mkdir -p ${WRAP_DIR}
@@ -111,8 +112,8 @@ script: |
# Correct tar file order
mkdir -p temp
pushd temp
- tar xf ../$SOURCEDIST
- find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
+ tar -xf ../$SOURCEDIST
+ find bitcoin-* | sort | tar --mtime="$REFERENCE_DATETIME" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
popd
# Workaround for tarball not building with the bare tag version (prep)
@@ -149,7 +150,7 @@ script: |
cp ${BASEPREFIX}/${i}/native/bin/${i}-pagestuff unsigned-app-${i}/pagestuff
mv dist unsigned-app-${i}
pushd unsigned-app-${i}
- find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz
+ 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
popd
make deploy
@@ -159,7 +160,7 @@ script: |
find . -name "lib*.la" -delete
find . -name "lib*.a" -delete
rm -rf ${DISTNAME}/lib/pkgconfig
- find ${DISTNAME} | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz
+ find ${DISTNAME} | 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}-${i}.tar.gz
cd ../../
done
mkdir -p $OUTDIR/src
diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml
index 045be873e9..656c6d9b7a 100644
--- a/contrib/gitian-descriptors/gitian-win-signer.yml
+++ b/contrib/gitian-descriptors/gitian-win-signer.yml
@@ -1,5 +1,6 @@
---
name: "bitcoin-win-signer"
+distro: "ubuntu"
suites:
- "bionic"
architectures:
@@ -16,6 +17,8 @@ files:
- "osslsigncode-Backports-to-1.7.1.patch"
- "bitcoin-win-unsigned.tar.gz"
script: |
+ set -e -o pipefail
+
BUILD_DIR=`pwd`
SIGDIR=${BUILD_DIR}/signature/win
UNSIGNED_DIR=${BUILD_DIR}/unsigned
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 31b9c309c7..f227c6ad92 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -1,6 +1,7 @@
---
-name: "bitcoin-win-0.18"
+name: "bitcoin-core-win-0.19"
enable_cache: true
+distro: "ubuntu"
suites:
- "bionic"
architectures:
@@ -20,15 +21,17 @@ packages:
- "nsis"
- "zip"
- "ca-certificates"
-- "python"
+- "python3"
- "rename"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
files: []
script: |
+ set -e -o pipefail
+
WRAP_DIR=$HOME/wrapped
- HOSTS="i686-w64-mingw32 x86_64-w64-mingw32"
+ HOSTS="x86_64-w64-mingw32"
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests"
FAKETIME_HOST_PROGS="ar ranlib nm windres strip objcopy"
FAKETIME_PROGS="date makensis zip"
@@ -37,8 +40,6 @@ script: |
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
- export GZIP="-9n"
- export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export TZ="UTC"
export BUILD_DIR=`pwd`
mkdir -p ${WRAP_DIR}
@@ -127,8 +128,8 @@ script: |
# Correct tar file order
mkdir -p temp
pushd temp
- tar xf ../$SOURCEDIST
- find bitcoin-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
+ tar -xf ../$SOURCEDIST
+ find bitcoin-* | sort | tar --mtime="$REFERENCE_DATETIME" --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
mkdir -p $OUTDIR/src
cp ../$SOURCEDIST $OUTDIR/src
popd
@@ -174,8 +175,6 @@ script: |
cd $BUILD_DIR/windeploy
mkdir unsigned
cp $OUTDIR/bitcoin-*setup-unsigned.exe unsigned/
- find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz
+ 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}-win-unsigned.tar.gz
mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip
- mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip
mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip
- mv ${OUTDIR}/${DISTNAME}-i686-*.zip ${OUTDIR}/${DISTNAME}-win32.zip
diff --git a/contrib/gitian-keys/keys.txt b/contrib/gitian-keys/keys.txt
index 80c18aa889..33f0f7e5b0 100644
--- a/contrib/gitian-keys/keys.txt
+++ b/contrib/gitian-keys/keys.txt
@@ -6,6 +6,7 @@ C519EBCF3B926298946783EFF6430754120EC2F4 Christian Decker (cdecker)
F20F56EF6A067F70E8A5C99FFF95FAA971697405 centaur
C060A6635913D98A3587D7DB1C2491FFEB0EF770 Cory Fields
BF6273FAEF7CC0BA1F562E50989F6B3048A116B5 Dev Random
+6D3170C1DC2C6FD0AEEBCA6743811D1A26623924 Douglas Roark
9A1689B60D1B3CCE9262307A2F40A9BF167FBA47 Erik Mossberg (erkmos)
D35176BE9264832E4ACA8986BF0792FBE95DC863 fivepiece
01CDF4627A3B88AAE4A571C87588242FBE38D3A8 Gavin Andresen
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
index 088d1c9dce..47594a5b0a 100755
--- a/contrib/install_db4.sh
+++ b/contrib/install_db4.sh
@@ -70,6 +70,20 @@ CLANG_CXX11_PATCH_HASH='7a9a47b03fd5fb93a16ef42235fa9512db9b0829cfc3bdf90edd3ec1
http_get "${CLANG_CXX11_PATCH_URL}" clang.patch "${CLANG_CXX11_PATCH_HASH}"
patch -p2 < clang.patch
+# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
+# Replace them with modern versions.
+# See https://github.com/bitcoin/bitcoin/issues/16064
+CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b'
+CONFIG_GUESS_HASH='2d1ff7bca773d2ec3c6217118129220fa72d8adda67c7d2bf79994b3129232c1'
+CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b'
+CONFIG_SUB_HASH='3a4befde9bcdf0fdb2763fc1bfa74e8696df94e1ad7aac8042d133c8ff1d2e32'
+
+rm -f "dist/config.guess"
+rm -f "dist/config.sub"
+
+http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}"
+http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}"
+
cd build_unix/
"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \
diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md
index 2985106982..25a1c7351a 100644
--- a/contrib/linearize/README.md
+++ b/contrib/linearize/README.md
@@ -1,6 +1,5 @@
# Linearize
-Construct a linear, no-fork, best version of the Bitcoin blockchain. The scripts
-run using Python 3 but are compatible with Python 2.
+Construct a linear, no-fork, best version of the Bitcoin blockchain.
## Step 1: Download hash list
diff --git a/contrib/linearize/linearize-data.py b/contrib/linearize/linearize-data.py
index 56c1fbfc92..468aec04b5 100755
--- a/contrib/linearize/linearize-data.py
+++ b/contrib/linearize/linearize-data.py
@@ -16,7 +16,7 @@ import hashlib
import datetime
import time
from collections import namedtuple
-from binascii import hexlify, unhexlify
+from binascii import unhexlify
settings = {}
@@ -61,7 +61,7 @@ def calc_hash_str(blk_hdr):
hash = calc_hdr_hash(blk_hdr)
hash = bufreverse(hash)
hash = wordreverse(hash)
- hash_str = hexlify(hash).decode('utf-8')
+ hash_str = hash.hex()
return hash_str
def get_blk_dt(blk_hdr):
@@ -213,7 +213,7 @@ class BlockDataCopier:
inMagic = inhdr[:4]
if (inMagic != self.settings['netmagic']):
- print("Invalid magic: " + hexlify(inMagic).decode('utf-8'))
+ print("Invalid magic: " + inMagic.hex())
return
inLenLE = inhdr[4:]
su = struct.unpack("<I", inLenLE)
diff --git a/contrib/seeds/makeseeds.py b/contrib/seeds/makeseeds.py
index 6527deccf2..523386e393 100755
--- a/contrib/seeds/makeseeds.py
+++ b/contrib/seeds/makeseeds.py
@@ -109,18 +109,30 @@ def filtermultiport(ips):
# Based on Greg Maxwell's seed_filter.py
def filterbyasn(ips, max_per_asn, max_total):
# Sift out ips by type
- ips_ipv4 = [ip for ip in ips if ip['net'] == 'ipv4']
- ips_ipv6 = [ip for ip in ips if ip['net'] == 'ipv6']
+ ips_ipv46 = [ip for ip in ips if ip['net'] in ['ipv4', 'ipv6']]
ips_onion = [ip for ip in ips if ip['net'] == 'onion']
- # Filter IPv4 by ASN
+ # Filter IPv46 by ASN
result = []
asn_count = {}
- for ip in ips_ipv4:
+ for ip in ips_ipv46:
if len(result) == max_total:
break
try:
- asn = int([x.to_text() for x in dns.resolver.query('.'.join(reversed(ip['ip'].split('.'))) + '.origin.asn.cymru.com', 'TXT').response.answer][0].split('\"')[1].split(' ')[0])
+ if ip['net'] == 'ipv4':
+ ipaddr = ip['ip']
+ prefix = '.origin'
+ else: # http://www.team-cymru.com/IP-ASN-mapping.html
+ res = str() # 2001:4860:b002:23::68
+ for nb in ip['ip'].split(':')[:4]: # pick the first 4 nibbles
+ for c in nb.zfill(4): # right padded with '0'
+ res += c + '.' # 2001 4860 b002 0023
+ ipaddr = res.rstrip('.') # 2.0.0.1.4.8.6.0.b.0.0.2.0.0.2.3
+ prefix = '.origin6'
+
+ asn = int([x.to_text() for x in dns.resolver.query('.'.join(
+ reversed(ipaddr.split('.'))) + prefix + '.asn.cymru.com',
+ 'TXT').response.answer][0].split('\"')[1].split(' ')[0])
if asn not in asn_count:
asn_count[asn] = 0
if asn_count[asn] == max_per_asn:
@@ -130,10 +142,7 @@ def filterbyasn(ips, max_per_asn, max_total):
except:
sys.stderr.write('ERR: Could not resolve ASN for "' + ip['ip'] + '"\n')
- # TODO: filter IPv6 by ASN
-
- # Add back non-IPv4
- result.extend(ips_ipv6)
+ # Add back Onions
result.extend(ips_onion)
return result
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
index a10da9d822..27fede6277 100644
--- a/contrib/verify-commits/trusted-keys
+++ b/contrib/verify-commits/trusted-keys
@@ -3,3 +3,4 @@
32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC
B8B3F1C0E58C15DB6A81D30C3648A882F4316B9B
CA03882CB1FC067B5D3ACFE4D300116E1C875A3D
+E777299FC265DD04793070EB944D35F9AC3DB76A
diff --git a/contrib/verify-commits/verify-commits.py b/contrib/verify-commits/verify-commits.py
index 6bbed01073..255ce75092 100755
--- a/contrib/verify-commits/verify-commits.py
+++ b/contrib/verify-commits/verify-commits.py
@@ -5,6 +5,7 @@
"""Verify commits against a trusted keys list."""
import argparse
import hashlib
+import logging
import os
import subprocess
import sys
@@ -66,6 +67,11 @@ def tree_sha512sum(commit='HEAD'):
return overall.hexdigest()
def main():
+
+ # Enable debug logging if running in CI
+ if 'CI' in os.environ and os.environ['CI'].lower() == "true":
+ logging.getLogger().setLevel(logging.DEBUG)
+
# Parse arguments
parser = argparse.ArgumentParser(usage='%(prog)s [options] [commit id]')
parser.add_argument('--disable-tree-check', action='store_false', dest='verify_tree', help='disable SHA-512 tree check')
@@ -95,6 +101,10 @@ def main():
# Iterate through commits
while True:
+
+ # Log a message to prevent Travis from timing out
+ logging.debug("verify-commits: [in-progress] processing commit {}".format(current_commit[:8]))
+
if current_commit == verified_root:
print('There is a valid path from "{}" to {} where all commits are signed!'.format(initial_commit, verified_root))
sys.exit(0)
diff --git a/contrib/windeploy/win-codesign.cert b/contrib/windeploy/win-codesign.cert
index 200b30a3f0..5bc5dc5809 100644
--- a/contrib/windeploy/win-codesign.cert
+++ b/contrib/windeploy/win-codesign.cert
@@ -1,99 +1,100 @@
-----BEGIN CERTIFICATE-----
-MIIFTTCCBDWgAwIBAgIRALlW05RLwG2hMQMX5d/o5J8wDQYJKoZIhvcNAQELBQAw
-fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxIzAhBgNV
-BAMTGkNPTU9ETyBSU0EgQ29kZSBTaWduaW5nIENBMB4XDTE2MDIwMzAwMDAwMFoX
-DTE5MDMwNTIzNTk1OVowgbUxCzAJBgNVBAYTAlVTMQ4wDAYDVQQRDAU5ODEwNDEL
-MAkGA1UECAwCV0ExEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAkMB1N0ZSAzMDAx
-FzAVBgNVBAkMDjcxIENvbHVtYmlhIFN0MSUwIwYDVQQKDBxUaGUgQml0Y29pbiBG
-b3VuZGF0aW9uLCBJbmMuMSUwIwYDVQQDDBxUaGUgQml0Y29pbiBGb3VuZGF0aW9u
-LCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw37Vrv9Gbku0
-+kuV0t89TuyxtAcmT7QE4GcwESKKjmkxfzD9a0qlhqk8GfQ+fw4DHNN+nLKNv7xB
-bk6aS7J2v2DcXkOjrP99P9jqgTkp7MC04VtG3OqVRGB+gum0pptRovYZUQXIdkY7
-GJOok/NDagwKiiUe2V2meZ7UctsZNvYeilQdTgKIIhrMB9NowCOhT8ocVL4Ki55/
-l7hukJn3fueCM3fHTwY2/1gaGsOHoCkFRsD7vokjAVpiY+8rUgvHjb0gxgojiVGd
-6a6/F5XJwKJacvUyN4Hfc2K5lRMQjTTmo4aWNWIa0iJ3TK9BHpdSLJBqerMPvmnM
-kkapS+ZTNQIDAQABo4IBjTCCAYkwHwYDVR0jBBgwFoAUKZFg/4pN+uv5pmq4z/nm
-S71JzhIwHQYDVR0OBBYEFONpQ+cV82URVe+V8G57377KxxexMA4GA1UdDwEB/wQE
-AwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG
-+EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDAjArMCkGCCsGAQUF
-BwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBDBgNVHR8EPDA6MDig
-NqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDb2RlU2lnbmlu
-Z0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYIKwYBBQUHMAKGMmh0dHA6Ly9jcnQu
-Y29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVTaWduaW5nQ0EuY3J0MCQGCCsGAQUF
-BzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQELBQADggEB
-AGnBSi9K/9rgTAyKFKrfGWSfNOwAghmsnsvpZSQ7QyoGWBFKSgCs/70kErl18oHA
-g7Y8loQB1yukZmJaCa3OvGud7smn45TCh0TMf4EpP20Wxf4rMQTxwAatasHL3+vi
-I+Nl5bsRZ09kWjvayqLII5upjS/yq0JfpmyGl5k2C/fIpztq0iOLvqWlXcL4+51r
-cMUAfX6E6EaZQm//ikp+w2+7MEXTKguOuV3gwsrTy0DsvkZl4YDgx/FA4ImzXopv
-d+3KJPLvO+OSBqUD3JPwXHnuJqGAbLBFyyCa/feGUjLlR8cxcNWLWdp4qxtoIUPG
-3wTsC9YgrglS0F7FKMXlNRY=
+MIIFcTCCBFmgAwIBAgIRALWcUnSOxv9FQW3xdaMDO6swDQYJKoZIhvcNAQELBQAw
+fDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQD
+ExtTZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcgQ0EwHhcNMTkwMzI3MDAwMDAwWhcN
+MjAwMzI2MjM1OTU5WjCBtDELMAkGA1UEBhMCQ0gxDTALBgNVBBEMBDgwMDUxCzAJ
+BgNVBAgMAlpIMRAwDgYDVQQHDAdaw7xyaWNoMRcwFQYDVQQJDA5NYXR0ZW5nYXNz
+ZSAyNzEuMCwGA1UECgwlQml0Y29pbiBDb3JlIENvZGUgU2lnbmluZyBBc3NvY2lh
+dGlvbjEuMCwGA1UEAwwlQml0Y29pbiBDb3JlIENvZGUgU2lnbmluZyBBc3NvY2lh
+dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK04VDwiY1wxcW3E
+WTTGmnbciCwETwC96DG4qcoH2PPNsVy3dfwGh0C02Qj2vL64IfwIGUFSgREvyjZk
+CNhEuJO2e0nO0rKNNH5v/JO+P7/VYPZkF5a3uUz9ulmihULXioieHB/q0l6BmiJL
++cYaMVfidL9Y+IJwgiTqjnpRhv1Ik083SPsu6GcfQT9MJfY/+xse2EP0l4GfdFE6
+DRcWjiC8UHpfpGYcImzSFZZpbFbqoAyhueCl28QU4f8QAbS6BqNfaAK9MMACWDcK
+eTz3C5JK6CiUxOnGIxilXhljuybFUjR4jGl5eTRpuPWk95NTTYS36q+bx/1nYelx
+0n4nnDMCAwEAAaOCAbMwggGvMB8GA1UdIwQYMBaAFA7hOqhTOjHVir7Bu61nGgOF
+rTQOMB0GA1UdDgQWBBRbN7ECrPCdVvh58enwy3Dix46h2jAOBgNVHQ8BAf8EBAMC
+B4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzARBglghkgBhvhC
+AQEEBAMCBBAwQAYDVR0gBDkwNzA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcC
+ARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwQwYDVR0fBDwwOjA4oDagNIYyaHR0
+cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ29kZVNpZ25pbmdDQS5jcmww
+cwYIKwYBBQUHAQEEZzBlMD4GCCsGAQUFBzAChjJodHRwOi8vY3J0LnNlY3RpZ28u
+Y29tL1NlY3RpZ29SU0FDb2RlU2lnbmluZ0NBLmNydDAjBggrBgEFBQcwAYYXaHR0
+cDovL29jc3Auc2VjdGlnby5jb20wKwYDVR0RBCQwIoEgam9uYXNAYml0Y29pbmNv
+cmVjb2Rlc2lnbmluZy5vcmcwDQYJKoZIhvcNAQELBQADggEBAF/AIXcFBWCC2Red
+SHN4Cvko5mdSkDNgzjVFc+OwAJ5RdOgbERde4PnHm3Qmrnx+uMetVnmrC8Fv1Iwb
+kkR0bdbWBj6lF6zMsClIN6WJEfY+qfj1qi7wyucu+3OElYRC9bm5Lf0mEHQr8lJ1
+lGvAjPh+/hmxoVNbHFMZ1Ea+BrbjVwiSznt0gzdMh0CispBZKLWCIwRwi+hFjQrw
+Z7RLH8HeCJ5Ojl/OTDQqh6AylQ7l9w9KHsUt4Jqy/AnCCyAj2/6xjdwnuo3tCZwb
+g/9CydiAacD/83odphEeC2iBa+0wsj9bWmyYKY7S9n0u+wm3wBfZbSVMDDPk/la1
+3qCUDLk=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIF4DCCA8igAwIBAgIQLnyHzA6TSlL+lP0ct800rzANBgkqhkiG9w0BAQwFADCB
-hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
-BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTMwNTA5
-MDAwMDAwWhcNMjgwNTA4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkGA1UECBMS
-R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD
-T01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNpZ25p
-bmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmmJBjd5E0f4rR
-3elnMRHrzB79MR2zuWJXP5O8W+OfHiQyESdrvFGRp8+eniWzX4GoGA8dHiAwDvth
-e4YJs+P9omidHCydv3Lj5HWg5TUjjsmK7hoMZMfYQqF7tVIDSzqwjiNLS2PgIpQ3
-e9V5kAoUGFEs5v7BEvAcP2FhCoyi3PbDMKrNKBh1SMF5WgjNu4xVjPfUdpA6M0ZQ
-c5hc9IVKaw+A3V7Wvf2pL8Al9fl4141fEMJEVTyQPDFGy3CuB6kK46/BAW+QGiPi
-XzjbxghdR7ODQfAuADcUuRKqeZJSzYcPe9hiKaR+ML0btYxytEjy4+gh+V5MYnmL
-Agaff9ULAgMBAAGjggFRMIIBTTAfBgNVHSMEGDAWgBS7r34CPfqm8TyEjq3uOJjs
-2TIy1DAdBgNVHQ4EFgQUKZFg/4pN+uv5pmq4z/nmS71JzhIwDgYDVR0PAQH/BAQD
-AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEQYD
-VR0gBAowCDAGBgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuY29t
-b2RvY2EuY29tL0NPTU9ET1JTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHEG
-CCsGAQUFBwEBBGUwYzA7BggrBgEFBQcwAoYvaHR0cDovL2NydC5jb21vZG9jYS5j
-b20vQ09NT0RPUlNBQWRkVHJ1c3RDQS5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
-Y3NwLmNvbW9kb2NhLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAAj8COcPu+Mo7id4M
-bU2x8U6ST6/COCwEzMVjEasJY6+rotcCP8xvGcM91hoIlP8l2KmIpysQGuCbsQci
-GlEcOtTh6Qm/5iR0rx57FjFuI+9UUS1SAuJ1CAVM8bdR4VEAxof2bO4QRHZXavHf
-WGshqknUfDdOvf+2dVRAGDZXZxHNTwLk/vPa/HUX2+y392UJI0kfQ1eD6n4gd2HI
-TfK7ZU2o94VFB696aSdlkClAi997OlE5jKgfcHmtbUIgos8MbAOMTM1zB5TnWo46
-BLqioXwfy2M6FafUFRunUkcyqfS/ZEfRqh9TTjIwc8Jvt3iCnVz/RrtrIh2IC/gb
-qjSm/Iz13X9ljIwxVzHQNuxHoc/Li6jvHBhYxQZ3ykubUa9MCEp6j+KjUuKOjswm
-5LLY5TjCqO3GgZw1a6lYYUoKl7RLQrZVnb6Z53BtWfhtKgx/GWBfDJqIbDCsUgmQ
-Fhv/K53b0CDKieoofjKOGd97SDMe12X4rsn4gxSTdn1k0I7OvjV9/3IxTZ+evR5s
-L6iPDAZQ+4wns3bJ9ObXwzTijIchhmH+v1V04SF3AwpobLvkyanmz1kl63zsRQ55
-ZmjoIs2475iFTZYRPAmK0H+8KCgT+2rKVI2SXM3CZZgGns5IW9S1N5NGQXwH3c/6
-Q++6Z2H/fUnguzB9XIDj5hY5S6c=
+MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
+iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
+cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
+BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
+MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
+dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
+3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
+tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
+Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
+VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
+79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
+c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
+Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
+c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
+UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
+Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
+BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
+A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
+Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
+VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
+ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
+8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
+iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
+Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
+XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
+qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
+VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
+L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
+jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
-hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
-BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
-MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
-EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
-Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
-6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
-pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
-9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
-/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
-Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
-+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
-qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
-SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
-u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
-Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
-crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
-FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
-/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
-wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
-4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
-2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
-FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
-CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
-boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
-jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
-S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
-QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
-0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
-NVOFBkpdn627G190
+MIIF9TCCA92gAwIBAgIQHaJIMG+bJhjQguCWfTPTajANBgkqhkiG9w0BAQwFADCB
+iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
+cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
+BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
+MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjB8MQswCQYDVQQGEwJHQjEbMBkGA1UE
+CBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQK
+Ew9TZWN0aWdvIExpbWl0ZWQxJDAiBgNVBAMTG1NlY3RpZ28gUlNBIENvZGUgU2ln
+bmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIYijTKFehif
+SfCWL2MIHi3cfJ8Uz+MmtiVmKUCGVEZ0MWLFEO2yhyemmcuVMMBW9aR1xqkOUGKl
+UZEQauBLYq798PgYrKf/7i4zIPoMGYmobHutAMNhodxpZW0fbieW15dRhqb0J+V8
+aouVHltg1X7XFpKcAC9o95ftanK+ODtj3o+/bkxBXRIgCFnoOc2P0tbPBrRXBbZO
+oT5Xax+YvMRi1hsLjcdmG0qfnYHEckC14l/vC0X/o84Xpi1VsLewvFRqnbyNVlPG
+8Lp5UEks9wO5/i9lNfIi6iwHr0bZ+UYc3Ix8cSjz/qfGFN1VkW6KEQ3fBiSVfQ+n
+oXw62oY1YdMCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvA
+nfKyA2bLMB0GA1UdDgQWBBQO4TqoUzox1Yq+wbutZxoDha00DjAOBgNVHQ8BAf8E
+BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcDAwYI
+KwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGGP2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6
+Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAl
+BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0B
+AQwFAAOCAgEATWNQ7Uc0SmGk295qKoyb8QAAHh1iezrXMsL2s+Bjs/thAIiaG20Q
+BwRPvrjqiXgi6w9G7PNGXkBGiRL0C3danCpBOvzW9Ovn9xWVM8Ohgyi33i/klPeF
+M4MtSkBIv5rCT0qxjyT0s4E307dksKYjalloUkJf/wTr4XRleQj1qZPea3FAmZa6
+ePG5yOLDCBaxq2NayBWAbXReSnV+pbjDbLXP30p5h1zHQE1jNfYw08+1Cg4LBH+g
+S667o6XQhACTPlNdNKUANWlsvp8gJRANGftQkGG+OY96jk32nw4e/gdREmaDJhlI
+lc5KycF/8zoFm/lv34h/wCOe0h5DekUxwZxNqfBZslkZ6GqNKQQCd3xLS81wvjqy
+VVp4Pry7bwMQJXcVNIr5NsxDkuS6T/FikyglVyn7URnHoSVAaoRXxrKdsbwcCtp8
+Z359LukoTBh+xHsxQXGaSynsCz1XUNLK3f2eBVHlRHjdAd6xdZgNVCT98E7j4viD
+vXK6yz067vBeF5Jobchh+abxKgoLpbn0nu6YMgWFnuv5gynTxix9vTp3Los3QqBq
+gu07SqqUEKThDfgXxbZaeTMYkuO1dfih6Y4KJR7kHvGfWocj/5+kUZ77OYARzdu1
+xKeogG/lU9Tg46LC0lsa+jImLWpXcBw8pFguo/NbSwfcMlnzh6cabVg=
-----END CERTIFICATE-----
diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py
deleted file mode 100644
index 66fdf7887f..0000000000
--- a/contrib/zmq/zmq_sub3.4.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-"""
- ZMQ example using python3's asyncio
-
- Bitcoin should be started with the command line arguments:
- bitcoind -testnet -daemon \
- -zmqpubrawtx=tcp://127.0.0.1:28332 \
- -zmqpubrawblock=tcp://127.0.0.1:28332 \
- -zmqpubhashtx=tcp://127.0.0.1:28332 \
- -zmqpubhashblock=tcp://127.0.0.1:28332
-
- We use the asyncio library here. `self.handle()` installs itself as a
- future at the end of the function. Since it never returns with the event
- loop having an empty stack of futures, this creates an infinite loop. An
- alternative is to wrap the contents of `handle` inside `while True`.
-
- The `@asyncio.coroutine` decorator and the `yield from` syntax found here
- was introduced in python 3.4 and has been deprecated in favor of the `async`
- and `await` keywords respectively.
-
- A blocking example using python 2.7 can be obtained from the git history:
- https://github.com/bitcoin/bitcoin/blob/37a7fe9e440b83e2364d5498931253937abe9294/contrib/zmq/zmq_sub.py
-"""
-
-import binascii
-import asyncio
-import zmq
-import zmq.asyncio
-import signal
-import struct
-import sys
-
-if (sys.version_info.major, sys.version_info.minor) < (3, 4):
- print("This example only works with Python 3.4 and greater")
- sys.exit(1)
-
-port = 28332
-
-class ZMQHandler():
- def __init__(self):
- self.loop = asyncio.get_event_loop()
- self.zmqContext = zmq.asyncio.Context()
-
- self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
- self.zmqSubSocket.setsockopt(zmq.RCVHWM, 0)
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashblock")
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "hashtx")
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawblock")
- self.zmqSubSocket.setsockopt_string(zmq.SUBSCRIBE, "rawtx")
- self.zmqSubSocket.connect("tcp://127.0.0.1:%i" % port)
-
- @asyncio.coroutine
- def handle(self) :
- msg = yield from self.zmqSubSocket.recv_multipart()
- topic = msg[0]
- body = msg[1]
- sequence = "Unknown"
- if len(msg[-1]) == 4:
- msgSequence = struct.unpack('<I', msg[-1])[-1]
- sequence = str(msgSequence)
- if topic == b"hashblock":
- print('- HASH BLOCK ('+sequence+') -')
- print(binascii.hexlify(body))
- elif topic == b"hashtx":
- print('- HASH TX ('+sequence+') -')
- print(binascii.hexlify(body))
- elif topic == b"rawblock":
- print('- RAW BLOCK HEADER ('+sequence+') -')
- print(binascii.hexlify(body[:80]))
- elif topic == b"rawtx":
- print('- RAW TX ('+sequence+') -')
- print(binascii.hexlify(body))
- # schedule ourselves to receive the next message
- asyncio.ensure_future(self.handle())
-
- def start(self):
- self.loop.add_signal_handler(signal.SIGINT, self.stop)
- self.loop.create_task(self.handle())
- self.loop.run_forever()
-
- def stop(self):
- self.loop.stop()
- self.zmqContext.destroy()
-
-daemon = ZMQHandler()
-daemon.start()
diff --git a/depends/Makefile b/depends/Makefile
index 50cc77ddeb..70af875189 100644
--- a/depends/Makefile
+++ b/depends/Makefile
@@ -7,6 +7,7 @@ SDK_PATH ?= $(BASEDIR)/SDKs
NO_QT ?=
RAPIDCHECK ?=
NO_WALLET ?=
+NO_ZMQ ?=
NO_UPNP ?=
FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources
@@ -93,6 +94,7 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null)
qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages)
wallet_packages_$(NO_WALLET) = $(wallet_packages)
upnp_packages_$(NO_UPNP) = $(upnp_packages)
+zmq_packages_$(NO_ZMQ) = $(zmq_packages)
rapidcheck_packages_$(RAPIDCHECK) = $(rapidcheck_packages)
@@ -103,6 +105,10 @@ ifneq ($(qt_packages_),)
native_packages += $(qt_native_packages)
endif
+ifneq ($(zmq_packages_),)
+packages += $(zmq_packages)
+endif
+
ifeq ($(rapidcheck_packages_),)
packages += $(rapidcheck_packages)
endif
@@ -143,6 +149,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_
-e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \
-e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \
-e 's|@no_qt@|$(NO_QT)|' \
+ -e 's|@no_zmq@|$(NO_ZMQ)|' \
-e 's|@no_wallet@|$(NO_WALLET)|' \
-e 's|@no_upnp@|$(NO_UPNP)|' \
-e 's|@debug@|$(DEBUG)|' \
@@ -192,4 +199,6 @@ download-win:
@$(MAKE) -s HOST=x86_64-w64-mingw32 download-one
download: download-osx download-linux download-win
+$(foreach package,$(all_packages),$(eval $(call ext_add_stages,$(package))))
+
.PHONY: install cached clean clean-all download-one download-osx download-linux download-win download check-packages check-sources
diff --git a/depends/README.md b/depends/README.md
index 693bc36197..6dbe365545 100644
--- a/depends/README.md
+++ b/depends/README.md
@@ -20,7 +20,6 @@ created. To use it for Bitcoin:
Common `host-platform-triplets` for cross compilation are:
-- `i686-w64-mingw32` for Win32
- `x86_64-w64-mingw32` for Win64
- `x86_64-apple-darwin14` for macOS
- `arm-linux-gnueabihf` for Linux ARM 32 bit
@@ -34,7 +33,7 @@ No other options are needed, the paths are automatically configured.
#### For macOS cross compilation
- sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python-setuptools
+ sudo apt-get install curl librsvg2-bin libtiff-tools bsdmainutils cmake imagemagick libcap-dev libz-dev libbz2-dev python3-setuptools
#### For Win32/Win64 cross compilation
@@ -44,7 +43,7 @@ No other options are needed, the paths are automatically configured.
Common linux dependencies:
- sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3
+ sudo apt-get install make automake cmake curl g++-multilib libtool binutils-gold bsdmainutils pkg-config python3 patch
For linux ARM cross compilation:
@@ -69,10 +68,11 @@ The following can be set when running make: make FOO=bar
SDK_PATH: Path where sdk's 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_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_UPNP: Don't download/build/cache packages needed for enabling upnp
DEBUG: disable some optimizations and enable more runtime checking
- RAPIDCHECK: build rapidcheck (experimental)
+ RAPIDCHECK: build rapidcheck (experimental, requires cmake)
HOST_ID_SALT: Optional salt to use when generating host package ids
BUILD_ID_SALT: Optional salt to use when generating build package ids
diff --git a/depends/config.site.in b/depends/config.site.in
index b7a5e795c8..e633752066 100644
--- a/depends/config.site.in
+++ b/depends/config.site.in
@@ -33,6 +33,10 @@ if test -z $with_gui && test -n "@no_qt@"; then
with_gui=no
fi
+if test -z $enable_zmq && test -n "@no_zmq@"; then
+ enable_zmq=no
+fi
+
if test x@host_os@ = xdarwin; then
BREW=no
PORT=no
@@ -67,7 +71,7 @@ fi
if test -n "@CXX@" -a -z "${CXX}"; then
CXX="@CXX@"
fi
-PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH
+PYTHONPATH=$depends_prefix/native/lib/python3/dist-packages:$PYTHONPATH
if test -n "@AR@"; then
AR=@AR@
diff --git a/depends/funcs.mk b/depends/funcs.mk
index 15e404e42d..8f03c5f37a 100644
--- a/depends/funcs.mk
+++ b/depends/funcs.mk
@@ -76,8 +76,9 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path))
#default commands
+# The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior
$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash))
-$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source)
+$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --no-same-owner --strip-components=1 -xf $$($(1)_source)
$(1)_preprocess_cmds ?=
$(1)_build_cmds ?=
$(1)_config_cmds ?=
@@ -170,15 +171,15 @@ $($(1)_extracted): | $($(1)_fetched)
$(AT)mkdir -p $$(@D)
$(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1))
$(AT)touch $$@
-$($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted)
+$($(1)_preprocessed): | $($(1)_extracted)
$(AT)echo Preprocessing $(1)...
$(AT)mkdir -p $$(@D) $($(1)_patch_dir)
$(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;)
$(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1))
$(AT)touch $$@
-$($(1)_configured): | $($(1)_preprocessed)
+$($(1)_configured): | $($(1)_dependencies) $($(1)_preprocessed)
$(AT)echo Configuring $(1)...
- $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); )
+ $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar --no-same-owner -xf $($(package)_cached); )
$(AT)mkdir -p $$(@D)
$(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1))
$(AT)touch $$@
@@ -213,6 +214,14 @@ $(1): | $($(1)_cached_checksum)
endef
+stages = fetched extracted preprocessed configured built staged postprocessed cached cached_checksum
+
+define ext_add_stages
+$(foreach stage,$(stages),
+ $(1)_$(stage): $($(1)_$(stage))
+ .PHONY: $(1)_$(stage))
+endef
+
# These functions create the build targets for each package. They must be
# broken down into small steps so that each part is done for all packages
# before moving on to the next step. Otherwise, a package's info
diff --git a/depends/packages.md b/depends/packages.md
index 7c80362509..2c592885b6 100644
--- a/depends/packages.md
+++ b/depends/packages.md
@@ -5,6 +5,10 @@ The package "mylib" will be used here as an example
General tips:
- mylib_foo is written as $(package)_foo in order to make recipes more similar.
+- Secondary dependency packages relative to the bitcoin binaries/libraries (i.e.
+ those not in `ALLOWED_LIBRARIES` in `contrib/devtools/symbol-check.py`) don't
+ need to be shared and should be built statically whenever possible. See
+ [below](#secondary-dependencies) for more details.
## Identifiers
Each package is required to define at least these variables:
@@ -14,8 +18,9 @@ Each package is required to define at least these variables:
placeholder such as 1.0 can be used.
$(package)_download_path:
- Location of the upstream source, without the file-name. Usually http or
- ftp.
+ Location of the upstream source, without the file-name. Usually http, https
+ or ftp. Secure transmission options like https should be preferred if
+ available.
$(package)_file_name:
The upstream source filename available at the download path.
@@ -145,3 +150,34 @@ $($(package)_config_opts) will be appended.
Most autotools projects can be properly staged using:
$(MAKE) DESTDIR=$($(package)_staging_dir) install
+
+## Build outputs:
+
+In general, the output of a depends package should not contain any libtool
+archives. Instead, the package should output `.pc` (`pkg-config`) files where
+possible.
+
+From the [Gentoo Wiki entry](https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Handling_Libtool_Archives):
+
+> Libtool pulls in all direct and indirect dependencies into the .la files it
+> creates. This leads to massive overlinking, which is toxic to the Gentoo
+> ecosystem, as it leads to a massive number of unnecessary rebuilds.
+
+## Secondary dependencies:
+
+Secondary dependency packages relative to the bitcoin binaries/libraries (i.e.
+those not in `ALLOWED_LIBRARIES` in `contrib/devtools/symbol-check.py`) don't
+need to be shared and should be built statically whenever possible. This
+improves general build reliability as illustrated by the following example:
+
+When linking an executable against a shared library `libprimary` that has its
+own shared dependency `libsecondary`, we may need to specify the path to
+`libsecondary` on the link command using the `-rpath/-rpath-link` options, it is
+not sufficient to just say `libprimary`.
+
+For us, it's much easier to just link a static `libsecondary` into a shared
+`libprimary`. Especially because in our case, we are linking against a dummy
+`libprimary` anyway that we'll throw away. We don't care if the end-user has a
+static or dynamic `libseconday`, that's not our concern. With a static
+`libseconday`, when we need to link `libprimary` into our executable, there's no
+dependency chain to worry about as `libprimary` has all the symbols.
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 3cd2e28858..6cdb79592b 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -1,6 +1,6 @@
package=bdb
$(package)_version=4.8.30
-$(package)_download_path=http://download.oracle.com/berkeley-db
+$(package)_download_path=https://download.oracle.com/berkeley-db
$(package)_file_name=db-$($(package)_version).NC.tar.gz
$(package)_sha256_hash=12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef
$(package)_build_subdir=build_unix
diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk
index 61806c7509..5df49b2af8 100644
--- a/depends/packages/boost.mk
+++ b/depends/packages/boost.mk
@@ -1,8 +1,8 @@
package=boost
-$(package)_version=1_64_0
-$(package)_download_path=https://dl.bintray.com/boostorg/release/1.64.0/source/
+$(package)_version=1_70_0
+$(package)_download_path=https://dl.bintray.com/boostorg/release/1.70.0/source/
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
-$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332
+$(package)_sha256_hash=430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778
define $(package)_set_vars
$(package)_config_opts_release=variant=release
diff --git a/depends/packages/dbus.mk b/depends/packages/dbus.mk
index bbe0375409..ad10b0fdd7 100644
--- a/depends/packages/dbus.mk
+++ b/depends/packages/dbus.mk
@@ -6,7 +6,7 @@ $(package)_sha256_hash=6049ddd5f3f3e2618f615f1faeda0a115104423a7996b7aa73e2f36e3
$(package)_dependencies=expat
define $(package)_set_vars
- $(package)_config_opts=--disable-tests --disable-doxygen-docs --disable-xml-docs --disable-static --without-x
+ $(package)_config_opts=--disable-tests --disable-doxygen-docs --disable-xml-docs --disable-shared --without-x
endef
define $(package)_config_cmds
@@ -21,3 +21,7 @@ define $(package)_stage_cmds
$(MAKE) -C dbus DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-dbusincludeHEADERS install-nodist_dbusarchincludeHEADERS && \
$(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/expat.mk b/depends/packages/expat.mk
index 8d06882cdb..b811f84a38 100644
--- a/depends/packages/expat.mk
+++ b/depends/packages/expat.mk
@@ -5,7 +5,8 @@ $(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2
define $(package)_set_vars
-$(package)_config_opts=--disable-static --without-docbook
+ $(package)_config_opts=--disable-shared --without-docbook
+ $(package)_config_opts_linux=--with-pic
endef
define $(package)_config_cmds
@@ -19,3 +20,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/fontconfig.mk b/depends/packages/fontconfig.mk
index 12695db4b9..293631739d 100644
--- a/depends/packages/fontconfig.mk
+++ b/depends/packages/fontconfig.mk
@@ -1,6 +1,6 @@
package=fontconfig
$(package)_version=2.12.1
-$(package)_download_path=http://www.freedesktop.org/software/fontconfig/release/
+$(package)_download_path=https://www.freedesktop.org/software/fontconfig/release/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=b449a3e10c47e1d1c7a6ec6e2016cca73d3bd68fbbd4f0ae5cc6b573f7d6c7f3
$(package)_dependencies=freetype expat
@@ -26,3 +26,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/freetype.mk b/depends/packages/freetype.mk
index 41e02e2030..f24fc69d81 100644
--- a/depends/packages/freetype.mk
+++ b/depends/packages/freetype.mk
@@ -1,6 +1,6 @@
package=freetype
$(package)_version=2.7.1
-$(package)_download_path=http://download.savannah.gnu.org/releases/$(package)
+$(package)_download_path=https://download.savannah.gnu.org/releases/$(package)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=3a3bb2c4e15ffb433f2032f50a5b5a92558206822e22bfe8cbe339af4aa82f88
@@ -20,3 +20,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/libX11.mk b/depends/packages/libX11.mk
index 298616bea4..f46bd9219e 100644
--- a/depends/packages/libX11.mk
+++ b/depends/packages/libX11.mk
@@ -1,13 +1,14 @@
package=libX11
$(package)_version=1.6.2
-$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/
+$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=2aa027e837231d2eeea90f3a4afe19948a6eb4c8b2bec0241eba7dbc8106bd16
$(package)_dependencies=libxcb xtrans xextproto xproto
define $(package)_set_vars
-$(package)_config_opts=--disable-xkb --disable-static
-$(package)_config_opts_linux=--with-pic
+ # See libXext for --disable-malloc0returnsnull rationale.
+ $(package)_config_opts=--disable-xkb --disable-static --disable-malloc0returnsnull
+ $(package)_config_opts_linux=--with-pic
endef
define $(package)_preprocess_cmds
@@ -25,3 +26,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/libXau.mk b/depends/packages/libXau.mk
index 304494e3c5..0e4a60ad25 100644
--- a/depends/packages/libXau.mk
+++ b/depends/packages/libXau.mk
@@ -1,6 +1,6 @@
package=libXau
$(package)_version=1.0.8
-$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/
+$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=fdd477320aeb5cdd67272838722d6b7d544887dfe7de46e1e7cc0c27c2bea4f2
$(package)_dependencies=xproto
@@ -25,3 +25,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/libXext.mk b/depends/packages/libXext.mk
index c0565dd672..77f32a340e 100644
--- a/depends/packages/libXext.mk
+++ b/depends/packages/libXext.mk
@@ -1,12 +1,35 @@
package=libXext
-$(package)_version=1.3.2
-$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/
+$(package)_version=1.3.3
+$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
-$(package)_sha256_hash=f829075bc646cdc085fa25d98d5885d83b1759ceb355933127c257e8e50432e0
+$(package)_sha256_hash=b518d4d332231f313371fdefac59e3776f4f0823bcb23cf7c7305bfb57b16e35
$(package)_dependencies=xproto xextproto libX11 libXau
define $(package)_set_vars
- $(package)_config_opts=--disable-static
+ # A number of steps in the autoconfig process implicitly assume that the build
+ # system and the host system are the same. For example, library components
+ # want to build and run test programs to determine the behavior of certain
+ # host system elements. This is clearly impossible when crosscompiling. To
+ # work around these issues, the --enable-malloc0returnsnull (or
+ # --disable-malloc0returnsnull, depending on the host system) must be passed
+ # to configure.
+ # -- https://www.x.org/wiki/CrossCompilingXorg/
+ #
+ # Concretely, between the releases of libXext 1.3.2 and 1.3.3,
+ # XORG_CHECK_MALLOC_ZERO from xorg-macros was changed to use the autoconf
+ # cache, expecting cross-compilation environments to seed this cache as there
+ # is no single correct value when cross compiling (think uclibc, musl, etc.).
+ # You can see the actual change in commit 72fdc868b56fe2b7bdc9a69872651baeca72
+ # in the freedesktop/xorg-macros repo.
+ #
+ # As a result of this change, if we don't seed the cache and we don't use
+ # either --{en,dis}able-malloc0returnsnull, the AC_RUN_IFELSE block has no
+ # optional action-if-cross-compiling argument and configure prints an error
+ # message and exits as documented in the autoconf manual. Prior to this
+ # commit, the AC_RUN_IFELSE block had an action-if-cross-compiling argument
+ # which set the more pessimistic default value MALLOC_ZERO_RETURNS_NULL=yes.
+ # This is why the flag was not required prior to libXext 1.3.3.
+ $(package)_config_opts=--disable-static --disable-malloc0returnsnull
endef
define $(package)_preprocess_cmds
@@ -24,3 +47,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk
index 5f622f8e6e..a3ade899b7 100644
--- a/depends/packages/libevent.mk
+++ b/depends/packages/libevent.mk
@@ -27,4 +27,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
+ rm lib/*.la
endef
diff --git a/depends/packages/libxcb.mk b/depends/packages/libxcb.mk
index 3f346d9728..9402951826 100644
--- a/depends/packages/libxcb.mk
+++ b/depends/packages/libxcb.mk
@@ -1,6 +1,6 @@
package=libxcb
$(package)_version=1.10
-$(package)_download_path=http://xcb.freedesktop.org/dist
+$(package)_download_path=https://xcb.freedesktop.org/dist
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=98d9ab05b636dd088603b64229dd1ab2d2cc02ab807892e107d674f9c3f2d5b5
$(package)_dependencies=xcb_proto libXau xproto
@@ -32,5 +32,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm -rf share/man share/doc
+ rm -rf share/man share/doc lib/*.la
endef
diff --git a/depends/packages/miniupnpc.mk b/depends/packages/miniupnpc.mk
index 5ad2b580d2..fdbe22cda6 100644
--- a/depends/packages/miniupnpc.mk
+++ b/depends/packages/miniupnpc.mk
@@ -1,6 +1,6 @@
package=miniupnpc
$(package)_version=2.0.20180203
-$(package)_download_path=http://miniupnp.free.fr/files
+$(package)_download_path=https://miniupnp.tuxfamily.org/files/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=90dda8c7563ca6cd4a83e23b3c66dbbea89603a1675bfdb852897c2c9cc220b7
diff --git a/depends/packages/native_biplist.mk b/depends/packages/native_biplist.mk
index 5f247e9bf3..c3054cbd1a 100644
--- a/depends/packages/native_biplist.mk
+++ b/depends/packages/native_biplist.mk
@@ -3,13 +3,13 @@ $(package)_version=1.0.3
$(package)_download_path=https://bitbucket.org/wooster/biplist/downloads
$(package)_file_name=biplist-$($(package)_version).tar.gz
$(package)_sha256_hash=4c0549764c5fe50b28042ec21aa2e14fe1a2224e239a1dae77d9e7f3932aa4c6
-$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
+$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages
define $(package)_build_cmds
- python setup.py build
+ python3 setup.py build
endef
define $(package)_stage_cmds
mkdir -p $($(package)_install_libdir) && \
- python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
+ python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
endef
diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk
index 44d238cc4c..a065256c1c 100644
--- a/depends/packages/native_cctools.mk
+++ b/depends/packages/native_cctools.mk
@@ -5,7 +5,7 @@ $(package)_file_name=$($(package)_version).tar.gz
$(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a
$(package)_build_subdir=cctools
$(package)_clang_version=3.7.1
-$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version)
+$(package)_clang_download_path=https://llvm.org/releases/$($(package)_clang_version)
$(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz
$(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz
$(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9
@@ -22,12 +22,12 @@ define $(package)_extract_cmds
echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \
$(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \
mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \
- tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \
+ tar --no-same-owner --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \
rm -f toolchain/lib/libc++abi.so* && \
echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \
echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \
chmod +x toolchain/bin/$(host)-dsymutil && \
- tar --strip-components=1 -xf $($(package)_source)
+ tar --no-same-owner --strip-components=1 -xf $($(package)_source)
endef
define $(package)_set_vars
diff --git a/depends/packages/native_cdrkit.mk b/depends/packages/native_cdrkit.mk
index cf694edb30..8243458ec8 100644
--- a/depends/packages/native_cdrkit.mk
+++ b/depends/packages/native_cdrkit.mk
@@ -1,6 +1,6 @@
package=native_cdrkit
$(package)_version=1.1.11
-$(package)_download_path=http://distro.ibiblio.org/fatdog/source/600/c
+$(package)_download_path=https://distro.ibiblio.org/fatdog/source/600/c
$(package)_file_name=cdrkit-$($(package)_version).tar.bz2
$(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564
$(package)_patches=cdrkit-deterministic.patch
diff --git a/depends/packages/native_ds_store.mk b/depends/packages/native_ds_store.mk
index 116fa25d38..f99b689ecd 100644
--- a/depends/packages/native_ds_store.mk
+++ b/depends/packages/native_ds_store.mk
@@ -3,14 +3,14 @@ $(package)_version=1.1.2
$(package)_download_path=https://github.com/al45tair/ds_store/archive/
$(package)_file_name=v$($(package)_version).tar.gz
$(package)_sha256_hash=3b3ecb7bf0a5157f5b6010bc3af7c141fb0ad3527084e63336220d22744bc20c
-$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
+$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages
$(package)_dependencies=native_biplist
define $(package)_build_cmds
- python setup.py build
+ python3 setup.py build
endef
define $(package)_stage_cmds
mkdir -p $($(package)_install_libdir) && \
- python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
+ python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
endef
diff --git a/depends/packages/native_mac_alias.mk b/depends/packages/native_mac_alias.mk
index 306c835656..e60b99dccc 100644
--- a/depends/packages/native_mac_alias.mk
+++ b/depends/packages/native_mac_alias.mk
@@ -3,13 +3,13 @@ $(package)_version=2.0.7
$(package)_download_path=https://github.com/al45tair/mac_alias/archive/
$(package)_file_name=v$($(package)_version).tar.gz
$(package)_sha256_hash=6f606d3b6bccd2112aeabf1a063f5b5ece87005a5d7e97c8faca23b916e88838
-$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
+$(package)_install_libdir=$(build_prefix)/lib/python3/dist-packages
define $(package)_build_cmds
- python setup.py build
+ python3 setup.py build
endef
define $(package)_stage_cmds
mkdir -p $($(package)_install_libdir) && \
- python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
+ python3 setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
endef
diff --git a/depends/packages/native_protobuf.mk b/depends/packages/native_protobuf.mk
index ce50b366fa..1de8c37d36 100644
--- a/depends/packages/native_protobuf.mk
+++ b/depends/packages/native_protobuf.mk
@@ -5,7 +5,7 @@ $(package)_file_name=protobuf-$($(package)_version).tar.bz2
$(package)_sha256_hash=ee445612d544d885ae240ffbcbf9267faa9f593b7b101f21d58beceb92661910
define $(package)_set_vars
-$(package)_config_opts=--disable-shared
+$(package)_config_opts=--disable-shared --without-zlib
endef
define $(package)_config_cmds
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index 38329d16d7..9a08e30892 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,4 +1,4 @@
-packages:=boost openssl libevent zeromq
+packages:=boost openssl libevent
qt_native_packages = native_protobuf
qt_packages = qrencode protobuf zlib
@@ -12,6 +12,8 @@ qt_mingw32_packages=qt
wallet_packages=bdb
+zmq_packages=zeromq
+
upnp_packages=miniupnpc
darwin_native_packages = native_biplist native_ds_store native_mac_alias
diff --git a/depends/packages/protobuf.mk b/depends/packages/protobuf.mk
index d201d1183f..52975b14ec 100644
--- a/depends/packages/protobuf.mk
+++ b/depends/packages/protobuf.mk
@@ -30,5 +30,5 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
- rm lib/libprotoc.a
+ rm lib/libprotoc.a lib/*.la
endef
diff --git a/depends/packages/qrencode.mk b/depends/packages/qrencode.mk
index 313e4adf2a..56681b52a1 100644
--- a/depends/packages/qrencode.mk
+++ b/depends/packages/qrencode.mk
@@ -24,3 +24,7 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
+
+define $(package)_postprocess_cmds
+ rm lib/*.la
+endef
diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk
index deebf13e98..23cde9ee6d 100644
--- a/depends/packages/qt.mk
+++ b/depends/packages/qt.mk
@@ -125,11 +125,11 @@ define $(package)_extract_cmds
echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \
$(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \
mkdir qtbase && \
- tar --strip-components=1 -xf $($(package)_source) -C qtbase && \
+ tar --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \
mkdir qttranslations && \
- tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \
+ tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \
mkdir qttools && \
- tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools
+ tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools
endef
define $(package)_preprocess_cmds
@@ -138,7 +138,7 @@ define $(package)_preprocess_cmds
sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \
sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \
sed -i.old "s|X11/extensions/XIproto.h|X11/X.h|" qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp && \
- sed -i.old 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' qtbase/configure && \
+ sed -i.old -e 's/if \[ "$$$$XPLATFORM_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/if \[ "$$$$BUILD_ON_MAC" = "yes" \]; then xspecvals=$$$$(macSDKify/' -e 's|/bin/pwd|pwd|' qtbase/configure && \
sed -i.old 's/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0)/CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft)/' qtbase/src/plugins/platforms/cocoa/qcocoacursor.mm && \
mkdir -p qtbase/mkspecs/macx-clang-linux &&\
cp -f qtbase/mkspecs/macx-clang/Info.plist.lib qtbase/mkspecs/macx-clang-linux/ &&\
diff --git a/depends/packages/rapidcheck.mk b/depends/packages/rapidcheck.mk
index 19cf1cae2e..fa4fb3c782 100644
--- a/depends/packages/rapidcheck.mk
+++ b/depends/packages/rapidcheck.mk
@@ -1,18 +1,21 @@
package=rapidcheck
-$(package)_version=10fc0cb
-$(package)_download_path=https://github.com/MarcoFalke/rapidcheck/archive
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=9640926223c00af45bce4c7df8b756b5458a89b2ba74cfe3e404467f13ce26df
+$(package)_version=3eb9b4ff69f4ff2d9932e8f852c2b2a61d7c20d3
+$(package)_download_path=https://github.com/emil-e/rapidcheck/archive
+$(package)_file_name=$($(package)_version).tar.gz
+$(package)_sha256_hash=5fbf82755c9a647127e62563be079448ff8b1db9ca80a52a673dd9a88fdb714b
define $(package)_config_cmds
- cmake -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true .
+ cmake -DCMAKE_INSTALL_PREFIX=$($(package)_staging_dir)$(host_prefix) -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true -DRC_INSTALL_ALL_EXTRAS=ON
+endef
+
+define $(package)_preprocess_cmds
+ sed -i.old 's/ -Wall//' CMakeLists.txt
endef
define $(package)_build_cmds
- $(MAKE) && \
- mkdir -p $($(package)_staging_dir)$(host_prefix)/include && \
- cp -a include/* $($(package)_staging_dir)$(host_prefix)/include/ && \
- cp -a extras/boost_test/include/rapidcheck/* $($(package)_staging_dir)$(host_prefix)/include/rapidcheck/ && \
- mkdir -p $($(package)_staging_dir)$(host_prefix)/lib && \
- cp -a librapidcheck.a $($(package)_staging_dir)$(host_prefix)/lib/
+ $(MAKE) rapidcheck
+endef
+
+define $(package)_stage_cmds
+ $(MAKE) rapidcheck install
endef
diff --git a/depends/packages/xcb_proto.mk b/depends/packages/xcb_proto.mk
index 0c7c958d62..44110394bd 100644
--- a/depends/packages/xcb_proto.mk
+++ b/depends/packages/xcb_proto.mk
@@ -1,6 +1,6 @@
package=xcb_proto
$(package)_version=1.10
-$(package)_download_path=http://xcb.freedesktop.org/dist
+$(package)_download_path=https://xcb.freedesktop.org/dist
$(package)_file_name=xcb-proto-$($(package)_version).tar.bz2
$(package)_sha256_hash=7ef40ddd855b750bc597d2a435da21e55e502a0fefa85b274f2c922800baaf05
diff --git a/depends/packages/xextproto.mk b/depends/packages/xextproto.mk
index 7065237bd5..157b76edf6 100644
--- a/depends/packages/xextproto.mk
+++ b/depends/packages/xextproto.mk
@@ -1,6 +1,6 @@
package=xextproto
$(package)_version=7.3.0
-$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto
+$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=f3f4b23ac8db9c3a9e0d8edb591713f3d70ef9c3b175970dd8823dfc92aa5bb0
diff --git a/depends/packages/xproto.mk b/depends/packages/xproto.mk
index 5328ec8481..23ad5ffa10 100644
--- a/depends/packages/xproto.mk
+++ b/depends/packages/xproto.mk
@@ -1,6 +1,6 @@
package=xproto
$(package)_version=7.0.26
-$(package)_download_path=http://xorg.freedesktop.org/releases/individual/proto
+$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f
diff --git a/depends/packages/xtrans.mk b/depends/packages/xtrans.mk
index c313b1f609..6201d1d270 100644
--- a/depends/packages/xtrans.mk
+++ b/depends/packages/xtrans.mk
@@ -1,12 +1,12 @@
package=xtrans
$(package)_version=1.3.4
-$(package)_download_path=http://xorg.freedesktop.org/releases/individual/lib/
+$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=054d4ee3efd52508c753e9f7bc655ef185a29bd2850dd9e2fc2ccc33544f583a
$(package)_dependencies=
define $(package)_set_vars
-$(package)_config_opts_linux=--with-pic --disable-static
+ $(package)_config_opts_linux=--disable-docs --without-xmlto --without-fop --without-xsltproc
endef
define $(package)_preprocess_cmds
diff --git a/depends/packages/zeromq.mk b/depends/packages/zeromq.mk
index dfbc50580c..e69a37e093 100644
--- a/depends/packages/zeromq.mk
+++ b/depends/packages/zeromq.mk
@@ -31,5 +31,5 @@ endef
define $(package)_postprocess_cmds
sed -i.old "s/ -lstdc++//" lib/pkgconfig/libzmq.pc && \
- rm -rf bin share
+ rm -rf bin share lib/*.la
endef
diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk
index 589490800f..1600b11a01 100644
--- a/depends/packages/zlib.mk
+++ b/depends/packages/zlib.mk
@@ -1,6 +1,6 @@
package=zlib
$(package)_version=1.2.11
-$(package)_download_path=http://www.zlib.net
+$(package)_download_path=https://www.zlib.net
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
diff --git a/doc/JSON-RPC-interface.md b/doc/JSON-RPC-interface.md
index 982afd5d56..a0cfe84a3e 100644
--- a/doc/JSON-RPC-interface.md
+++ b/doc/JSON-RPC-interface.md
@@ -5,6 +5,18 @@ The headless daemon `bitcoind` has the JSON-RPC API enabled by default, the GUI
option. In the GUI it is possible to execute RPC methods in the Debug Console
Dialog.
+## Versioning
+
+The RPC interface might change from one major version of Bitcoin Core to the
+next. This makes the RPC interface implicitly versioned on the major version.
+The version tuple can be retrieved by e.g. the `getnetworkinfo` RPC in
+`version`.
+
+Usually deprecated features can be re-enabled during the grace-period of one
+major version via the `-deprecatedrpc=` command line option. The release notes
+of a new major release come with detailed instructions on what RPC features
+were deprecated and how to re-enable them temporarily.
+
## Security
The RPC interface allows other programs to control Bitcoin Core,
diff --git a/doc/README.md b/doc/README.md
index 8876ffdd72..b4fa933c8e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -57,7 +57,6 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
- [Source Code Documentation (External Link)](https://dev.visucore.com/bitcoin/doxygen/)
- [Translation Process](translation_process.md)
- [Translation Strings Policy](translation_strings_policy.md)
-- [Travis CI](travis-ci.md)
- [JSON-RPC Interface](JSON-RPC-interface.md)
- [Unauthenticated REST Interface](REST-interface.md)
- [Shared Libraries](shared-libraries.md)
diff --git a/doc/REST-interface.md b/doc/REST-interface.md
index 02a665008b..c96871ab5f 100644
--- a/doc/REST-interface.md
+++ b/doc/REST-interface.md
@@ -101,6 +101,7 @@ $ curl localhost:18332/rest/getutxos/checkmempool/b2cdfd7b89def827ff8af7cd9bff76
Returns various information about the TX mempool.
Only supports JSON as output format.
+* loaded : (boolean) if the mempool is fully loaded
* size : (numeric) the number of transactions in the TX mempool
* bytes : (numeric) size of the TX mempool in bytes
* usage : (numeric) total TX mempool memory usage
diff --git a/doc/bips.md b/doc/bips.md
index 76edc94c29..eb24ce6f66 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -1,4 +1,4 @@
-BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.17.0**):
+BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.18.0**):
* [`BIP 9`](https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki): The changes allowing multiple soft-forks to be deployed in parallel have been implemented since **v0.12.1** ([PR #7575](https://github.com/bitcoin/bitcoin/pull/7575))
* [`BIP 11`](https://github.com/bitcoin/bips/blob/master/bip-0011.mediawiki): Multisig outputs are standard since **v0.6.0** ([PR #669](https://github.com/bitcoin/bitcoin/pull/669)).
@@ -15,11 +15,11 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.17.0**):
* [`BIP 35`](https://github.com/bitcoin/bips/blob/master/bip-0035.mediawiki): The 'mempool' protocol message (and the protocol version bump to 60002) has been implemented since **v0.7.0** ([PR #1641](https://github.com/bitcoin/bitcoin/pull/1641)).
* [`BIP 37`](https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki): The bloom filtering for transaction relaying, partial Merkle trees for blocks, and the protocol version bump to 70001 (enabling low-bandwidth SPV clients) has been implemented since **v0.8.0** ([PR #1795](https://github.com/bitcoin/bitcoin/pull/1795)).
* [`BIP 42`](https://github.com/bitcoin/bips/blob/master/bip-0042.mediawiki): The bug that would have caused the subsidy schedule to resume after block 13440000 was fixed in **v0.9.2** ([PR #3842](https://github.com/bitcoin/bitcoin/pull/3842)).
-* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)). Starting *v0.17.0*, whether to send reject messages can be configured with the `-enablebip61` option.
+* [`BIP 61`](https://github.com/bitcoin/bips/blob/master/bip-0061.mediawiki): The 'reject' protocol message (and the protocol version bump to 70002) was added in **v0.9.0** ([PR #3185](https://github.com/bitcoin/bitcoin/pull/3185)). Starting **v0.17.0**, whether to send reject messages can be configured with the `-enablebip61` option, and support is deprecated as of **v0.18.0**.
* [`BIP 65`](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki): The CHECKLOCKTIMEVERIFY softfork was merged in **v0.12.0** ([PR #6351](https://github.com/bitcoin/bitcoin/pull/6351)), and backported to **v0.11.2** and **v0.10.4**. Mempool-only CLTV was added in [PR #6124](https://github.com/bitcoin/bitcoin/pull/6124).
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
* [`BIP 68`](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki): Sequence locks have been implemented as of **v0.12.1** ([PR #7184](https://github.com/bitcoin/bitcoin/pull/7184)), and have been activated since *block 419328*.
-* [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)).
+* [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)). Support can be optionally disabled at build time since **v0.18.0** ([PR 14451](https://github.com/bitcoin/bitcoin/pull/14451)).
* [`BIP 90`](https://github.com/bitcoin/bips/blob/master/bip-0090.mediawiki): Trigger mechanism for activation of BIPs 34, 65, and 66 has been simplified to block height checks since **v0.14.0** ([PR #8391](https://github.com/bitcoin/bitcoin/pull/8391)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, and enforced for all peer versions as of **v0.13.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579) and [PR #6641](https://github.com/bitcoin/bitcoin/pull/6641)).
* [`BIP 112`](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki): The CHECKSEQUENCEVERIFY opcode has been implemented since **v0.12.1** ([PR #7524](https://github.com/bitcoin/bitcoin/pull/7524)) and has been activated since *block 419328*.
@@ -33,7 +33,7 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.17.0**):
* [`BIP 145`](https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki): getblocktemplate updates for Segregated Witness as of **v0.13.0** ([PR 8149](https://github.com/bitcoin/bitcoin/pull/8149)).
* [`BIP 147`](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki): NULLDUMMY softfork as of **v0.13.1** ([PR 8636](https://github.com/bitcoin/bitcoin/pull/8636) and [PR 8937](https://github.com/bitcoin/bitcoin/pull/8937)).
* [`BIP 152`](https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki): Compact block transfer and related optimizations are used as of **v0.13.0** ([PR 8068](https://github.com/bitcoin/bitcoin/pull/8068)).
-* [`BIP 159`](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki): NODE_NETWORK_LIMITED service bit [signaling only] is supported as of **v0.16.0** ([PR 11740](https://github.com/bitcoin/bitcoin/pull/11740)).
+* [`BIP 159`](https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki): The NODE_NETWORK_LIMITED service bit is signalled as of **v0.16.0** ([PR 11740](https://github.com/bitcoin/bitcoin/pull/11740)), and such nodes are connected to as of **v0.17.0** ([PR 10387](https://github.com/bitcoin/bitcoin/pull/10387)).
* [`BIP 173`](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki): Bech32 addresses for native Segregated Witness outputs are supported as of **v0.16.0** ([PR 11167](https://github.com/bitcoin/bitcoin/pull/11167)).
* [`BIP 174`](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki): RPCs to operate on Partially Signed Bitcoin Transactions (PSBT) are present as of **v0.17.0** ([PR 13557](https://github.com/bitcoin/bitcoin/pull/13557)).
* [`BIP 176`](https://github.com/bitcoin/bips/blob/master/bip-0176.mediawiki): Bits Denomination [QT only] is supported as of **v0.16.0** ([PR 12035](https://github.com/bitcoin/bitcoin/pull/12035)).
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 119896dc67..65cfce6b15 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -1,33 +1,37 @@
-macOS Build Instructions and Notes
-====================================
+# macOS Build Instructions and Notes
+
The commands in this guide should be executed in a Terminal application.
-The built-in one is located in `/Applications/Utilities/Terminal.app`.
+The built-in one is located in
+```
+/Applications/Utilities/Terminal.app
+```
-Preparation
------------
+## Preparation
Install the macOS command line tools:
-`xcode-select --install`
+```shell
+xcode-select --install
+```
When the popup appears, click `Install`.
Then install [Homebrew](https://brew.sh).
-Dependencies
-----------------------
-
- brew install automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf python qt libevent qrencode
+## Dependencies
+```shell
+brew install automake berkeley-db4 libtool boost miniupnpc openssl pkg-config protobuf python qt libevent qrencode
+```
See [dependencies.md](dependencies.md) for a complete overview.
If you want to build the disk image with `make deploy` (.dmg / optional), you need RSVG:
+```shell
+brew install librsvg
+```
- brew install librsvg
-
-Berkeley DB
------------
+## Berkeley DB
It is recommended to use Berkeley DB 4.8. If you have to build it yourself,
-you can use [the installation script included in contrib/](/contrib/install_db4.sh)
+you can use [this](/contrib/install_db4.sh) script to install it
like so:
```shell
@@ -38,170 +42,167 @@ from the root of the repository.
**Note**: You only need Berkeley DB if the wallet is enabled (see [*Disable-wallet mode*](/doc/build-osx.md#disable-wallet-mode)).
-Build Bitcoin Core
-------------------------
+## Build Bitcoin Core
1. Clone the Bitcoin Core source code:
-
- git clone https://github.com/bitcoin/bitcoin
- cd bitcoin
+ ```shell
+ git clone https://github.com/bitcoin/bitcoin
+ cd bitcoin
+ ```
2. Build Bitcoin Core:
Configure and build the headless Bitcoin Core binaries as well as the GUI (if Qt is found).
You can disable the GUI build by passing `--without-gui` to configure.
-
- ./autogen.sh
- ./configure
- make
+ ```shell
+ ./autogen.sh
+ ./configure
+ make
+ ```
3. It is recommended to build and run the unit tests:
-
- make check
-
-4. You can also create a .dmg that contains the .app bundle (optional):
-
- make deploy
-
-Disable-wallet mode
---------------------
-When the intention is to run only a P2P node without a wallet, Bitcoin Core may be compiled in
-disable-wallet mode with:
-
- ./configure --disable-wallet
+ ```shell
+ make check
+ ```
+
+4. You can also create a `.dmg` that contains the `.app` bundle (optional):
+ ```shell
+ make deploy
+ ```
+
+## `disable-wallet` mode
+When the intention is to run only a P2P node without a wallet, Bitcoin Core may be
+compiled in `disable-wallet` mode with:
+```shell
+./configure --disable-wallet
+```
In this case there is no dependency on Berkeley DB 4.8.
Mining is also possible in disable-wallet mode using the `getblocktemplate` RPC call.
-Running
--------
-
+## Running
Bitcoin Core is now available at `./src/bitcoind`
Before running, you may create an empty configuration file:
+```shell
+mkdir -p "/Users/${USER}/Library/Application Support/Bitcoin"
- touch "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
+touch "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
- chmod 600 "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
+chmod 600 "/Users/${USER}/Library/Application Support/Bitcoin/bitcoin.conf"
+```
-The first time you run bitcoind, it will start downloading the blockchain. This process could take many hours, or even days on slower than average systems.
+The first time you run bitcoind, it will start downloading the blockchain. This process could
+take many hours, or even days on slower than average systems.
You can monitor the download process by looking at the debug.log file:
+```shell
+tail -f $HOME/Library/Application\ Support/Bitcoin/debug.log
+```
- tail -f $HOME/Library/Application\ Support/Bitcoin/debug.log
-
-Other commands:
--------
-
- ./src/bitcoind -daemon # Starts the bitcoin daemon.
- ./src/bitcoin-cli --help # Outputs a list of command-line options.
- ./src/bitcoin-cli help # Outputs a list of RPC commands when the daemon is running.
-
-Notes
------
-
-* Tested on OS X 10.10 Yosemite through macOS 10.13 High Sierra on 64-bit Intel processors only.
-
-* Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714)
+## Other commands:
+```shell
+./src/bitcoind -daemon # Starts the bitcoin daemon.
+./src/bitcoin-cli --help # Outputs a list of command-line options.
+./src/bitcoin-cli help # Outputs a list of RPC commands when the daemon is running.
+```
-Deterministic macOS DMG Notes
------------------------------
+## Notes
+* Tested on OS X 10.10 Yosemite through macOS 10.14 Mojave on 64-bit Intel
+processors only.
+* Building with downloaded Qt binaries is not officially supported. See the notes in [#7714](https://github.com/bitcoin/bitcoin/issues/7714).
-Working macOS DMGs are created in Linux by combining a recent clang,
-the Apple binutils (ld, ar, etc) and DMG authoring tools.
+## Deterministic macOS DMG Notes
+Working macOS DMGs are created in Linux by combining a recent `clang`, the Apple
+`binutils` (`ld`, `ar`, etc) and DMG authoring tools.
-Apple uses clang extensively for development and has upstreamed the necessary
-functionality so that a vanilla clang can take advantage. It supports the use
-of -F, -target, -mmacosx-version-min, and --sysroot, which are all necessary
-when building for macOS.
+Apple uses `clang` extensively for development and has upstreamed the necessary
+functionality so that a vanilla clang can take advantage. It supports the use of `-F`,
+`-target`, `-mmacosx-version-min`, and `--sysroot`, which are all necessary when
+building for macOS.
-Apple's version of binutils (called cctools) contains lots of functionality
-missing in the FSF's binutils. In addition to extra linker options for
-frameworks and sysroots, several other tools are needed as well such as
-install_name_tool, lipo, and nmedit. These do not build under linux, so they
-have been patched to do so. The work here was used as a starting point:
-[mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4).
+Apple's version of `binutils` (called `cctools`) contains lots of functionality missing in the
+FSF's `binutils`. In addition to extra linker options for frameworks and sysroots, several
+other tools are needed as well such as `install_name_tool`, `lipo`, and `nmedit`. These
+do not build under Linux, so they have been patched to do so. The work here was used as
+a starting point: [mingwandroid/toolchain4](https://github.com/mingwandroid/toolchain4).
-In order to build a working toolchain, the following source packages are needed
-from Apple: cctools, dyld, and ld64.
+In order to build a working toolchain, the following source packages are needed from
+Apple: `cctools`, `dyld`, and `ld64`.
-These tools inject timestamps by default, which produce non-deterministic
-binaries. The ZERO_AR_DATE environment variable is used to disable that.
+These tools inject timestamps by default, which produce non-deterministic binaries. The
+`ZERO_AR_DATE` environment variable is used to disable that.
-This version of cctools has been patched to use the current version of clang's
-headers and its libLTO.so rather than those from llvmgcc, as it was
-originally done in toolchain4.
+This version of `cctools` has been patched to use the current version of `clang`'s headers
+and its `libLTO.so` rather than those from `llvmgcc`, as it was originally done in `toolchain4`.
-To complicate things further, all builds must target an Apple SDK. These SDKs
-are free to download, but not redistributable.
-To obtain it, register for a developer account, then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg).
+To complicate things further, all builds must target an Apple SDK. These SDKs are free to
+download, but not redistributable. To obtain it, register for an Apple Developer Account,
+then download the [Xcode 7.3.1 dmg](https://developer.apple.com/devcenter/download.action?path=/Developer_Tools/Xcode_7.3.1/Xcode_7.3.1.dmg).
-This file is several gigabytes in size, but only a single directory inside is
-needed:
+This file is several gigabytes in size, but only a single directory inside is needed:
```
Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk
```
-Unfortunately, the usual linux tools (7zip, hpmount, loopback mount) are incapable of opening this file.
-To create a tarball suitable for Gitian input, there are two options:
+Unfortunately, the usual Linux tools (7zip, hpmount, loopback mount) are incapable of
+opening this file. To create a tarball suitable for Gitian input, there are two options:
-Using macOS, you can mount the dmg, and then create it with:
-```
- $ hdiutil attach Xcode_7.3.1.dmg
- $ tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
+Using macOS, you can mount the DMG, and then create it with:
+```shell
+hdiutil attach Xcode_7.3.1.dmg
+tar -C /Volumes/Xcode/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ -czf MacOSX10.11.sdk.tar.gz MacOSX10.11.sdk
```
-Alternatively, you can use 7zip and SleuthKit to extract the files one by one.
-The script contrib/macdeploy/extract-osx-sdk.sh automates this. First ensure
-the dmg file is in the current directory, and then run the script. You may wish
-to delete the intermediate 5.hfs file and MacOSX10.11.sdk (the directory) when
-you've confirmed the extraction succeeded.
+Alternatively, you can use 7zip and SleuthKit to extract the files one by one. The script
+[`extract-osx-sdk.sh`](./../contrib/macdeploy/extract-osx-sdk.sh) automates this. First
+ensure the DMG file is in the current directory, and then run the script. You may wish to
+delete the `intermediate 5.hfs` file and `MacOSX10.11.sdk` (the directory) when you've
+confirmed the extraction succeeded.
-```bash
+```shell
apt-get install p7zip-full sleuthkit
contrib/macdeploy/extract-osx-sdk.sh
rm -rf 5.hfs MacOSX10.11.sdk
```
-The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries
-which are created using these tools. The build process has been designed to
-avoid including the SDK's files in Gitian's outputs. All interim tarballs are
-fully deterministic and may be freely redistributed.
+The Gitian descriptors build 2 sets of files: Linux tools, then Apple binaries which are
+created using these tools. The build process has been designed to avoid including the
+SDK's files in Gitian's outputs. All interim tarballs are fully deterministic and may be freely
+redistributed.
-genisoimage is used to create the initial DMG. It is not deterministic as-is,
-so it has been patched. A system genisoimage will work fine, but it will not
-be deterministic because the file-order will change between invocations.
-The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff).
-No effort was made to fix this cleanly, so it likely leaks memory badly. But
-it's only used for a single invocation, so that's no real concern.
+`genisoimage` is used to create the initial DMG. It is not deterministic as-is, so it has been
+patched. A system `genisoimage` will work fine, but it will not be deterministic because
+the file-order will change between invocations. The patch can be seen here: [theuni/osx-cross-depends](https://raw.githubusercontent.com/theuni/osx-cross-depends/master/patches/cdrtools/genisoimage.diff).
+No effort was made to fix this cleanly, so it likely leaks memory badly. But it's only used for
+a single invocation, so that's no real concern.
-genisoimage cannot compress DMGs, so afterwards, the 'dmg' tool from the
-libdmg-hfsplus project is used to compress it. There are several bugs in this
-tool and its maintainer has seemingly abandoned the project. It has been forked
-and is available (with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus).
+`genisoimage` cannot compress DMGs, so afterwards, the DMG tool from the
+`libdmg-hfsplus` project is used to compress it. There are several bugs in this tool and its
+maintainer has seemingly abandoned the project. It has been forked and is available
+(with fixes) here: [theuni/libdmg-hfsplus](https://github.com/theuni/libdmg-hfsplus).
-The 'dmg' tool has the ability to create DMGs from scratch as well, but this
-functionality is broken. Only the compression feature is currently used.
-Ideally, the creation could be fixed and genisoimage would no longer be necessary.
+The DMG tool has the ability to create DMGs from scratch as well, but this functionality is
+broken. Only the compression feature is currently used. Ideally, the creation could be fixed
+and `genisoimage` would no longer be necessary.
Background images and other features can be added to DMG files by inserting a
-.DS_Store before creation. This is generated by the script
-contrib/macdeploy/custom_dsstore.py.
-
-As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a
-requirement in order to satisfy the new Gatekeeper requirements. Because this
-private key cannot be shared, we'll have to be a bit creative in order for the
-build process to remain somewhat deterministic. Here's how it works:
-
-- Builders use Gitian to create an unsigned release. This outputs an unsigned
- dmg which users may choose to bless and run. It also outputs an unsigned app
- structure in the form of a tarball, which also contains all of the tools
- that have been previously (deterministically) built in order to create a
- final dmg.
-- The Apple keyholder uses this unsigned app to create a detached signature,
- using the script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs).
-- Builders feed the unsigned app + detached signature back into Gitian. It
- uses the pre-built tools to recombine the pieces into a deterministic dmg.
+`.DS_Store` before creation. This is generated by the script
+`contrib/macdeploy/custom_dsstore.py`.
+
+As of OS X 10.9 Mavericks, using an Apple-blessed key to sign binaries is a requirement in
+order to satisfy the new Gatekeeper requirements. Because this private key cannot be
+shared, we'll have to be a bit creative in order for the build process to remain somewhat
+deterministic. Here's how it works:
+
+- Builders use Gitian to create an unsigned release. This outputs an unsigned DMG which
+ users may choose to bless and run. It also outputs an unsigned app structure in the form
+ of a tarball, which also contains all of the tools that have been previously (deterministically)
+ built in order to create a final DMG.
+- The Apple keyholder uses this unsigned app to create a detached signature, using the
+ script that is also included there. Detached signatures are available from this [repository](https://github.com/bitcoin-core/bitcoin-detached-sigs).
+- Builders feed the unsigned app + detached signature back into Gitian. It uses the
+ pre-built tools to recombine the pieces into a deterministic DMG.
diff --git a/doc/build-windows.md b/doc/build-windows.md
index 9641e0d3fd..5ca9f98475 100644
--- a/doc/build-windows.md
+++ b/doc/build-windows.md
@@ -71,6 +71,11 @@ If you want to build the windows installer with `make deploy` you need [NSIS](ht
sudo apt install nsis
+Acquire the source in the usual way:
+
+ git clone https://github.com/bitcoin/bitcoin.git
+ cd bitcoin
+
## Building for 64-bit Windows
The first step is to install the mingw-w64 cross-compilation tool chain:
@@ -87,11 +92,7 @@ Note that for WSL the Bitcoin Core source path MUST be somewhere in the default
example /usr/src/bitcoin, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail.
This means you cannot use a directory that is located directly on the host Windows file system to perform the build.
-Acquire the source in the usual way:
-
- git clone https://github.com/bitcoin/bitcoin.git
-
-Once the source code is ready the build steps are below:
+Build using:
PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var
cd depends
@@ -101,34 +102,6 @@ Once the source code is ready the build steps are below:
CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site ./configure --prefix=/
make
-## Building for 32-bit Windows
-
-To build executables for Windows 32-bit, install the following dependencies:
-
- sudo apt install g++-mingw-w64-i686 mingw-w64-i686-dev
-
-For Ubuntu Bionic 18.04 and Windows Subsystem for Linux <sup>[1](#footnote1)</sup>:
-
- sudo update-alternatives --config i686-w64-mingw32-g++ # Set the default mingw32 g++ compiler option to posix.
-
-Note that for WSL the Bitcoin Core source path MUST be somewhere in the default mount file system, for
-example /usr/src/bitcoin, AND not under /mnt/d/. If this is not the case the dependency autoconf scripts will fail.
-This means you cannot use a directory that located directly on the host Windows file system to perform the build.
-
-Acquire the source in the usual way:
-
- git clone https://github.com/bitcoin/bitcoin.git
-
-Then build using:
-
- PATH=$(echo "$PATH" | sed -e 's/:\/mnt.*//g') # strip out problematic Windows %PATH% imported var
- cd depends
- make HOST=i686-w64-mingw32
- cd ..
- ./autogen.sh # not required when building from tarball
- CONFIG_SITE=$PWD/depends/i686-w64-mingw32/share/config.site ./configure --prefix=/
- make
-
## Depends system
For further documentation on the depends system see [README.md](../depends/README.md) in the depends directory.
diff --git a/doc/dependencies.md b/doc/dependencies.md
index e4be63772c..4c0e8d2567 100644
--- a/doc/dependencies.md
+++ b/doc/dependencies.md
@@ -6,7 +6,7 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| Dependency | Version used | Minimum required | CVEs | Shared | [Bundled Qt library](https://doc.qt.io/qt-5/configure-options.html#third-party-libraries) |
| --- | --- | --- | --- | --- | --- |
| Berkeley DB | [4.8.30](https://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html) | 4.8.x | No | | |
-| Boost | [1.64.0](https://www.boost.org/users/download/) | [1.47.0](https://github.com/bitcoin/bitcoin/pull/8920) | No | | |
+| Boost | [1.70.0](https://www.boost.org/users/download/) | [1.47.0](https://github.com/bitcoin/bitcoin/pull/8920) | No | | |
| Clang | | [3.3+](https://llvm.org/releases/download.html) (C++11 support) | | | |
| D-Bus | [1.10.18](https://cgit.freedesktop.org/dbus/dbus/tree/NEWS?h=dbus-1.10) | | No | Yes | |
| Expat | [2.2.6](https://libexpat.github.io/) | | No | Yes | |
@@ -17,12 +17,12 @@ These are the dependencies currently used by Bitcoin Core. You can find instruct
| libevent | [2.1.8-stable](https://github.com/libevent/libevent/releases) | 2.0.22 | No | | |
| libjpeg | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L65) |
| libpng | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L64) |
-| libsrvg | | | | | |
+| librsvg | | | | | |
| MiniUPnPc | [2.0.20180203](http://miniupnp.free.fr/files) | | No | | |
| OpenSSL | [1.0.1k](https://www.openssl.org/source) | | Yes | | |
| PCRE | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L66) |
| protobuf | [2.6.1](https://github.com/google/protobuf/releases) | | No | | |
-| Python (tests) | | [3.4](https://www.python.org/downloads) | | | |
+| Python (tests) | | [3.5](https://www.python.org/downloads) | | | |
| qrencode | [3.4.4](https://fukuchi.org/works/qrencode) | | No | | |
| Qt | [5.9.7](https://download.qt.io/official_releases/qt/) | [5.5.1](https://github.com/bitcoin/bitcoin/issues/13478) | No | | |
| XCB | | | | | [Yes](https://github.com/bitcoin/bitcoin/blob/master/depends/packages/qt.mk#L87) (Linux only) |
@@ -43,4 +43,4 @@ Some dependencies are not needed in all configurations. The following are some f
* ZeroMQ is needed only with the `--with-zmq` option.
#### Other
-* librsvg is only needed if you need to run `make deploy` on (cross-compliation to) macOS. \ No newline at end of file
+* librsvg is only needed if you need to run `make deploy` on (cross-compilation to) macOS.
diff --git a/doc/descriptors.md b/doc/descriptors.md
index 5dbcd95e1d..dbdac2c5b6 100644
--- a/doc/descriptors.md
+++ b/doc/descriptors.md
@@ -1,11 +1,18 @@
# Support for Output Descriptors in Bitcoin Core
-Since Bitcoin Core v0.17, there is support for Output Descriptors in the
-`scantxoutset` RPC call. This is a simple language which can be used to
-describe collections of output scripts.
-
-This document describes the language. For the specifics on usage for scanning
-the UTXO set, see the `scantxoutset` RPC help.
+Since Bitcoin Core v0.17, there is support for Output Descriptors. This is a
+simple language which can be used to describe collections of output scripts.
+Supporting RPCs are:
+- `scantxoutset` takes as input descriptors to scan for, and also reports
+ specialized descriptors for the matching UTXOs.
+- `getdescriptorinfo` analyzes a descriptor, and reports a canonicalized version
+ with checksum added.
+- `deriveaddresses` takes as input a descriptor and computes the corresponding
+ addresses.
+- `listunspent` outputs a specialized descriptor for the reported unspent outputs.
+
+This document describes the language. For the specifics on usage, see the RPC
+documentation for the functions mentioned above.
## Features
diff --git a/doc/developer-notes.md b/doc/developer-notes.md
index 2662eea8fc..ecd720539e 100644
--- a/doc/developer-notes.md
+++ b/doc/developer-notes.md
@@ -34,7 +34,6 @@ Developer Notes
- [Source code organization](#source-code-organization)
- [GUI](#gui)
- [Subtrees](#subtrees)
- - [Git and GitHub tips](#git-and-github-tips)
- [Scripted diffs](#scripted-diffs)
- [Release notes](#release-notes)
- [RPC interface guidelines](#rpc-interface-guidelines)
@@ -280,7 +279,7 @@ thread](https://askubuntu.com/questions/50145/how-to-install-perf-monitoring-too
for specific instructions.
Certain kernel parameters may need to be set for perf to be able to inspect the
-running process' stack.
+running process's stack.
```sh
$ sudo sysctl -w kernel.perf_event_paranoid=-1
@@ -478,6 +477,14 @@ Wallet
General C++
-------------
+For general C++ guidelines, you may refer to the [C++ Core
+Guidelines](https://isocpp.github.io/CppCoreGuidelines/).
+
+Common misconceptions are clarified in those sections:
+
+- Passing (non-)fundamental types in the [C++ Core
+ Guideline](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-conventional)
+
- Assertions should not have side-effects
- *Rationale*: Even though the source code is set to refuse to compile
@@ -620,8 +627,8 @@ class AddressBookPage
Mode m_mode;
}
-AddressBookPage::AddressBookPage(Mode _mode) :
- m_mode(_mode)
+AddressBookPage::AddressBookPage(Mode _mode)
+ : m_mode(_mode)
...
```
@@ -952,8 +959,7 @@ A few guidelines for introducing and reviewing new RPC interfaces:
from there.
- A RPC method must either be a wallet method or a non-wallet method. Do not
- introduce new methods such as `signrawtransaction` that differ in behavior
- based on presence of a wallet.
+ introduce new methods that differ in behavior based on presence of a wallet.
- *Rationale*: as well as complicating the implementation and interfering
with the introduction of multi-wallet, wallet and non-wallet code should be
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
index 9b36319e64..edbc0911a1 100644
--- a/doc/man/Makefile.am
+++ b/doc/man/Makefile.am
@@ -15,3 +15,9 @@ endif
if BUILD_BITCOIN_TX
dist_man1_MANS+=bitcoin-tx.1
endif
+
+if ENABLE_WALLET
+if BUILD_BITCOIN_WALLET
+ dist_man1_MANS+=bitcoin-wallet.1
+endif
+endif
diff --git a/doc/man/bitcoin-qt.1 b/doc/man/bitcoin-qt.1
index 052d420608..1e8443b1d3 100644
--- a/doc/man/bitcoin-qt.1
+++ b/doc/man/bitcoin-qt.1
@@ -488,9 +488,6 @@ Relay and mine data carrier transactions (default: 1)
Maximum size of data in data carrier transactions we relay and mine
(default: 83)
.HP
-\fB\-mempoolreplacement\fR
-.IP
-Enable transaction replacement in the memory pool (default: 1)
.HP
\fB\-minrelaytxfee=\fR<amt>
.IP
diff --git a/doc/man/bitcoind.1 b/doc/man/bitcoind.1
index 5e057d923f..2a79b6cb46 100644
--- a/doc/man/bitcoind.1
+++ b/doc/man/bitcoind.1
@@ -488,10 +488,6 @@ Relay and mine data carrier transactions (default: 1)
Maximum size of data in data carrier transactions we relay and mine
(default: 83)
.HP
-\fB\-mempoolreplacement\fR
-.IP
-Enable transaction replacement in the memory pool (default: 1)
-.HP
\fB\-minrelaytxfee=\fR<amt>
.IP
Fees (in BTC/kB) smaller than this are considered zero fee for relaying,
diff --git a/doc/productivity.md b/doc/productivity.md
index 862017290d..b25ddc94e5 100644
--- a/doc/productivity.md
+++ b/doc/productivity.md
@@ -8,7 +8,9 @@ Table of Contents
* [Cache compilations with `ccache`](#cache-compilations-with-ccache)
* [Disable features with `./configure`](#disable-features-with-configure)
* [Make use of your threads with `make -j`](#make-use-of-your-threads-with-make--j)
+ * [Only build what you need](#only-build-what-you-need)
* [Multiple working directories with `git worktrees`](#multiple-working-directories-with-git-worktrees)
+ * [Interactive "dummy rebases" for fixups and execs with `git merge-base`](#interactive-dummy-rebases-for-fixups-and-execs-with-git-merge-base)
* [Writing code](#writing-code)
* [Format C/C++/Protobuf diffs with `clang-format-diff.py`](#format-ccprotobuf-diffs-with-clang-format-diffpy)
* [Format Python diffs with `yapf-diff.py`](#format-python-diffs-with-yapf-diffpy)
@@ -32,6 +34,17 @@ Install `ccache` through your distribution's package manager, and run `./configu
To use ccache for all your C/C++ projects, follow the symlinks method [here](https://ccache.samba.org/manual/latest.html#_run_modes) to set it up.
+To get the most out of ccache, put something like this in `~/.ccache/ccache.conf`:
+
+```
+max_size = 50.0G # or whatever cache size you prefer; default is 5G; 0 means unlimited
+base_dir = /home/yourname # or wherever you keep your source files
+```
+
+Note: base_dir is required for ccache to share cached compiles of the same file across different repositories / paths; it will only do this for paths under base_dir. So this option is required for effective use of ccache with git worktrees (described below).
+
+You _must not_ set base_dir to "/", or anywhere that contains system headers (according to the ccache docs).
+
### Disable features with `./configure`
After running `./autogen.sh`, which generates the `./configure` file, use `./configure --help` to identify features that you can disable to save on compilation time. A few common flags:
@@ -43,6 +56,8 @@ After running `./autogen.sh`, which generates the `./configure` file, use `./con
--without-gui
```
+If you do need the wallet enabled, it is common for devs to add `--with-incompatible-bdb`. This uses your system bdb version for the wallet, so you don't have to find a copy of bdb 4.8. Wallets from such a build will be incompatible with any release binary (and vice versa), so use with caution on mainnet.
+
### Make use of your threads with `make -j`
If you have multiple threads on your machine, you can tell `make` to utilize all of them with:
@@ -51,6 +66,20 @@ If you have multiple threads on your machine, you can tell `make` to utilize all
make -j"$(($(nproc)+1))"
```
+### Only build what you need
+
+When rebuilding during development, note that running `make`, without giving a target, will do a lot of work you probably don't need. It will build the GUI (unless you've disabled it) and all the tests (which take much longer to build than the app does).
+
+Obviously, it is important to build and run the tests at appropriate times -- but when you just want a quick compile to check your work, consider picking one or a set of build targets relevant to what you're working on, e.g.:
+
+```sh
+make src/bitcoind src/bitcoin-cli
+make src/qt/bitcoin-qt
+make -C src bitcoin_bench
+```
+
+(You can and should combine this with `-j`, as above, for a parallel build.)
+
### Multiple working directories with `git worktrees`
If you work with multiple branches or multiple copies of the repository, you should try `git worktrees`.
@@ -65,6 +94,21 @@ To simply check out a commit-ish under a new working directory without disruptin
git worktree add --checkout ../where-my-checkout-commit-ish-will-live my-checkout-commit-ish
```
+### Interactive "dummy rebases" for fixups and execs with `git merge-base`
+
+When rebasing, we often want to do a "dummy rebase," whereby we are not rebasing over an updated master but rather over the last common commit with master. This might be useful for rearranging commits, `rebase --autosquash`ing, or `rebase --exec`ing without introducing conflicts that arise from an updated master. In these situations, we can use `git merge-base` to identify the last common commit with master, and rebase off of that.
+
+To squash in `git commit --fixup` commits without rebasing over an updated master, we can do the following:
+
+```sh
+git rebase -i --autosquash "$(git merge-base master HEAD)"
+```
+
+To execute `make check` on every commit since last diverged from master, but without rebasing over an updated master, we can do the following:
+```sh
+git rebase -i --exec "make check" "$(git merge-base master HEAD)"
+```
+
-----
This synergizes well with [`ccache`](#cache-compilations-with-ccache) as objects resulting from unchanged code will most likely hit the cache and won't need to be recompiled.
@@ -76,7 +120,7 @@ Writing code
### Format C/C++/Protobuf diffs with `clang-format-diff.py`
-See [contrib/devtools/README.md](contrib/devtools/README.md#clang-format-diff.py).
+See [contrib/devtools/README.md](/contrib/devtools/README.md#clang-format-diff.py).
### Format Python diffs with `yapf-diff.py`
@@ -136,7 +180,7 @@ This will add an `upstream-pull` remote to your git repository, which can be fet
### Diff the diffs with `git range-diff`
-It is very common for contributors to rebase their pull requests, or make changes to commits (perhaps in response to review) that are not at the head of their branch. This poses a problem for reviewers as when the contributor force pushes, the reviewer is no longer sure that his previous reviews of commits are still valid (as the commit hashes can now be different even though the diff is semantically the same). `git range-diff` can help solve this problem by diffing the diffs.
+It is very common for contributors to rebase their pull requests, or make changes to commits (perhaps in response to review) that are not at the head of their branch. This poses a problem for reviewers as when the contributor force pushes, the reviewer is no longer sure that his previous reviews of commits are still valid (as the commit hashes can now be different even though the diff is semantically the same). [git range-diff](https://git-scm.com/docs/git-range-diff) (Git >= 2.19) can help solve this problem by diffing the diffs.
For example, to identify the differences between your previously reviewed diffs P1-5, and the new diffs P1-2,N3-4 as illustrated below:
```
@@ -152,7 +196,19 @@ You can do:
git range-diff master previously-reviewed-head new-head
```
-Note that `git range-diff` also work for rebases.
+Note that `git range-diff` also work for rebases:
+
+```
+ P1--P2--P3--P4--P5 <-- previously-reviewed-head
+ /
+...--m--m1--m2--m3 <-- master
+ \
+ P1--P2--N3--N4 <-- new-head (with P3 modified, P4 & P5 squashed)
+
+PREV=P5 N=4 && git range-diff `git merge-base --all HEAD $PREV`...$PREV HEAD~$N...HEAD
+```
+
+Where `P5` is the commit you last reviewed and `4` is the number of commits in the new version.
-----
diff --git a/doc/psbt.md b/doc/psbt.md
index 560b45ef31..c411b31d5d 100644
--- a/doc/psbt.md
+++ b/doc/psbt.md
@@ -67,6 +67,9 @@ hardware implementations will typically implement multiple roles simultaneously.
input a PSBT, adds UTXO, key, and script data to inputs and outputs that miss
it, and optionally signs inputs. Where possible it also finalizes the partial
signatures.
+- **`utxoupdatepsbt` (Updater)** is a node RPC that takes a PSBT and updates it
+ to include information available from the UTXO set (works only for SegWit
+ inputs).
- **`finalizepsbt` (Finalizer, Extractor)** is a utility RPC that finalizes any
partial signatures, and if all inputs are finalized, converts the result to a
fully signed transaction which can be broadcast with `sendrawtransaction`.
@@ -74,8 +77,16 @@ hardware implementations will typically implement multiple roles simultaneously.
can be used at any point in the workflow to merge information added to
different versions of the same PSBT. In particular it is useful to combine the
output of multiple Updaters or Signers.
+- **`joinpsbts`** (Creator) is a utility RPC that joins multiple PSBTs together,
+ concatenating the inputs and outputs. This can be used to construct CoinJoin
+ transactions.
- **`decodepsbt`** is a diagnostic utility RPC which will show all information in
a PSBT in human-readable form, as well as compute its eventual fee if known.
+- **`analyzepsbt`** is a utility RPC that examines a PSBT and reports the
+ current status of its inputs, the next step in the workflow if known, and if
+ possible, computes the fee of the resulting transaction and estimates the
+ final weight and feerate.
+
### Workflows
diff --git a/doc/reduce-traffic.md b/doc/reduce-traffic.md
index dd1469f563..5a71f62e0f 100644
--- a/doc/reduce-traffic.md
+++ b/doc/reduce-traffic.md
@@ -35,3 +35,16 @@ blocks and transactions to fewer nodes.
Reducing the maximum connected nodes to a minimum could be desirable if traffic
limits are tiny. Keep in mind that bitcoin's trustless model works best if you are
connected to a handful of nodes.
+
+## 4. Turn off transaction relay (`-blocksonly`)
+
+Forwarding transactions to peers increases the P2P traffic. To only sync blocks
+with other peers, you can disable transaction relay.
+
+Be reminded of the effects of this setting.
+
+- Fee estimation will no longer work.
+- Not relaying other's transactions could hurt your privacy if used while a
+ wallet is loaded or if you use the node to broadcast transactions.
+- It makes block propagation slower because compact block relay can only be
+ used when transaction relay is enabled.
diff --git a/doc/release-notes-0.18.1-16257.md b/doc/release-notes-0.18.1-16257.md
new file mode 100644
index 0000000000..21867b7fb2
--- /dev/null
+++ b/doc/release-notes-0.18.1-16257.md
@@ -0,0 +1,6 @@
+Wallet changes
+--------------
+When creating a transaction with a fee above `-maxtxfee` (default 0.1 BTC),
+the RPC commands `walletcreatefundedpsbt` and `fundrawtransaction` will now fail
+instead of rounding down the fee. Beware that the `feeRate` argument is specified
+in BTC per kilobyte, not satoshi per byte.
diff --git a/doc/release-notes-13756.md b/doc/release-notes-13756.md
new file mode 100644
index 0000000000..a500aceb0f
--- /dev/null
+++ b/doc/release-notes-13756.md
@@ -0,0 +1,41 @@
+Coin selection
+--------------
+
+### Reuse Avoidance
+
+A new wallet flag `avoid_reuse` has been added (default off). When enabled,
+a wallet will distinguish between used and unused addresses, and default to not
+use the former in coin selection.
+
+Rescanning the blockchain is required, to correctly mark previously
+used destinations.
+
+Together with "avoid partial spends" (present as of Bitcoin v0.17), this
+addresses a serious privacy issue where a malicious user can track spends by
+peppering a previously paid to address with near-dust outputs, which would then
+be inadvertently included in future payments.
+
+New RPCs
+--------
+
+- A new `setwalletflag` RPC sets/unsets flags for an existing wallet.
+
+
+Updated RPCs
+------------
+
+Several RPCs have been updated to include an "avoid_reuse" flag, used to control
+whether already used addresses should be left out or included in the operation.
+These include:
+
+- createwallet
+- getbalance
+- getbalances
+- sendtoaddress
+
+In addition, `sendtoaddress` has been changed to avoid partial spends when `avoid_reuse`
+is enabled (if not already enabled via the `-avoidpartialspends` command line flag),
+as it would otherwise risk using up the "wrong" UTXO for an address reuse case.
+
+The listunspent RPC has also been updated to now include a "reused" bool, for nodes
+with "avoid_reuse" enabled.
diff --git a/doc/release-notes-14021.md b/doc/release-notes-14021.md
deleted file mode 100644
index 4797a95bdb..0000000000
--- a/doc/release-notes-14021.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Miscellaneous RPC Changes
--------------------------
-- Descriptors with key origin information imported through `importmulti` will have their key origin information stored in the wallet for use with creating PSBTs.
-- If `bip32derivs` of both `walletprocesspsbt` and `walletcreatefundedpsbt` is set to true but the key metadata for a public key has not been updated yet, then that key will have a derivation path as if it were just an independent key (i.e. no derivation path and its master fingerprint is itself)
-
-Miscellaneous Wallet changes
-----------------------------
-
-- The key metadata will need to be upgraded the first time that the HD seed is available.
-For unencrypted wallets this will occur on wallet loading.
-For encrypted wallets this will occur the first time the wallet is unlocked.
diff --git a/doc/release-notes-14054.md b/doc/release-notes-14054.md
new file mode 100644
index 0000000000..d8cad369c5
--- /dev/null
+++ b/doc/release-notes-14054.md
@@ -0,0 +1,7 @@
+P2P changes
+-----------
+
+BIP 61 reject messages were deprecated in v0.18. They are now disabled by
+default, but can be enabled by setting the `-enablebip61` command line option.
+BIP 61 reject messages will be removed entirely in a future version of
+Bitcoin Core.
diff --git a/doc/release-notes-14481.md b/doc/release-notes-14481.md
deleted file mode 100644
index ea8fc3c34e..0000000000
--- a/doc/release-notes-14481.md
+++ /dev/null
@@ -1,9 +0,0 @@
-Low-level RPC changes
-----------------------
-
-The `listunspent` RPC has been modified so that it also returns `witnessScript`,
-the witness script in the case of a P2WSH or P2SH-P2WSH output.
-
-The `signrawtransactionwithkey` and `signrawtransactionwithwallet` RPCs have been
-modified so that they also optionally accept a `witnessScript`, the witness script in the
-case of a P2WSH or P2SH-P2WSH output. This is compatible with the change to `listunspent`.
diff --git a/doc/release-notes-14491.md b/doc/release-notes-14491.md
deleted file mode 100644
index 1cf36e85cf..0000000000
--- a/doc/release-notes-14491.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Descriptor import support
----------------------
-
-The `importmulti` RPC now supports importing of addresses from descriptors. A "desc" parameter can be provided instead of the "scriptPubKey" in a request, as well as an optional range for ranged descriptors to specify the start and end of the range to import. More information about
-descriptors can be found [here](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md).
diff --git a/doc/release-notes-14667.md b/doc/release-notes-14667.md
deleted file mode 100644
index 5cb1d0aee7..0000000000
--- a/doc/release-notes-14667.md
+++ /dev/null
@@ -1,4 +0,0 @@
-New RPC methods
-------------
-
-- `deriveaddresses` returns one or more addresses corresponding to an [output descriptor](/doc/descriptors.md).
diff --git a/doc/release-notes-14802.md b/doc/release-notes-14802.md
new file mode 100644
index 0000000000..1fcc38866a
--- /dev/null
+++ b/doc/release-notes-14802.md
@@ -0,0 +1,3 @@
+RPC changes
+-----------
+The `getblockstats` RPC is faster for fee calculation by using BlockUndo data. Also, `-txindex` is no longer required and `getblockstats` works for all non-pruned blocks.
diff --git a/doc/release-notes-14954.md b/doc/release-notes-14954.md
new file mode 100644
index 0000000000..4bb0fcca74
--- /dev/null
+++ b/doc/release-notes-14954.md
@@ -0,0 +1,3 @@
+Build system changes
+--------------------
+Python >=3.5 is now required by all aspects of the project. This includes the build systems, test framework and linters. The previously supported minimum (3.4), was EOL in March 2019. See #14954 for more details. \ No newline at end of file
diff --git a/doc/release-notes-15006.md b/doc/release-notes-15006.md
new file mode 100644
index 0000000000..76ed3247a6
--- /dev/null
+++ b/doc/release-notes-15006.md
@@ -0,0 +1,4 @@
+Miscellaneous RPC changes
+------------
+
+- `createwallet` can now create encrypted wallets if a non-empty passphrase is specified.
diff --git a/doc/release-notes-15226.md b/doc/release-notes-15226.md
deleted file mode 100644
index 3be84db3e9..0000000000
--- a/doc/release-notes-15226.md
+++ /dev/null
@@ -1,8 +0,0 @@
-Miscellaneous RPC changes
-------------
-
-- The RPC `createwallet` now has an optional `blank` argument that can be used to create a blank wallet.
-Blank wallets do not have any keys or HD seed.
-They cannot be opened in software older than 0.18.
-Once a blank wallet has a HD seed set (by using `sethdseed`) or private keys, scripts, addresses, and other watch only things have been imported, the wallet is no longer blank and can be opened in 0.17.x.
-Encrypting a blank wallet will also set a HD seed for it.
diff --git a/doc/release-notes-15393.md b/doc/release-notes-15393.md
deleted file mode 100644
index f478dc798d..0000000000
--- a/doc/release-notes-15393.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Dependencies
-------------
-
-- The minimum required version of QT has been increased from 5.2 to 5.5.1 (the [depends system](https://github.com/bitcoin/bitcoin/blob/master/depends/README.md) provides 5.9.7)
diff --git a/doc/release-notes-15492.md b/doc/release-notes-15492.md
deleted file mode 100644
index 1149eb0dbc..0000000000
--- a/doc/release-notes-15492.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Deprecated or removed RPCs
---------------------------
-- The wallet's `generate` RPC method was deprecated in v0.18 and has now
- been fully removed. This RPC is only used for
- testing, but its implementation reached across multiple subsystems
- (wallet and mining), so it has been removed to simplify the
- wallet-node interface. Projects that are using `generate` for testing
- purposes should transition to using the `generatetoaddress` RPC, which
- does not require or use the wallet component. Calling
- `generatetoaddress` with an address returned by the `getnewaddress`
- RPC gives the same functionality as the old `generate` RPC.
diff --git a/doc/release-notes-15566.md b/doc/release-notes-15566.md
new file mode 100644
index 0000000000..49964d7550
--- /dev/null
+++ b/doc/release-notes-15566.md
@@ -0,0 +1,3 @@
+Miscellaneous CLI Changes
+-------------------------
+- The `testnet` field in `bitcoin-cli -getinfo` has been renamed to `chain` and now returns the current network name as defined in BIP70 (main, test, regtest). \ No newline at end of file
diff --git a/doc/release-notes-15620.md b/doc/release-notes-15620.md
new file mode 100644
index 0000000000..bf89a70a4e
--- /dev/null
+++ b/doc/release-notes-15620.md
@@ -0,0 +1,13 @@
+Updated RPCs
+------------
+
+* The -maxtxfee setting no longer has any effect on non-wallet RPCs.
+
+ The `sendrawtransaction` and `testmempoolaccept` RPC methods previously
+ accepted an `allowhighfees` parameter to fail the mempool acceptance in case
+ the transaction's fee would exceed the value of the command line argument
+ `-maxtxfee`. To uncouple the RPCs from the global option, they now have a
+ hardcoded default for the maximum transaction fee, that can be changed for
+ both RPCs on a per-call basis with the `maxfeerate` parameter. The
+ `allowhighfees` boolean option has been removed and replaced by the
+ `maxfeerate` numeric option.
diff --git a/doc/release-notes-15637.md b/doc/release-notes-15637.md
new file mode 100644
index 0000000000..048d5e7218
--- /dev/null
+++ b/doc/release-notes-15637.md
@@ -0,0 +1,3 @@
+RPC changes
+-----------
+In getmempoolancestors, getmempooldescendants, getmempoolentry and getrawmempool RPCs, to be consistent with the returned value and other RPCs such as getrawtransaction, vsize has been added and size is now deprecated. size will only be returned if bitcoind is started with `-deprecatedrpc=size`. \ No newline at end of file
diff --git a/doc/release-notes-15730.md b/doc/release-notes-15730.md
new file mode 100644
index 0000000000..7a4a60b1ee
--- /dev/null
+++ b/doc/release-notes-15730.md
@@ -0,0 +1,5 @@
+RPC changes
+-----------
+The RPC `getwalletinfo` response now includes the `scanning` key with an object
+if there is a scanning in progress or `false` otherwise. Currently the object
+has the scanning duration and progress.
diff --git a/doc/release-notes-15849.md b/doc/release-notes-15849.md
new file mode 100644
index 0000000000..a1df31f250
--- /dev/null
+++ b/doc/release-notes-15849.md
@@ -0,0 +1,6 @@
+Thread names in logs
+--------------------
+
+On platforms supporting `thread_local`, log lines can be prefixed with the name
+of the thread that caused the log. To enable this behavior, use
+`-logthreadnames=1`.
diff --git a/doc/release-notes.md b/doc/release-notes.md
index ebcdcda306..9efb6cbabb 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,5 +1,19 @@
-(note: this is a temporary file, to be added-to by anybody, and moved to
-release-notes at release time)
+*After branching off for a major version release of Bitcoin Core, use this
+template to create the initial release notes draft.*
+
+*The release notes draft is a temporary file that can be added to by anyone. See
+[/doc/developer-notes.md#release-notes](/doc/developer-notes.md#release-notes)
+for the process.*
+
+*Create the draft, named* "*version* Release Notes Draft"
+*(e.g. "0.20.0 Release Notes Draft"), as a collaborative wiki in:*
+
+https://github.com/bitcoin-core/bitcoin-devwiki/wiki/
+
+*Before the final release, move the notes back to this git repository.*
+
+*version* Release Notes Draft
+===============================
Bitcoin Core version *version* is now available from:
@@ -24,14 +38,9 @@ shut down (which might take a few minutes for older versions), then run the
installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac)
or `bitcoind`/`bitcoin-qt` (on Linux).
-The first time you run version 0.15.0, your chainstate database will be converted to a
-new format, which will take anywhere from a few minutes to half an hour,
-depending on the speed of your machine.
-
-Note that the block database format also changed in version 0.8.0 and there is no
-automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading
-directly from 0.7.x and earlier without redownloading the blockchain is not supported.
-However, as usual, old wallet versions are still supported.
+Upgrading directly from a version of Bitcoin Core that has reached its EOL is
+possible, but might take some time if the datadir needs to be migrated. Old
+wallet versions of Bitcoin Core are generally supported.
Downgrading warning
-------------------
@@ -66,16 +75,63 @@ platform.
Notable changes
===============
-Example item
+New RPCs
+--------
+
+- `getbalances` returns an object with all balances (`mine`,
+ `untrusted_pending` and `immature`). Please refer to the RPC help of
+ `getbalances` for details. The new RPC is intended to replace
+ `getunconfirmedbalance` and the balance fields in `getwalletinfo`, as well as
+ `getbalance`. The old calls may be removed in a future version.
+
+Updated RPCs
------------
+Note: some low-level RPC changes mainly useful for testing are described in the
+Low-level Changes section below.
+
+- The `sendmany` RPC had an argument `minconf` that was not well specified and
+ would lead to RPC errors even when the wallet's coin selection would succeed.
+ The `sendtoaddress` RPC never had this check, so to normalize the behavior,
+ `minconf` is now ignored in `sendmany`. If the coin selection does not
+ succeed due to missing coins, it will still throw an RPC error. Be reminded
+ that coin selection is influenced by the `-spendzeroconfchange`,
+ `-limitancestorcount`, `-limitdescendantcount` and `-walletrejectlongchains`
+ command line arguments.
+
Low-level changes
=================
-Example item
+Configuration
------------
+- An error is issued where previously a warning was issued when a setting in
+ the config file was specified in the default section, but not overridden for
+ the selected network. This change takes only effect if the selected network
+ is not mainnet.
+
+Network
+-------
+
+- When fetching a transaction announced by multiple peers, previous versions of
+ Bitcoin Core would sequentially attempt to download the transaction from each
+ announcing peer until the transaction is received, in the order that those
+ peers' announcements were received. In this release, the download logic has
+ changed to randomize the fetch order across peers and to prefer sending
+ download requests to outbound peers over inbound peers. This fixes an issue
+ where inbound peers can prevent a node from getting a transaction.
+
+Wallet
+------
+
+- When in pruned mode, a rescan that was triggered by an `importwallet`,
+ `importpubkey`, `importaddress`, or `importprivkey` RPC will only fail when
+ blocks have been pruned. Previously it would fail when `-prune` has been set.
+ This change allows to set `-prune` to a high value (e.g. the disk size) and
+ the calls to any of the import RPCs would fail when the first block is
+ pruned.
+
Credits
=======
diff --git a/doc/release-notes/release-notes-0.12.0.md b/doc/release-notes/release-notes-0.12.0.md
index cf74a17975..bc0d5ea3b0 100644
--- a/doc/release-notes/release-notes-0.12.0.md
+++ b/doc/release-notes/release-notes-0.12.0.md
@@ -127,7 +127,7 @@ minimum relay feerate. The initial minimum relay feerate is set to
Bitcoin Core 0.12 also introduces new default policy limits on the length and
size of unconfirmed transaction chains that are allowed in the mempool
(generally limiting the length of unconfirmed chains to 25 transactions, with a
-total size of 101 KB). These limits can be overriden using command line
+total size of 101 KB). These limits can be overridden using command line
arguments; see the extended help (`--help -help-debug`) for more information.
Opt-in Replace-by-fee transactions
diff --git a/doc/release-notes/release-notes-0.18.0.md b/doc/release-notes/release-notes-0.18.0.md
new file mode 100644
index 0000000000..3ca7d52243
--- /dev/null
+++ b/doc/release-notes/release-notes-0.18.0.md
@@ -0,0 +1,1224 @@
+Bitcoin Core version 0.18.0 is now available from:
+
+ <https://bitcoincore.org/bin/bitcoin-core-0.18.0/>
+
+This is a new major version release, including 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 for older
+versions), then run the installer (on Windows) or just copy over
+`/Applications/Bitcoin-Qt` (on Mac) or `bitcoind`/`bitcoin-qt` (on
+Linux).
+
+The first time you run version 0.15.0 or newer, your chainstate database
+will be converted to a new format, which will take anywhere from a few
+minutes to half an hour, depending on the speed of your machine.
+
+Note that the block database format also changed in version 0.8.0 and
+there is no automatic upgrade code from before version 0.8 to version
+0.15.0 or later. Upgrading directly from 0.7.x and earlier without
+redownloading the blockchain is not supported. However, as usual, old
+wallet versions are still supported.
+
+Compatibility
+==============
+
+Bitcoin Core is supported and extensively tested on operating systems
+using the Linux kernel, macOS 10.10+, and Windows 7 and newer. It is not
+recommended to use Bitcoin Core on unsupported systems.
+
+Bitcoin Core should also work on most other Unix-like systems but is not
+as frequently tested on them.
+
+From 0.17.0 onwards, macOS <10.10 is no longer supported. 0.17.0 is
+built using Qt 5.9.x, which doesn't support versions of macOS older than
+10.10. Additionally, Bitcoin Core does not yet change appearance when
+macOS "dark mode" is activated.
+
+In addition to previously-supported CPU platforms, this release's
+pre-compiled distribution also provides binaries for the RISC-V
+platform.
+
+If you are using the `systemd` unit configuration file located at
+`contrib/init/bitcoind.service`, it has been changed to use
+`/var/lib/bitcoind` as the data directory instead of
+`~bitcoin/.bitcoin`. When switching over to the new configuration file,
+please make sure that the filesystem on which `/var/lib/bitcoind` will
+exist has enough space (check using `df -h /var/lib/bitcoind`), and
+optionally copy over your existing data directory. See the [systemd init
+file section](#systemd-init-file) for more details.
+
+Known issues
+============
+
+Wallet GUI
+----------
+
+For advanced users who have both (1) enabled coin control features, and
+(2) are using multiple wallets loaded at the same time: The coin control
+input selection dialog can erroneously retain wrong-wallet state when
+switching wallets using the dropdown menu. For now, it is recommended
+not to use coin control features with multiple wallets loaded.
+
+Notable changes
+===============
+
+Mining
+------
+
+- Calls to `getblocktemplate` will fail if the segwit rule is not
+ specified. Calling `getblocktemplate` without segwit specified is
+ almost certainly a misconfiguration since doing so results in lower
+ rewards for the miner. Failed calls will produce an error message
+ describing how to enable the segwit rule.
+
+Configuration option changes
+----------------------------
+
+- A warning is printed if an unrecognized section name is used in the
+ configuration file. Recognized sections are `[test]`, `[main]`, and
+ `[regtest]`.
+
+- Four new options are available for configuring the maximum number of
+ messages that ZMQ will queue in memory (the "high water mark") before
+ dropping additional messages. The default value is 1,000, the same as
+ was used for previous releases. See the [ZMQ
+ documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md#usage)
+ for details.
+
+- The `rpcallowip` option can no longer be used to automatically listen
+ on all network interfaces. Instead, the `rpcbind` parameter must be
+ used to specify the IP addresses to listen on. Listening for RPC
+ commands over a public network connection is insecure and should be
+ disabled, so a warning is now printed if a user selects such a
+ configuration. If you need to expose RPC in order to use a tool like
+ Docker, ensure you only bind RPC to your localhost, e.g. `docker run
+ [...] -p 127.0.0.1:8332:8332` (this is an extra `:8332` over the
+ normal Docker port specification).
+
+- The `rpcpassword` option now causes a startup error if the password
+ set in the configuration file contains a hash character (#), as it's
+ ambiguous whether the hash character is meant for the password or as a
+ comment.
+
+- The `whitelistforcerelay` option is used to relay transactions from
+ whitelisted peers even when not accepted to the mempool. This option
+ now defaults to being off, so that changes in policy and
+ disconnect/ban behavior will not cause a node that is whitelisting
+ another to be dropped by peers. Users can still explicitly enable
+ this behavior with the command line option (and may want to consider
+ [contacting](https://bitcoincore.org/en/contact/) the Bitcoin Core
+ project to let us know about their use-case, as this feature could be
+ deprecated in the future).
+
+systemd init file
+-----------------
+
+The systemd init file (`contrib/init/bitcoind.service`) has been changed
+to use `/var/lib/bitcoind` as the data directory instead of
+`~bitcoin/.bitcoin`. This change makes Bitcoin Core more consistent with
+other services, and makes the systemd init config more consistent with
+existing Upstart and OpenRC configs.
+
+The configuration, PID, and data directories are now completely managed
+by systemd, which will take care of their creation, permissions, etc.
+See [`systemd.exec(5)`](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=)
+for more details.
+
+When using the provided init files under `contrib/init`, overriding the
+`datadir` option in `/etc/bitcoin/bitcoin.conf` will have no effect.
+This is because the command line arguments specified in the init files
+take precedence over the options specified in
+`/etc/bitcoin/bitcoin.conf`.
+
+
+Documentation
+-------------
+
+- A new short [document](https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md)
+ about the JSON-RPC interface describes cases where the results of an
+ RPC might contain inconsistencies between data sourced from different
+ subsystems, such as wallet state and mempool state. A note is added
+ to the [REST interface documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/REST-interface.md)
+ indicating that the same rules apply.
+
+- Further information is added to the [JSON-RPC
+ documentation](https://github.com/bitcoin/bitcoin/blob/master/doc/JSON-RPC-interface.md)
+ about how to secure this interface.
+
+- A new [document](https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md)
+ about the `bitcoin.conf` file describes how to use it to configure
+ Bitcoin Core.
+
+- A new document introduces Bitcoin Core's BIP174 [Partially-Signed
+ Bitcoin Transactions
+ (PSBT)](https://github.com/bitcoin/bitcoin/blob/master/doc/psbt.md)
+ interface, which is used to allow multiple programs to collaboratively
+ work to create, sign, and broadcast new transactions. This is useful
+ for offline (cold storage) wallets, multisig wallets, coinjoin
+ implementations, and many other cases where two or more programs need
+ to interact to generate a complete transaction.
+
+- The [output script
+ descriptor](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md)
+ documentation has been updated with information about new features in
+ this still-developing language for describing the output scripts that
+ a wallet or other program wants to receive notifications for, such as
+ which addresses it wants to know received payments. The language is
+ currently used in multiple new and updated RPCs described in these
+ release notes and is expected to be adapted to other RPCs and to the
+ underlying wallet structure.
+
+Build system changes
+--------------------
+
+- A new `--disable-bip70` option may be passed to `./configure` to
+ prevent Bitcoin-Qt from being built with support for the BIP70 payment
+ protocol or from linking libssl. As the payment protocol has exposed
+ Bitcoin Core to libssl vulnerabilities in the past, builders who don't
+ need BIP70 support are encouraged to use this option to reduce their
+ exposure to future vulnerabilities.
+
+- The minimum required version of Qt (when building the GUI) has been
+ increased from 5.2 to 5.5.1 (the [depends
+ system](https://github.com/bitcoin/bitcoin/blob/master/depends/README.md)
+ provides 5.9.7)
+
+New RPCs
+--------
+
+- `getnodeaddresses` returns peer addresses known to this node. It may
+ be used to find nodes to connect to without using a DNS seeder.
+
+- `listwalletdir` returns a list of wallets in the wallet directory
+ (either the default wallet directory or the directory configured by
+ the `-walletdir` parameter).
+
+- `getrpcinfo` returns runtime details of the RPC server. At the moment,
+ it returns an array of the currently active commands and how long
+ they've been running.
+
+- `deriveaddresses` returns one or more addresses corresponding to an
+ [output descriptor](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md).
+
+- `getdescriptorinfo` accepts a descriptor and returns information about
+ it, including its computed checksum.
+
+- `joinpsbts` merges multiple distinct PSBTs into a single PSBT. The
+ multiple PSBTs must have different inputs. The resulting PSBT will
+ contain every input and output from all of the PSBTs. Any signatures
+ provided in any of the PSBTs will be dropped.
+
+- `analyzepsbt` examines a PSBT and provides information about what
+ the PSBT contains and the next steps that need to be taken in order
+ to complete the transaction. For each input of a PSBT, `analyzepsbt`
+ provides information about what information is missing for that
+ input, including whether a UTXO needs to be provided, what pubkeys
+ still need to be provided, which scripts need to be provided, and
+ what signatures are still needed. Every input will also list which
+ role is needed to complete that input, and `analyzepsbt` will also
+ list the next role in general needed to complete the PSBT.
+ `analyzepsbt` will also provide the estimated fee rate and estimated
+ virtual size of the completed transaction if it has enough
+ information to do so.
+
+- `utxoupdatepsbt` searches the set of Unspent Transaction Outputs
+ (UTXOs) to find the outputs being spent by the partial transaction.
+ PSBTs need to have the UTXOs being spent to be provided because
+ the signing algorithm requires information from the UTXO being spent.
+ For segwit inputs, only the UTXO itself is necessary. For
+ non-segwit outputs, the entire previous transaction is needed so
+ that signers can be sure that they are signing the correct thing.
+ Unfortunately, because the UTXO set only contains UTXOs and not full
+ transactions, `utxoupdatepsbt` will only add the UTXO for segwit
+ inputs.
+
+Updated RPCs
+------------
+
+Note: some low-level RPC changes mainly useful for testing are described
+in the Low-level Changes section below.
+
+- `getpeerinfo` now returns an additional `minfeefilter` field set to
+ the peer's BIP133 fee filter. You can use this to detect that you
+ have peers that are willing to accept transactions below the default
+ minimum relay fee.
+
+- The mempool RPCs, such as `getrawmempool` with `verbose=true`, now
+ return an additional "bip125-replaceable" value indicating whether the
+ transaction (or its unconfirmed ancestors) opts-in to asking nodes and
+ miners to replace it with a higher-feerate transaction spending any of
+ the same inputs.
+
+- `settxfee` previously silently ignored attempts to set the fee below
+ the allowed minimums. It now prints a warning. The special value of
+ "0" may still be used to request the minimum value.
+
+- `getaddressinfo` now provides an `ischange` field indicating whether
+ the wallet used the address in a change output.
+
+- `importmulti` has been updated to support P2WSH, P2WPKH, P2SH-P2WPKH,
+ and P2SH-P2WSH. Requests for P2WSH and P2SH-P2WSH accept an additional
+ `witnessscript` parameter.
+
+- `importmulti` now returns an additional `warnings` field for each
+ request with an array of strings explaining when fields are being
+ ignored or are inconsistent, if there are any.
+
+- `getaddressinfo` now returns an additional `solvable` boolean field
+ when Bitcoin Core knows enough about the address's scriptPubKey,
+ optional redeemScript, and optional witnessScript in order for the
+ wallet to be able to generate an unsigned input spending funds sent to
+ that address.
+
+- The `getaddressinfo`, `listunspent`, and `scantxoutset` RPCs now
+ return an additional `desc` field that contains an output descriptor
+ containing all key paths and signing information for the address
+ (except for the private key). The `desc` field is only returned for
+ `getaddressinfo` and `listunspent` when the address is solvable.
+
+- `importprivkey` will preserve previously-set labels for addresses or
+ public keys corresponding to the private key being imported. For
+ example, if you imported a watch-only address with the label "cold
+ wallet" in earlier releases of Bitcoin Core, subsequently importing
+ the private key would default to resetting the address's label to the
+ default empty-string label (""). In this release, the previous label
+ of "cold wallet" will be retained. If you optionally specify any
+ label besides the default when calling `importprivkey`, the new label
+ will be applied to the address.
+
+- See the [Mining](#mining) section for changes to `getblocktemplate`.
+
+- `getmininginfo` now omits `currentblockweight` and `currentblocktx`
+ when a block was never assembled via RPC on this node.
+
+- The `getrawtransaction` RPC & REST endpoints no longer check the
+ unspent UTXO set for a transaction. The remaining behaviors are as
+ follows: 1. If a blockhash is provided, check the corresponding block.
+ 2. If no blockhash is provided, check the mempool. 3. If no blockhash
+ is provided but txindex is enabled, also check txindex.
+
+- `unloadwallet` is now synchronous, meaning it will not return until
+ the wallet is fully unloaded.
+
+- `importmulti` now supports importing of addresses from descriptors. A
+ "desc" parameter can be provided instead of the "scriptPubKey" in a
+ request, as well as an optional range for ranged descriptors to
+ specify the start and end of the range to import. Descriptors with key
+ origin information imported through `importmulti` will have their key
+ origin information stored in the wallet for use with creating PSBTs.
+ More information about descriptors can be found
+ [here](https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md).
+
+- `listunspent` has been modified so that it also returns
+ `witnessScript`, the witness script in the case of a P2WSH or
+ P2SH-P2WSH output.
+
+- `createwallet` now has an optional `blank` argument that can be used
+ to create a blank wallet. Blank wallets do not have any keys or HD
+ seed. They cannot be opened in software older than 0.18. Once a blank
+ wallet has a HD seed set (by using `sethdseed`) or private keys,
+ scripts, addresses, and other watch only things have been imported,
+ the wallet is no longer blank and can be opened in 0.17.x. Encrypting
+ a blank wallet will also set a HD seed for it.
+
+Deprecated or removed RPCs
+--------------------------
+
+- `signrawtransaction` is removed after being deprecated and hidden
+ behind a special configuration option in version 0.17.0.
+
+- The 'account' API is removed after being deprecated in v0.17. The
+ 'label' API was introduced in v0.17 as a replacement for accounts.
+ See the [release notes from
+ v0.17](https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.17.0.md#label-and-account-apis-for-wallet)
+ for a full description of the changes from the 'account' API to the
+ 'label' API.
+
+- `addwitnessaddress` is removed after being deprecated in version
+ 0.16.0.
+
+- `generate` is deprecated and will be fully removed in a subsequent
+ major version. This RPC is only used for testing, but its
+ implementation reached across multiple subsystems (wallet and mining),
+ so it is being deprecated to simplify the wallet-node interface.
+ Projects that are using `generate` for testing purposes should
+ transition to using the `generatetoaddress` RPC, which does not
+ require or use the wallet component. Calling `generatetoaddress` with
+ an address returned by the `getnewaddress` RPC gives the same
+ functionality as the old `generate` RPC. To continue using `generate`
+ in this version, restart bitcoind with the `-deprecatedrpc=generate`
+ configuration option.
+
+- Be reminded that parts of the `validateaddress` command have been
+ deprecated and moved to `getaddressinfo`. The following deprecated
+ fields have moved to `getaddressinfo`: `ismine`, `iswatchonly`,
+ `script`, `hex`, `pubkeys`, `sigsrequired`, `pubkey`, `embedded`,
+ `iscompressed`, `label`, `timestamp`, `hdkeypath`, `hdmasterkeyid`.
+
+- The `addresses` field has been removed from the `validateaddress`
+ and `getaddressinfo` RPC methods. This field was confusing since
+ it referred to public keys using their P2PKH address. Clients
+ should use the `embedded.address` field for P2SH or P2WSH wrapped
+ addresses, and `pubkeys` for inspecting multisig participants.
+
+REST changes
+------------
+
+- A new `/rest/blockhashbyheight/` endpoint is added for fetching the
+ hash of the block in the current best blockchain based on its height
+ (how many blocks it is after the Genesis Block).
+
+Graphical User Interface (GUI)
+------------------------------
+
+- A new Window menu is added alongside the existing File, Settings, and
+ Help menus. Several items from the other menus that opened new
+ windows have been moved to this new Window menu.
+
+- In the Send tab, the checkbox for "pay only the required fee" has been
+ removed. Instead, the user can simply decrease the value in the
+ Custom Feerate field all the way down to the node's configured minimum
+ relay fee.
+
+- In the Overview tab, the watch-only balance will be the only balance
+ shown if the wallet was created using the `createwallet` RPC and the
+ `disable_private_keys` parameter was set to true.
+
+- The launch-on-startup option is no longer available on macOS if
+ compiled with macosx min version greater than 10.11 (use
+ CXXFLAGS="-mmacosx-version-min=10.11"
+ CFLAGS="-mmacosx-version-min=10.11" for setting the deployment sdk
+ version)
+
+Tools
+-----
+
+- A new `bitcoin-wallet` tool is now distributed alongside Bitcoin
+ Core's other executables. Without needing to use any RPCs, this tool
+ can currently create a new wallet file or display some basic
+ information about an existing wallet, such as whether the wallet is
+ encrypted, whether it uses an HD seed, how many transactions it
+ contains, and how many address book entries it has.
+
+Planned changes
+===============
+
+This section describes planned changes to Bitcoin Core that may affect
+other Bitcoin software and services.
+
+- Since version 0.16.0, Bitcoin Core’s built-in wallet has defaulted to
+ generating P2SH-wrapped segwit addresses when users want to receive
+ payments. These addresses are backwards compatible with all
+ widely-used software. Starting with Bitcoin Core 0.20 (expected about
+ a year after 0.18), Bitcoin Core will default to native segwit
+ addresses (bech32) that provide additional fee savings and other
+ benefits. Currently, many wallets and services already support sending
+ to bech32 addresses, and if the Bitcoin Core project sees enough
+ additional adoption, it will instead default to bech32 receiving
+ addresses in Bitcoin Core 0.19 (approximately November 2019).
+ P2SH-wrapped segwit addresses will continue to be provided if the user
+ requests them in the GUI or by RPC, and anyone who doesn’t want the
+ update will be able to configure their default address type.
+ (Similarly, pioneering users who want to change their default now may
+ set the `addresstype=bech32` configuration option in any Bitcoin Core
+ release from 0.16.0 up.)
+
+Deprecated P2P messages
+-----------------------
+
+- BIP 61 reject messages are now deprecated. Reject messages have no use
+ case on the P2P network and are only logged for debugging by most
+ network nodes. Furthermore, they increase bandwidth and can be harmful
+ for privacy and security. It has been possible to disable BIP 61
+ messages since v0.17 with the `-enablebip61=0` option. BIP 61 messages
+ will be disabled by default in a future version, before being removed
+ entirely.
+
+Low-level changes
+=================
+
+This section describes RPC changes mainly useful for testing, mostly not
+relevant in production. The changes are mentioned for completeness.
+
+RPC
+---
+
+- The `submitblock` RPC previously returned the reason a rejected block
+ was invalid the first time it processed that block, but returned a
+ generic "duplicate" rejection message on subsequent occasions it
+ processed the same block. It now always returns the fundamental
+ reason for rejecting an invalid block and only returns "duplicate" for
+ valid blocks it has already accepted.
+
+- A new `submitheader` RPC allows submitting block headers independently
+ from their block. This is likely only useful for testing.
+
+- The `signrawtransactionwithkey` and `signrawtransactionwithwallet`
+ RPCs have been modified so that they also optionally accept a
+ `witnessScript`, the witness script in the case of a P2WSH or
+ P2SH-P2WSH output. This is compatible with the change to
+ `listunspent`.
+
+- For the `walletprocesspsbt` and `walletcreatefundedpsbt` RPCs, if the
+ `bip32derivs` parameter is set to true but the key metadata for a
+ public key has not been updated yet, then that key will have a
+ derivation path as if it were just an independent key (i.e. no
+ derivation path and its master fingerprint is itself).
+
+Configuration
+-------------
+
+- The `-usehd` configuration option was removed in version 0.16. From
+ that version onwards, all new wallets created are hierarchical
+ deterministic wallets. This release makes specifying `-usehd` an
+ invalid configuration option.
+
+Network
+-------
+
+- This release allows peers that your node automatically disconnected
+ for misbehavior (e.g. sending invalid data) to reconnect to your node
+ if you have unused incoming connection slots. If your slots fill up,
+ a misbehaving node will be disconnected to make room for nodes without
+ a history of problems (unless the misbehaving node helps your node in
+ some other way, such as by connecting to a part of the Internet from
+ which you don't have many other peers). Previously, Bitcoin Core
+ banned the IP addresses of misbehaving peers for a period of time
+ (default of 1 day); this was easily circumvented by attackers with
+ multiple IP addresses. If you manually ban a peer, such as by using
+ the `setban` RPC, all connections from that peer will still be
+ rejected.
+
+Wallet
+-------
+
+- The key metadata will need to be upgraded the first time that the HD
+ seed is available. For unencrypted wallets this will occur on wallet
+ loading. For encrypted wallets this will occur the first time the
+ wallet is unlocked.
+
+- Newly encrypted wallets will no longer require restarting the
+ software. Instead such wallets will be completely unloaded and
+ reloaded to achieve the same effect.
+
+- A sub-project of Bitcoin Core now provides Hardware Wallet Interaction
+ (HWI) scripts that allow command-line users to use several popular
+ hardware key management devices with Bitcoin Core. See their [project
+ page](https://github.com/bitcoin-core/HWI#readme) for details.
+
+Security
+--------
+
+- This release changes the Random Number Generator (RNG) used from
+ OpenSSL to Bitcoin Core's own implementation, although entropy
+ gathered by Bitcoin Core is fed out to OpenSSL and then read back in
+ when the program needs strong randomness. This moves Bitcoin Core a
+ little closer to no longer needing to depend on OpenSSL, a dependency
+ that has caused security issues in the past. The new implementation
+ gathers entropy from multiple sources, including from hardware
+ supporting the rdseed CPU instruction.
+
+Changes for particular platforms
+--------------------------------
+
+- On macOS, Bitcoin Core now opts out of application CPU throttling
+ ("app nap") during initial blockchain download, when catching up from
+ over 100 blocks behind the current chain tip, or when reindexing chain
+ data. This helps prevent these operations from taking an excessively
+ long time because the operating system is attempting to conserve
+ power.
+
+0.18.0 change log
+=================
+
+### Consensus
+- #14247 Fix crash bug with duplicate inputs within a transaction (TheBlueMatt)
+
+### Mining
+- #14811 Mining: Enforce that segwit option must be set in GBT (jnewbery)
+
+### Block and transaction handling
+- #13310 Report progress in ReplayBlocks while rolling forward (promag)
+- #13783 validation: Pass tx pool reference into CheckSequenceLocks (MarcoFalke)
+- #14834 validation: Assert that pindexPrev is non-null when required (kallewoof)
+- #14085 index: Fix for indexers skipping genesis block (jimpo)
+- #14963 mempool, validation: Explain `cs_main` locking semantics (MarcoFalke)
+- #15193 Default `-whitelistforcerelay` to off (sdaftuar)
+- #15429 Update `assumevalid`, `minimumchainwork`, and `getchaintxstats` to height 563378 (gmaxwell)
+- #15552 Granular invalidateblock and RewindBlockIndex (MarcoFalke)
+- #14841 Move CheckBlock() call to critical section (hebasto)
+
+### P2P protocol and network code
+- #14025 Remove dead code for nVersion=10300 (MarcoFalke)
+- #12254 BIP 158: Compact Block Filters for Light Clients (jimpo)
+- #14073 blockfilter: Avoid out-of-bounds script access (jimpo)
+- #14140 Switch nPrevNodeCount to vNodesSize (pstratem)
+- #14027 Skip stale tip checking if outbound connections are off or if reindexing (gmaxwell)
+- #14532 Never bind `INADDR_ANY` by default, and warn when doing so explicitly (luke-jr)
+- #14733 Make peer timeout configurable, speed up very slow test and ensure correct code path tested (zallarak)
+- #14336 Implement poll (pstratem)
+- #15051 IsReachable is the inverse of IsLimited (DRY). Includes unit tests (mmachicao)
+- #15138 Drop IsLimited in favor of IsReachable (Empact)
+- #14605 Return of the Banman (dongcarl)
+- #14970 Add dnsseed.emzy.de to DNS seeds (Emzy)
+- #14929 Allow connections from misbehavior banned peers (gmaxwell)
+- #15345 Correct comparison of addr count (dongcarl)
+- #15201 Add missing locking annotation for vNodes. vNodes is guarded by cs_vNodes (practicalswift)
+- #14626 Select orphan transaction uniformly for eviction (sipa)
+- #15486 Ensure tried collisions resolve, and allow feeler connections to existing outbound netgroups (sdaftuar)
+
+### Wallet
+- #13962 Remove unused `dummy_tx` variable from FillPSBT (dongcarl)
+- #13967 Don't report `minversion` wallet entry as unknown (instagibbs)
+- #13988 Add checks for settxfee reasonableness (ajtowns)
+- #12559 Avoid locking `cs_main` in some wallet RPC (promag)
+- #13631 Add CMerkleTx::IsImmatureCoinBase method (Empact)
+- #14023 Remove accounts RPCs (jnewbery)
+- #13825 Kill accounts (jnewbery)
+- #10605 Add AssertLockHeld assertions in CWallet::ListCoins (ryanofsky)
+- #12490 Remove deprecated wallet rpc features from `bitcoin_server` (jnewbery)
+- #14138 Set `encrypted_batch` to nullptr after delete. Avoid double free in the case of NDEBUG (practicalswift)
+- #14168 Remove `ENABLE_WALLET` from `libbitcoin_server.a` (jnewbery)
+- #12493 Reopen CDBEnv after encryption instead of shutting down (achow101)
+- #14282 Remove `-usehd` option (jnewbery)
+- #14146 Remove trailing separators from `-walletdir` arg (PierreRochard)
+- #14291 Add ListWalletDir utility function (promag)
+- #14468 Deprecate `generate` RPC method (jnewbery)
+- #11634 Add missing `cs_wallet`/`cs_KeyStore` locks to wallet (practicalswift)
+- #14296 Remove `addwitnessaddress` (jnewbery)
+- #14451 Add BIP70 deprecation warning and allow building GUI without BIP70 support (jameshilliard)
+- #14320 Fix duplicate fileid detection (ken2812221)
+- #14561 Remove `fs::relative` call and fix listwalletdir tests (promag)
+- #14454 Add SegWit support to importmulti (MeshCollider)
+- #14410 rpcwallet: `ischange` field for `getaddressinfo` RPC (mrwhythat)
+- #14350 Add WalletLocation class (promag)
+- #14689 Require a public key to be retrieved when signing a P2PKH input (achow101)
+- #14478 Show error to user when corrupt wallet unlock fails (MeshCollider)
+- #14411 Restore ability to list incoming transactions by label (ryanofsky)
+- #14552 Detect duplicate wallet by comparing the db filename (ken2812221)
+- #14678 Remove redundant KeyOriginInfo access, already done in CreateSig (instagibbs)
+- #14477 Add ability to convert solvability info to descriptor (sipa)
+- #14380 Fix assert crash when specified change output spend size is unknown (instagibbs)
+- #14760 Log env path in `BerkeleyEnvironment::Flush` (promag)
+- #14646 Add expansion cache functions to descriptors (unused for now) (sipa)
+- #13076 Fix ScanForWalletTransactions to return an enum indicating scan result: `success` / `failure` / `user_abort` (Empact)
+- #14821 Replace CAffectedKeysVisitor with descriptor based logic (sipa)
+- #14957 Initialize `stop_block` in CWallet::ScanForWalletTransactions (Empact)
+- #14565 Overhaul `importmulti` logic (sipa)
+- #15039 Avoid leaking nLockTime fingerprint when anti-fee-sniping (MarcoFalke)
+- #14268 Introduce SafeDbt to handle Dbt with free or `memory_cleanse` raii-style (Empact)
+- #14711 Remove uses of chainActive and mapBlockIndex in wallet code (ryanofsky)
+- #15279 Clarify rescanblockchain doc (MarcoFalke)
+- #15292 Remove `boost::optional`-related false positive -Wmaybe-uninitialized warnings on GCC compiler (hebasto)
+- #13926 [Tools] bitcoin-wallet - a tool for creating and managing wallets offline (jnewbery)
+- #11911 Free BerkeleyEnvironment instances when not in use (ryanofsky)
+- #15235 Do not import private keys to wallets with private keys disabled (achow101)
+- #15263 Descriptor expansions only need pubkey entries for PKH/WPKH (sipa)
+- #15322 Add missing `cs_db` lock (promag)
+- #15297 Releases dangling files on `BerkeleyEnvironment::Close` (promag)
+- #14491 Allow descriptor imports with importmulti (MeshCollider)
+- #15365 Add lock annotation for mapAddressBook (MarcoFalke)
+- #15226 Allow creating blank (empty) wallets (alternative) (achow101)
+- #15390 [wallet-tool] Close bdb when flushing wallet (jnewbery)
+- #15334 Log absolute paths for the wallets (hebasto)
+- #14978 Factor out PSBT utilities from RPCs for use in GUI code; related refactoring (gwillen)
+- #14481 Add P2SH-P2WSH support to listunspent RPC (MeshCollider)
+- #14021 Import key origin data through descriptors in importmulti (achow101)
+- #14075 Import watch only pubkeys to the keypool if private keys are disabled (achow101)
+- #15368 Descriptor checksums (sipa)
+- #15433 Use a single wallet batch for `UpgradeKeyMetadata` (jonasschnelli)
+- #15408 Remove unused `TransactionError` constants (MarcoFalke)
+- #15583 Log and ignore errors in ListWalletDir and IsBerkeleyBtree (promag)
+- #14195 Pass privkey export DER compression flag correctly (fingera)
+- #15299 Fix assertion in `CKey::SignCompact` (promag)
+- #14437 Start to separate wallet from node (ryanofsky)
+- #15749 Fix: importmulti only imports origin info for PKH outputs (sipa)
+
+### RPC and other APIs
+- #12842 Prevent concurrent `savemempool` (promag)
+- #13987 Report `minfeefilter` value in `getpeerinfo` RPC (ajtowns)
+- #13891 Remove getinfo deprecation warning (jnewbery)
+- #13399 Add `submitheader` (MarcoFalke)
+- #12676 Show `bip125-replaceable` flag, when retrieving mempool entries (dexX7)
+- #13723 PSBT key path cleanups (sipa)
+- #14008 Preserve a format of RPC command definitions (kostyantyn)
+- #9332 Let wallet `importmulti` RPC accept labels for standard scriptPubKeys (ryanofsky)
+- #13983 Return more specific reject reason for submitblock (MarcoFalke)
+- #13152 Add getnodeaddresses RPC command (chris-belcher)
+- #14298 rest: Improve performance for JSON calls (alecalve)
+- #14297 Remove warning for removed estimatefee RPC (jnewbery)
+- #14373 Consistency fixes for RPC descriptions (ch4ot1c)
+- #14150 Add key origin support to descriptors (sipa)
+- #14518 Always throw in getblockstats if `-txindex` is required (promag)
+- #14060 ZMQ: add options to configure outbound message high water mark, aka SNDHWM (mruddy)
+- #13381 Add possibility to preserve labels on importprivkey (marcoagner)
+- #14530 Use `RPCHelpMan` to generate RPC doc strings (MarcoFalke)
+- #14720 Correctly name RPC arguments (MarcoFalke)
+- #14726 Use `RPCHelpMan` for all RPCs (MarcoFalke)
+- #14796 Pass argument descriptions to `RPCHelpMan` (MarcoFalke)
+- #14670 http: Fix HTTP server shutdown (promag)
+- #14885 Assert that named arguments are unique in `RPCHelpMan` (promag)
+- #14877 Document default values for optional arguments (MarcoFalke)
+- #14875 RPCHelpMan: Support required arguments after optional ones (MarcoFalke)
+- #14993 Fix data race (UB) in InterruptRPC() (practicalswift)
+- #14653 rpcwallet: Add missing transaction categories to RPC helptexts (andrewtoth)
+- #14981 Clarify RPC `getrawtransaction`'s time help text (benthecarman)
+- #12151 Remove `cs_main` lock from blockToJSON and blockheaderToJSON (promag)
+- #15078 Document `bytessent_per_msg` and `bytesrecv_per_msg` (MarcoFalke)
+- #15057 Correct `reconsiderblock `help text, add test (MarcoFalke)
+- #12153 Avoid permanent `cs_main` lock in `getblockheader` (promag)
+- #14982 Add `getrpcinfo` command (promag)
+- #15122 Expand help text for `importmulti` changes (jnewbery)
+- #15186 remove duplicate solvable field from `getaddressinfo` (fanquake)
+- #15209 zmq: log outbound message high water mark when reusing socket (fanquake)
+- #15177 rest: Improve tests and documention of /headers and /block (promag)
+- #14353 rest: Add blockhash call, fetch blockhash by height (jonasschnelli)
+- #15248 Compile on GCC4.8 (MarcoFalke)
+- #14987 RPCHelpMan: Pass through Result and Examples (MarcoFalke)
+- #15159 Remove lookup to UTXO set from GetTransaction (amitiuttarwar)
+- #15245 remove deprecated mentions of signrawtransaction from fundraw help (instagibbs)
+- #14667 Add `deriveaddresses` RPC util method (Sjors)
+- #15357 Don't ignore `-maxtxfee` when wallet is disabled (JBaczuk)
+- #15337 Fix for segfault if combinepsbt called with empty inputs (benthecarman)
+- #14918 RPCHelpMan: Check default values are given at compile-time (MarcoFalke)
+- #15383 mining: Omit uninitialized currentblockweight, currentblocktx (MarcoFalke)
+- #13932 Additional utility RPCs for PSBT (achow101)
+- #15401 Actually throw help when passed invalid number of params (MarcoFalke)
+- #15471 rpc/gui: Remove 'Unknown block versions being mined' warning (laanwj)
+- #15497 Consistent range arguments in scantxoutset/importmulti/deriveaddresses (sipa)
+- #15510 deriveaddresses: add range to CRPCConvertParam (Sjors)
+- #15582 Fix overflow bug in analyzepsbt fee: CAmount instead of int (sipa)
+- #13424 Consistently validate txid / blockhash length and encoding in rpc calls (Empact)
+- #15750 Remove the addresses field from the getaddressinfo return object (jnewbery)
+
+### GUI
+- #13634 Compile `boost::signals2` only once (MarcoFalke)
+- #13248 Make proxy icon from statusbar clickable (mess110)
+- #12818 TransactionView: highlight replacement tx after fee bump (Sjors)
+- #13529 Use new Qt5 connect syntax (promag)
+- #14162 Also log and print messages or questions like bitcoind (MarcoFalke)
+- #14385 Avoid system harfbuzz and bz2 (theuni)
+- #14450 Fix QCompleter popup regression (hebasto)
+- #14177 Set C locale for amountWidget (hebasto)
+- #14374 Add `Blocksdir` to Debug window (hebasto)
+- #14554 Remove unused `adjustedTime` parameter (hebasto)
+- #14228 Enable system tray icon by default if available (hebasto)
+- #14608 Remove the "Pay only required fee…" checkbox (hebasto)
+- #14521 qt, docs: Fix `bitcoin-qt -version` output formatting (hebasto)
+- #13966 When private key is disabled, only show watch-only balance (ken2812221)
+- #14828 Remove hidden columns in coin control dialog (promag)
+- #14783 Fix `boost::signals2::no_slots_error` in early calls to InitWarning (promag)
+- #14854 Cleanup SplashScreen class (hebasto)
+- #14801 Use window() instead of obsolete topLevelWidget() (hebasto)
+- #14573 Add Window menu (promag)
+- #14979 Restore < Qt5.6 compatibility for addAction (jonasschnelli)
+- #14975 Refactoring with QString::toNSString() (hebasto)
+- #15000 Fix broken notificator on GNOME (hebasto)
+- #14375 Correct misleading "overridden options" label (hebasto)
+- #15007 Notificator class refactoring (hebasto)
+- #14784 Use `WalletModel*` instead of the wallet name as map key (promag)
+- #11625 Add BitcoinApplication & RPCConsole tests (ryanofsky)
+- #14517 Fix start with the `-min` option (hebasto)
+- #13216 implements concept for different disk sizes on intro (marcoagner)
+- #15114 Replace remaining 0 with nullptr (Empact)
+- #14594 Fix minimized window bug on Linux (hebasto)
+- #14556 Fix confirmed transaction labeled "open" (#13299) (hebasto)
+- #15149 Show current wallet name in window title (promag)
+- #15136 "Peers" tab overhaul (hebasto)
+- #14250 Remove redundant stopThread() and stopExecutor() signals (hebasto)
+- #15040 Add workaround for QProgressDialog bug on macOS (hebasto)
+- #15101 Add WalletController (promag)
+- #15178 Improve "help-console" message (hebasto)
+- #15210 Fix window title update (promag)
+- #15167 Fix wallet selector size adjustment (hebasto)
+- #15208 Remove macOS launch-at-startup when compiled with > macOS 10.11, fix memory mismanagement (jonasschnelli)
+- #15163 Correct units for "-dbcache" and "-prune" (hebasto)
+- #15225 Change the receive button to respond to keypool state changing (achow101)
+- #15280 Fix shutdown order (promag)
+- #15203 Fix issue #9683 "gui, wallet: random abort (segmentation fault) (dooglus)
+- #15091 Fix model overlay header sync (jonasschnelli)
+- #15153 Add Open Wallet menu (promag)
+- #15183 Fix `m_assumed_blockchain_size` variable value (marcoagner)
+- #15063 If BIP70 is disabled, attempt to fall back to BIP21 parsing (luke-jr)
+- #15195 Add Close Wallet action (promag)
+- #15462 Fix async open wallet call order (promag)
+- #15801 Bugfix: GUI: Options: Initialise prune setting range before loading current value, and remove upper bound limit (luke-jr)
+
+### Build system
+- #13955 gitian: Bump descriptors for (0.)18 (fanquake)
+- #13899 Enable -Wredundant-decls where available. Remove redundant redeclarations (practicalswift)
+- #13665 Add RISC-V support to gitian (ken2812221)
+- #14062 Generate MSVC project files via python script (ken2812221)
+- #14037 Add README.md to linux release tarballs (hebasto)
+- #14183 Remove unused Qt 4 dependencies (ken2812221)
+- #14127 Avoid getifaddrs when unavailable (greenaddress)
+- #14184 Scripts and tools: increased timeout downloading (cisba)
+- #14204 Move `interfaces/*` to `libbitcoin_server` (laanwj)
+- #14208 Actually remove `ENABLE_WALLET` (jnewbery)
+- #14212 Remove libssl from LDADD unless GUI (MarcoFalke)
+- #13578 Upgrade zeromq to 4.2.5 and avoid deprecated zeromq API functions (mruddy)
+- #14281 lcov: filter /usr/lib/ from coverage reports (MarcoFalke)
+- #14325 gitian: Use versioned unsigned tarballs instead of generically named ones (achow101)
+- #14253 During 'make clean', remove some files that are currently missed (murrayn)
+- #14455 Unbreak `make clean` (jamesob)
+- #14495 Warn (don't fail!) on spelling errors (practicalswift)
+- #14496 Pin to specific versions of Python packages we install from PyPI in Travis (practicalswift)
+- #14568 Fix Qt link order for Windows build (ken2812221)
+- #14252 Run functional tests and benchmarks under the undefined behaviour sanitizer (UBSan) (practicalswift)
+- #14612 Include full version number in released file names (achow101)
+- #14840 Remove duplicate libconsensus linking in test make (AmirAbrams)
+- #14564 Adjust configure so that only BIP70 is disabled when protobuf is missing instead of the GUI (jameshilliard)
+- #14883 Add `--retry 5` to curl opts in `install_db4.sh` (qubenix)
+- #14701 Add `CLIENT_VERSION_BUILD` to CFBundleGetInfoString (fanquake)
+- #14849 Qt 5.9.7 (fanquake)
+- #15020 Add names to Travis jobs (gkrizek)
+- #15047 Allow to configure --with-sanitizers=fuzzer (MarcoFalke)
+- #15154 Configure: bitcoin-tx doesn't need libevent, so don't pull it in (luke-jr)
+- #15175 Drop macports support (Empact)
+- #15308 Restore compatibility with older boost (Empact)
+- #15407 msvc: Fix silent merge conflict between #13926 and #14372 part II (ken2812221)
+- #15388 Makefile.am: add rule for src/bitcoin-wallet (Sjors)
+- #15393 Bump minimum Qt version to 5.5.1 (Sjors)
+- #15285 Prefer Python 3.4 even if newer versions are present on the system (Sjors)
+- #15398 msvc: Add rapidcheck property tests (ken2812221)
+- #15431 msvc: scripted-diff: Remove NDEBUG pre-define in project file (ken2812221)
+- #15549 gitian: Improve error handling (laanwj)
+- #15548 use full version string in setup.exe (MarcoFalke)
+- #11526 Visual Studio build configuration for Bitcoin Core (sipsorcery)
+- #15110 build\_msvc: Fix the build problem in `libbitcoin_server` (Mr-Leshiy)
+- #14372 msvc: build secp256k1 and leveldb locally (ken2812221)
+- #15325 msvc: Fix silent merge conflict between #13926 and #14372 (ken2812221)
+- #15391 Add compile time verification of assumptions we're currently making implicitly/tacitly (practicalswift)
+- #15503 msvc: Use a single file to specify the include path (ken2812221)
+- #13765 contrib: Add gitian build support for github pull request (ken2812221)
+- #15809 gitignore: plist and dat (jamesob)
+
+### Tests and QA
+- #15405 appveyor: Clean cache when build configuration changes (Sjors)
+- #13953 Fix deprecation in bitcoin-util-test.py (isghe)
+- #13963 Replace usage of tostring() with tobytes() (dongcarl)
+- #13964 ci: Add appveyor ci (ken2812221)
+- #13997 appveyor: fetch the latest port data (ken2812221)
+- #13707 Add usage note to check-rpc-mappings.py (masonicboom)
+- #14036 travis: Run unit tests --with-sanitizers=undefined (MarcoFalke)
+- #13861 Add testing of `value_ret` for SelectCoinsBnB (Empact)
+- #13863 travis: Move script sections to files in `.travis/` subject to shellcheck (scravy)
+- #14081 travis: Fix missing differentiation between unit and functional tests (scravy)
+- #14042 travis: Add cxxflags=-wno-psabi at arm job (ken2812221)
+- #14051 Make `combine_logs.py` handle multi-line logs (jnewbery)
+- #14093 Fix accidental trunction from int to bool (practicalswift)
+- #14108 Add missing locking annotations and locks (`g_cs_orphans`) (practicalswift)
+- #14088 Don't assert(…) with side effects (practicalswift)
+- #14086 appveyor: Use clcache to speed up build (ken2812221)
+- #13954 Warn (don't fail!) on spelling errors. Fix typos reported by codespell (practicalswift)
+- #12775 Integration of property based testing into Bitcoin Core (Christewart)
+- #14119 Read reject reasons from debug log, not P2P messages (MarcoFalke)
+- #14189 Fix silent merge conflict in `wallet_importmulti` (MarcoFalke)
+- #13419 Speed up `knapsack_solver_test` by not recreating wallet 100 times (lucash-dev)
+- #14199 Remove redundant BIP174 test from `rpc_psbt.json` (araspitzu)
+- #14179 Fixups to "Run all tests even if wallet is not compiled" (MarcoFalke)
+- #14225 Reorder tests and move most of extended tests up to normal tests (ken2812221)
+- #14236 `generate` --> `generatetoaddress` change to allow tests run without wallet (sanket1729)
+- #14287 Use MakeUnique to construct objects owned by `unique_ptrs` (practicalswift)
+- #14007 Run functional test on Windows and enable it on Appveyor (ken2812221)
+- #14275 Write the notification message to different files to avoid race condition in `feature_notifications.py` (ken2812221)
+- #14306 appveyor: Move AppVeyor YAML to dot-file-style YAML (MitchellCash)
+- #14305 Enforce critical class instance attributes in functional tests, fix segwit test specificity (JustinTArthur)
+- #12246 Bugfix: Only run bitcoin-tx tests when bitcoin-tx is enabled (luke-jr)
+- #14316 Exclude all tests with difference parameters in `--exclude` list (ken2812221)
+- #14381 Add missing call to `skip_if_no_cli()` (practicalswift)
+- #14389 travis: Set codespell version to avoid breakage (MarcoFalke)
+- #14398 Don't access out of bounds array index: array[sizeof(array)] (Empact)
+- #14419 Remove `rpc_zmq.py` (jnewbery)
+- #14241 appveyor: Script improvement (ken2812221)
+- #14413 Allow closed RPC handler in `assert_start_raises_init_error` (ken2812221)
+- #14324 Run more tests with wallet disabled (MarcoFalke)
+- #13649 Allow arguments to be forwarded to flake8 in lint-python.sh (jamesob)
+- #14465 Stop node before removing the notification file (ken2812221)
+- #14460 Improve 'CAmount' tests (hebasto)
+- #14456 forward timeouts properly in `send_blocks_and_test` (jamesob)
+- #14527 Revert "Make qt wallet test compatible with qt4" (MarcoFalke)
+- #14504 Show the progress of functional tests (isghe)
+- #14559 appveyor: Enable multiwallet tests (ken2812221)
+- #13515 travis: Enable qt for all jobs (ken2812221)
+- #14571 Test that nodes respond to `getdata` with `notfound` (MarcoFalke)
+- #14569 Print dots by default in functional tests (ken2812221)
+- #14631 Move deterministic address import to `setup_nodes` (jnewbery)
+- #14630 test: Remove travis specific code (MarcoFalke)
+- #14528 travis: Compile once on xenial (MarcoFalke)
+- #14092 Dry run `bench_bitcoin` as part `make check` to allow for quick identification of assertion/sanitizer failures in benchmarking code (practicalswift)
+- #14664 `example_test.py`: fixup coinbase height argument, derive number clearly (instagibbs)
+- #14522 Add invalid P2P message tests (jamesob)
+- #14619 Fix value display name in `test_runner` help text (merland)
+- #14672 Send fewer spam messages in `p2p_invalid_messages` (jamesob)
+- #14673 travis: Fail the ubsan travis build in case of newly introduced ubsan errors (practicalswift)
+- #14665 appveyor: Script improvement part II (ken2812221)
+- #14365 Add Python dead code linter (vulture) to Travis (practicalswift)
+- #14693 `test_node`: `get_mem_rss` fixups (MarcoFalke)
+- #14714 util.h: explicitly include required QString header (1Il1)
+- #14705 travis: Avoid timeout on verify-commits check (MarcoFalke)
+- #14770 travis: Do not specify sudo in `.travis` (scravy)
+- #14719 Check specific reject reasons in `feature_block` (MarcoFalke)
+- #14771 Add `BOOST_REQUIRE` to getters returning optional (MarcoFalke)
+- #14777 Add regtest for JSON-RPC batch calls (domob1812)
+- #14764 travis: Run thread sanitizer on unit tests (MarcoFalke)
+- #14400 Add Benchmark to test input de-duplication worst case (JeremyRubin)
+- #14812 Fix `p2p_invalid_messages` on macOS (jamesob)
+- #14813 Add `wallet_encryption` error tests (MarcoFalke)
+- #14820 Fix `descriptor_tests` not checking ToString output of public descriptors (ryanofsky)
+- #14794 Add AddressSanitizer (ASan) Travis build (practicalswift)
+- #14819 Bugfix: `test/functional/mempool_accept`: Ensure oversize transaction is actually oversize (luke-jr)
+- #14822 bench: Destroy wallet txs instead of leaking their memory (MarcoFalke)
+- #14683 Better `combine_logs.py` behavior (jamesob)
+- #14231 travis: Save cache even when build or test fail (ken2812221)
+- #14816 Add CScriptNum decode python implementation in functional suite (instagibbs)
+- #14861 Modify `rpc_bind` to conform to #14532 behaviour (dongcarl)
+- #14864 Run scripted-diff in subshell (dongcarl)
+- #14795 Allow `test_runner` command line to receive parameters for each test (marcoagner)
+- #14788 Possible fix the permission error when the tests open the cookie file (ken2812221)
+- #14857 `wallet_keypool_topup.py`: Test for all keypool address types (instagibbs)
+- #14886 Refactor importmulti tests (jnewbery)
+- #14908 Removed implicit CTransaction constructor calls from tests and benchmarks (lucash-dev)
+- #14903 Handle ImportError explicitly, improve comparisons against None (daniel-s-ingram)
+- #14884 travis: Enforce python 3.4 support through linter (Sjors)
+- #14940 Add test for truncated pushdata script (MarcoFalke)
+- #14926 consensus: Check that final transactions are valid (MarcoFalke)
+- #14937 travis: Fix travis would always be green even if it fail (ken2812221)
+- #14953 Make `g_insecure_rand_ctx` `thread_local` (MarcoFalke)
+- #14931 mempool: Verify prioritization is dumped correctly (MarcoFalke)
+- #14935 Test for expected return values when calling functions returning a success code (practicalswift)
+- #14969 Fix `cuckoocache_tests` TSAN failure introduced in 14935 (practicalswift)
+- #14964 Fix race in `mempool_accept` (MarcoFalke)
+- #14829 travis: Enable functional tests in the threadsanitizer (tsan) build job (practicalswift)
+- #14985 Remove `thread_local` from `test_bitcoin` (MarcoFalke)
+- #15005 Bump timeout to run tests in travis thread sanitizer (MarcoFalke)
+- #15013 Avoid race in `p2p_timeouts` (MarcoFalke)
+- #14960 lint/format-strings: Correctly exclude escaped percent symbols (luke-jr)
+- #14930 pruning: Check that verifychain can be called when pruned (MarcoFalke)
+- #15022 Upgrade Travis OS to Xenial (gkrizek)
+- #14738 Fix running `wallet_listtransactions.py` individually through `test_runner.py` (kristapsk)
+- #15026 Rename `rpc_timewait` to `rpc_timeout` (MarcoFalke)
+- #15069 Fix `rpc_net.py` `pong` race condition (Empact)
+- #14790 Allow running `rpc_bind.py` --nonloopback test without IPv6 (kristapsk)
+- #14457 add invalid tx templates for use in functional tests (jamesob)
+- #14855 Correct ineffectual WithOrVersion from `transactions_tests` (Empact)
+- #15099 Use `std::vector` API for construction of test data (domob1812)
+- #15102 Run `invalid_txs.InputMissing` test in `feature_block` (MarcoFalke)
+- #15059 Add basic test for BIP34 (MarcoFalke)
+- #15108 Tidy up `wallet_importmulti.py` (amitiuttarwar)
+- #15164 Ignore shellcheck warning SC2236 (promag)
+- #15170 refactor/lint: Add ignored shellcheck suggestions to an array (koalaman)
+- #14958 Remove race between connecting and shutdown on separate connections (promag)
+- #15166 Pin shellcheck version (practicalswift)
+- #15196 Update all `subprocess.check_output` functions to be Python 3.4 compatible (gkrizek)
+- #15043 Build fuzz targets into seperate executables (MarcoFalke)
+- #15276 travis: Compile once on trusty (MarcoFalke)
+- #15246 Add tests for invalid message headers (MarcoFalke)
+- #15301 When testing with --usecli, unify RPC arg to cli arg conversion and handle dicts and lists (achow101)
+- #15247 Use wallet to retrieve raw transactions (MarcoFalke)
+- #15303 travis: Remove unused `functional_tests_config` (MarcoFalke)
+- #15330 Fix race in `p2p_invalid_messages` (MarcoFalke)
+- #15324 Make bloom tests deterministic (MarcoFalke)
+- #15328 travis: Revert "run extended tests once daily" (MarcoFalke)
+- #15327 Make test `updatecoins_simulation_test` deterministic (practicalswift)
+- #14519 add utility to easily profile node performance with perf (jamesob)
+- #15349 travis: Only exit early if compilation took longer than 30 min (MarcoFalke)
+- #15350 Drop RPC connection if --usecli (promag)
+- #15370 test: Remove unused --force option (MarcoFalke)
+- #14543 minor `p2p_sendheaders` fix of height in coinbase (instagibbs)
+- #13787 Test for Windows encoding issue (ken2812221)
+- #15378 Added missing tests for RPC wallet errors (benthecarman)
+- #15238 remove some magic mining constants in functional tests (instagibbs)
+- #15411 travis: Combine --disable-bip70 into existing job (MarcoFalke)
+- #15295 fuzz: Add `test/fuzz/test_runner.py` and run it in travis (MarcoFalke)
+- #15413 Add missing `cs_main` locks required when accessing pcoinsdbview, pcoinsTip or pblocktree (practicalswift)
+- #15399 fuzz: Script validation flags (MarcoFalke)
+- #15410 txindex: interrupt threadGroup before calling destructor (MarcoFalke)
+- #15397 Remove manual byte editing in `wallet_tx_clone` func test (instagibbs)
+- #15415 functional: allow custom cwd, use tmpdir as default (Sjors)
+- #15404 Remove `-txindex` to start nodes (amitiuttarwar)
+- #15439 remove `byte.hex()` to keep compatibility (AkioNak)
+- #15419 Always refresh cache to be out of ibd (MarcoFalke)
+- #15507 Bump timeout on tests that timeout on windows (MarcoFalke)
+- #15506 appveyor: fix cache issue and reduce dependencies build time (ken2812221)
+- #15485 add `rpc_misc.py`, mv test getmemoryinfo, add test mallocinfo (adamjonas)
+- #15321 Add `cs_main` lock annotations for mapBlockIndex (MarcoFalke)
+- #14128 lint: Make sure we read the command line inputs using UTF-8 decoding in python (ken2812221)
+- #14115 lint: Make all linters work under the default macos dev environment (build-osx.md) (practicalswift)
+- #15219 lint: Enable python linters via an array (Empact)
+
+### Platform support
+- #13866 utils: Use `_wfopen` and `_wfreopen` on windows (ken2812221)
+- #13886 utils: Run commands using UTF-8 string on windows (ken2812221)
+- #14192 utils: Convert `fs::filesystem_error` messages from local multibyte to UTF-8 on windows (ken2812221)
+- #13877 utils: Make fs::path::string() always return UTF-8 string on windows (ken2812221)
+- #13883 utils: Convert windows args to UTF-8 string (ken2812221)
+- #13878 utils: Add fstream wrapper to allow to pass unicode filename on windows (ken2812221)
+- #14426 utils: Fix broken windows filelock (ken2812221)
+- #14686 Fix windows build error if `--disable-bip70` (ken2812221)
+- #14922 windows: Set `_WIN32_WINNT` to 0x0601 (Windows 7) (ken2812221)
+- #13888 Call unicode API on Windows (ken2812221)
+- #15468 Use `fsbridge::ifstream` to fix Windows path issue (ken2812221)
+- #13734 Drop `boost::scoped_array` and use `wchar_t` API explicitly on Windows (ken2812221)
+- #13884 Enable bdb unicode support for Windows (ken2812221)
+
+### Miscellaneous
+- #13935 contrib: Adjust output to current test format (AkioNak)
+- #14097 validation: Log FormatStateMessage on ConnectBlock error in ConnectTip (MarcoFalke)
+- #13724 contrib: Support ARM and RISC-V symbol check (ken2812221)
+- #13159 Don't close old debug log file handle prematurely when trying to re-open (on SIGHUP) (practicalswift)
+- #14186 bitcoin-cli: don't translate command line options (HashUnlimited)
+- #14057 logging: Only log `using config file path_to_bitcoin.conf` message on startup if conf file exists (leishman)
+- #14164 Update univalue subtree (MarcoFalke)
+- #14272 init: Remove deprecated args from hidden args (MarcoFalke)
+- #14494 Error if # is used in rpcpassword in conf (MeshCollider)
+- #14742 Properly generate salt in rpcauth.py (dongcarl)
+- #14708 Warn unrecognised sections in the config file (AkioNak)
+- #14756 Improve rpcauth.py by using argparse and getpass modules (promag)
+- #14785 scripts: Fix detection of copyright holders (cornelius)
+- #14831 scripts: Use `#!/usr/bin/env bash` instead of `#!/bin/bash` (vim88)
+- #14869 Scripts: Add trusted key for samuel dobson (laanwj)
+- #14809 Tools: improve verify-commits.py script (jlopp)
+- #14624 Some simple improvements to the RNG code (sipa)
+- #14947 scripts: Remove python 2 import workarounds (practicalswift)
+- #15087 Error if rpcpassword contains hash in conf sections (MeshCollider)
+- #14433 Add checksum in gitian build scripts for ossl (TheCharlatan)
+- #15165 contrib: Allow use of github api authentication in github-merge (laanwj)
+- #14409 utils and libraries: Make 'blocksdir' always net specific (hebasto)
+- #14839 threads: Fix unitialized members in `sched_param` (fanquake)
+- #14955 Switch all RNG code to the built-in PRNG (sipa)
+- #15258 Scripts and tools: Fix `devtools/copyright_header.py` to always honor exclusions (Empact)
+- #12255 Update bitcoin.service to conform to init.md (dongcarl)
+- #15266 memory: Construct globals on first use (MarcoFalke)
+- #15347 Fix build after pr 15266 merged (hebasto)
+- #15351 Update linearize-hashes.py (OverlordQ)
+- #15358 util: Add setuphelpoptions() (MarcoFalke)
+- #15216 Scripts and tools: Replace script name with a special parameter (hebasto)
+- #15250 Use RdSeed when available, and reduce RdRand load (sipa)
+- #15278 Improve PID file error handling (hebasto)
+- #15270 Pull leveldb subtree (MarcoFalke)
+- #15456 Enable PID file creation on WIN (riordant)
+- #12783 macOS: disable AppNap during sync (krab)
+- #13910 Log progress while verifying blocks at level 4 (domob1812)
+- #15124 Fail AppInitMain if either disk space check fails (Empact)
+- #15117 Fix invalid memory write in case of failing mmap(…) in PosixLockedPageAllocator::AllocateLocked (practicalswift)
+- #14357 streams: Fix broken `streams_vector_reader` test. Remove unused `seek(size_t)`
+- #11640 Make `LOCK`, `LOCK2`, `TRY_LOCK` work with CWaitableCriticalSection (ryanofsky)
+- #14074 Use `std::unordered_set` instead of `set` in blockfilter interface (jimpo)
+- #15275 Add gitian PGP key for hebasto (hebasto)
+
+### Documentation
+- #14120 Notes about control port and read access to cookie (JBaczuk)
+- #14135 correct GetDifficulty doc after #13288 (fanquake)
+- #14013 Add new regtest ports in man following #10825 ports reattributions (ariard)
+- #14149 Remove misleading checkpoints comment in CMainParams (MarcoFalke)
+- #14153 Add disable-wallet section to OSX build instructions, update line in Unix instructions (bitstein)
+- #13662 Explain when reindex-chainstate can be used instead of reindex (Sjors)
+- #14207 `-help-debug` implies `-help` (laanwj)
+- #14213 Fix reference to lint-locale-dependence.sh (hebasto)
+- #14206 Document `-checklevel` levels (laanwj)
+- #14217 Add GitHub PR template (MarcoFalke)
+- #14331 doxygen: Fix member comments (MarcoFalke)
+- #14264 Split depends installation instructions per arch (MarcoFalke)
+- #14393 Add missing apt-get install (poiuty)
+- #14428 Fix macOS files description in qt/README.md (hebasto)
+- #14390 release process: RPC documentation (karel-3d)
+- #14472 getblocktemplate: use SegWit in example (Sjors)
+- #14497 Add doc/bitcoin-conf.md (hebasto)
+- #14526 Document lint tests (fanquake)
+- #14511 Remove explicit storage requirement from README.md (merland)
+- #14600 Clarify commit message guidelines (merland)
+- #14617 FreeBSD: Document Python 3 requirement for 'gmake check' (murrayn)
+- #14592 Add external interface consistency guarantees (MarcoFalke)
+- #14625 Make clear function argument case in dev notes (dongcarl)
+- #14515 Update OpenBSD build guide for 6.4 (fanquake)
+- #14436 Add comment explaining recentRejects-DoS behavior (jamesob)
+- #14684 conf: Remove deprecated options from docs, Other cleanup (MarcoFalke)
+- #14731 Improve scripted-diff developer docs (dongcarl)
+- #14778 A few minor formatting fixes and clarifications to descriptors.md (jnewbery)
+- #14448 Clarify rpcwallet flag url change (JBaczuk)
+- #14808 Clarify RPC rawtransaction documentation (jlopp)
+- #14804 Less confusing documentation for `torpassword` (fanquake)
+- #14848 Fix broken Gmane URL in security-check.py (cyounkins-bot)
+- #14882 developer-notes.md: Point out that UniValue deviates from upstream (Sjors)
+- #14909 Update minimum required Qt (fanquake)
+- #14914 Add nice table to files.md (emilengler)
+- #14741 Indicate `-rpcauth` option password hashing alg (dongcarl)
+- #14950 Add NSIS setup/install steps to windows docs (fanquake)
+- #13930 Better explain GetAncestor check for `m_failed_blocks` in AcceptBlockHeader (Sjors)
+- #14973 Improve Windows native build instructions (murrayn)
+- #15073 Botbot.me (IRC logs) not available anymore (anduck)
+- #15038 Get more info about GUI-related issue on Linux (hebasto)
+- #14832 Add more Doxygen information to Developer Notes (ch4ot1c)
+- #15128 Fix download link in doc/README.md (merland)
+- #15127 Clarifying testing instructions (benthecarman)
+- #15132 Add FreeBSD build notes link to doc/README.md (fanquake)
+- #15173 Explain what .python-version does (Sjors)
+- #15223 Add information about security to the JSON-RPC doc (harding)
+- #15249 Update python docs to reflect that wildcard imports are disallowed (Empact)
+- #15176 Get rid of badly named `doc/README_osx.md` (merland)
+- #15272 Correct logging return type and RPC example (fanquake)
+- #15244 Gdb attaching to process during tests has non-sudo solution (instagibbs)
+- #15332 Small updates to `getrawtransaction` description (amitiuttarwar)
+- #15354 Add missing `bitcoin-wallet` tool manpages (MarcoFalke)
+- #15343 netaddress: Make IPv4 loopback comment more descriptive (dongcarl)
+- #15353 Minor textual improvements in `translation_strings_policy.md` (merland)
+- #15426 importmulti: add missing description of keypool option (harding)
+- #15425 Add missing newline to listunspent help for witnessScript (harding)
+- #15348 Add separate productivity notes document (dongcarl)
+- #15416 Update FreeBSD build guide for 12.0 (fanquake)
+- #15222 Add info about factors that affect dependency list (merland)
+- #13676 Explain that mempool memory is added to `-dbcache` (Sjors)
+- #15273 Slight tweak to the verify-commits script directions (droark)
+- #15477 Remove misleading hint in getrawtransaction (MarcoFalke)
+- #15489 Update release process for snap package (MarcoFalke)
+- #15524 doc: Remove berkeleydb PPA from linux build instructions (MarcoFalke)
+- #15559 Correct `analyzepsbt` rpc doc (fanquake)
+- #15194 Add comment describing `fDisconnect` behavior (dongcarl)
+- #15754 getrpcinfo docs (benthecarman)
+- #15763 Update bips.md for 0.18.0 (sipa)
+- #15757 List new RPCs in psbt.md and descriptors.md (sipa)
+- #15765 correct bitcoinconsensus_version in shared-libraries.md (fanquake)
+- #15792 describe onlynet option in doc/tor.md (jonatack)
+- #15802 mention creating application support bitcoin folder on OSX (JimmyMow)
+- #15799 Clarify RPC versioning (MarcoFalke)
+
+Credits
+=======
+
+Thanks to everyone who directly contributed to this release:
+
+- 1Il1
+- 251
+- Aaron Clauson
+- Adam Jonas
+- Akio Nakamura
+- Alexander Leishman
+- Alexey Ivanov
+- Alexey Poghilenkov
+- Amir Abrams
+- Amiti Uttarwar
+- Andrew Chow
+- andrewtoth
+- Anthony Towns
+- Antoine Le Calvez
+- Antoine Riard
+- Antti Majakivi
+- araspitzu
+- Arvid Norberg
+- Ben Carman
+- Ben Woosley
+- benthecarman
+- bitcoinhodler
+- Carl Dong
+- Chakib Benziane
+- Chris Moore
+- Chris Stewart
+- chris-belcher
+- Chun Kuan Lee
+- Cornelius Schumacher
+- Cory Fields
+- Craig Younkins
+- Cristian Mircea Messel
+- Damian Mee
+- Daniel Ingram
+- Daniel Kraft
+- David A. Harding
+- DesWurstes
+- dexX7
+- Dimitri Deijs
+- Dimitris Apostolou
+- Douglas Roark
+- DrahtBot
+- Emanuele Cisbani
+- Emil Engler
+- Eric Scrivner
+- fridokus
+- Gal Buki
+- Gleb Naumenko
+- Glenn Willen
+- Graham Krizek
+- Gregory Maxwell
+- Gregory Sanders
+- gustavonalle
+- Harry Moreno
+- Hennadii Stepanov
+- Isidoro Ghezzi
+- Jack Mallers
+- James Hilliard
+- James O'Beirne
+- Jameson Lopp
+- Jeremy Rubin
+- Jesse Cohen
+- Jim Posen
+- John Newbery
+- Jon Layton
+- Jonas Schnelli
+- João Barbosa
+- Jordan Baczuk
+- Jorge Timón
+- Julian Fleischer
+- Justin Turner Arthur
+- Karel Bílek
+- Karl-Johan Alm
+- Kaz Wesley
+- ken2812221
+- Kostiantyn Stepaniuk
+- Kristaps Kaupe
+- Lawrence Nahum
+- Lenny Maiorani
+- liuyujun
+- lucash-dev
+- luciana
+- Luke Dashjr
+- marcaiaf
+- marcoagner
+- MarcoFalke
+- Martin Erlandsson
+- Marty Jones
+- Mason Simon
+- Michael Ford
+- Michael Goldstein
+- Michael Polzer
+- Mitchell Cash
+- mruddy
+- Murray Nesbitt
+- OverlordQ
+- Patrick Strateman
+- Pierre Rochard
+- Pieter Wuille
+- poiuty
+- practicalswift
+- priscoan
+- qubenix
+- riordant
+- Russell Yanofsky
+- Samuel Dobson
+- sanket1729
+- Sjors Provoost
+- Stephan Oeste
+- Steven Roose
+- Suhas Daftuar
+- TheCharlatan
+- Tim Ruffing
+- Vidar Holen
+- vim88
+- Walter
+- whythat
+- Wladimir J. van der Laan
+- Zain Iqbal Allarakhia
+
+As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/).
diff --git a/doc/release-process.md b/doc/release-process.md
index eb1f5ad222..480b09ee11 100644
--- a/doc/release-process.md
+++ b/doc/release-process.md
@@ -1,18 +1,19 @@
Release Process
====================
-Before every release candidate:
+## Branch updates
-* Update translations (ping wumpus on IRC) see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#synchronising-translations).
+### Before every release candidate
+* Update translations (ping wumpus on IRC) see [translation_process.md](https://github.com/bitcoin/bitcoin/blob/master/doc/translation_process.md#synchronising-translations).
* Update manpages, see [gen-manpages.sh](https://github.com/bitcoin/bitcoin/blob/master/contrib/devtools/README.md#gen-manpagessh).
-* Update release candidate version in `configure.ac` (`CLIENT_VERSION_RC`)
+* Update release candidate version in `configure.ac` (`CLIENT_VERSION_RC`).
-Before every minor and major release:
+### Before every major and minor release
* Update [bips.md](bips.md) to account for changes since the last release.
-* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_IS_RELEASE` to `true`) (don't forget to set `CLIENT_VERSION_RC` to `0`)
-* Write release notes (see below)
+* Update version in `configure.ac` (don't forget to set `CLIENT_VERSION_RC` to `0`).
+* Write release notes (see "Write the release notes" below).
* Update `src/chainparams.cpp` nMinimumChainWork with information from the getblockchaininfo rpc.
* Update `src/chainparams.cpp` defaultAssumeValid with information from the getblockhash rpc.
- The selected value must not be orphaned so it may be useful to set the value two blocks back from the tip.
@@ -20,13 +21,38 @@ Before every minor and major release:
- This update should be reviewed with a reindex-chainstate with assumevalid=0 to catch any defect
that causes rejection of blocks in the past history.
-Before every major release:
+### Before every major release
* Update hardcoded [seeds](/contrib/seeds/README.md), see [this pull request](https://github.com/bitcoin/bitcoin/pull/7415) for an example.
* Update [`src/chainparams.cpp`](/src/chainparams.cpp) m_assumed_blockchain_size and m_assumed_chain_state_size with the current size plus some overhead.
* Update `src/chainparams.cpp` chainTxData with statistics about the transaction count and rate. Use the output of the RPC `getchaintxstats`, see
[this pull request](https://github.com/bitcoin/bitcoin/pull/12270) for an example. Reviewers can verify the results by running `getchaintxstats <window_block_count> <window_last_block_hash>` with the `window_block_count` and `window_last_block_hash` from your output.
-* Update version of `contrib/gitian-descriptors/*.yml`: usually one'd want to do this on master after branching off the release - but be sure to at least do it before a new major release
+* On both the master branch and the new release branch:
+ - update `CLIENT_VERSION_MINOR` in [`configure.ac`](../configure.ac)
+ - update `CLIENT_VERSION_MINOR`, `PACKAGE_VERSION`, and `PACKAGE_STRING` in [`build_msvc/bitcoin_config.h`](/build_msvc/bitcoin_config.h)
+* On the new release branch in [`configure.ac`](../configure.ac) and [`build_msvc/bitcoin_config.h`](/build_msvc/bitcoin_config.h) (see [this commit](https://github.com/bitcoin/bitcoin/commit/742f7dd)):
+ - set `CLIENT_VERSION_REVISION` to `0`
+ - set `CLIENT_VERSION_IS_RELEASE` to `true`
+
+#### Before branch-off
+
+- Clear the release notes and move them to the wiki (see "Write the release notes" below).
+
+#### After branch-off (on master)
+
+- Update the version of `contrib/gitian-descriptors/*.yml`.
+
+#### After branch-off (on the major release branch)
+
+- Update the versions and the link to the release notes draft in `doc/release-notes.md`.
+
+#### Before final release
+
+- Merge the release notes from the wiki into the branch.
+- Ensure the "Needs release note" label is removed from all relevant pull requests and issues.
+
+
+## Building
### First time / New builders
@@ -40,22 +66,26 @@ Check out the source code in the following directory hierarchy.
git clone https://github.com/devrandom/gitian-builder.git
git clone https://github.com/bitcoin/bitcoin.git
-### Bitcoin maintainers/release engineers, suggestion for writing release notes
+### Write the release notes
-Write release notes. git shortlog helps a lot, for example:
+Open a draft of the release notes for collaborative editing at https://github.com/bitcoin-core/bitcoin-devwiki/wiki.
- git shortlog --no-merges v(current version, e.g. 0.7.2)..v(new version, e.g. 0.8.0)
+For the period during which the notes are being edited on the wiki, the version on the branch should be wiped and replaced with a link to the wiki which should be used for all announcements until `-final`.
+
+Write the release notes. `git shortlog` helps a lot, for example:
+
+ git shortlog --no-merges v(current version, e.g. 0.19.2)..v(new version, e.g. 0.20.0)
(or ping @wumpus on IRC, he has specific tooling to generate the list of merged pulls
-and sort them into categories based on labels)
+and sort them into categories based on labels).
Generate list of authors:
- git log --format='- %aN' v(current version, e.g. 0.16.0)..v(new version, e.g. 0.16.1) | sort -fiu
+ git log --format='- %aN' v(current version, e.g. 0.20.0)..v(new version, e.g. 0.20.1) | sort -fiu
-Tag version (or release candidate) in git
+Tag the version (or release candidate) in git:
- git tag -s v(new version, e.g. 0.8.0)
+ git tag -s v(new version, e.g. 0.20.0)
### Setup and perform Gitian builds
@@ -65,7 +95,7 @@ Setup Gitian descriptors:
pushd ./bitcoin
export SIGNER="(your Gitian key, ie bluematt, sipa, etc)"
- export VERSION=(new version, e.g. 0.8.0)
+ export VERSION=(new version, e.g. 0.20.0)
git fetch
git checkout v${VERSION}
popd
@@ -216,7 +246,6 @@ Create (and optionally verify) the signed Windows binaries:
./bin/gsign --signer "$SIGNER" --release ${VERSION}-win-signed --destination ../gitian.sigs/ ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
./bin/gverify -v -d ../gitian.sigs/ -r ${VERSION}-win-signed ../bitcoin/contrib/gitian-descriptors/gitian-win-signer.yml
mv build/out/bitcoin-*win64-setup.exe ../bitcoin-${VERSION}-win64-setup.exe
- mv build/out/bitcoin-*win32-setup.exe ../bitcoin-${VERSION}-win32-setup.exe
popd
Commit your signature for the signed macOS/Windows binaries:
@@ -224,7 +253,7 @@ Commit your signature for the signed macOS/Windows binaries:
pushd gitian.sigs
git add ${VERSION}-osx-signed/"${SIGNER}"
git add ${VERSION}-win-signed/"${SIGNER}"
- git commit -a
+ git commit -m "Add ${SIGNER} ${VERSION} signed binaries signatures"
git push # Assuming you can push to the gitian.sigs tree
popd
@@ -241,12 +270,11 @@ The list of files should be:
bitcoin-${VERSION}-aarch64-linux-gnu.tar.gz
bitcoin-${VERSION}-arm-linux-gnueabihf.tar.gz
bitcoin-${VERSION}-i686-pc-linux-gnu.tar.gz
+bitcoin-${VERSION}-riscv64-linux-gnu.tar.gz
bitcoin-${VERSION}-x86_64-linux-gnu.tar.gz
bitcoin-${VERSION}-osx64.tar.gz
bitcoin-${VERSION}-osx.dmg
bitcoin-${VERSION}.tar.gz
-bitcoin-${VERSION}-win32-setup.exe
-bitcoin-${VERSION}-win32.zip
bitcoin-${VERSION}-win64-setup.exe
bitcoin-${VERSION}-win64.zip
```
@@ -295,6 +323,9 @@ bitcoin.org (see below for bitcoin.org update instructions).
- bitcoincore.org blog post
+ - bitcoincore.org maintained versions update:
+ [table](https://github.com/bitcoin-core/bitcoincore.org/commits/master/_includes/posts/maintenance-table.md)
+
- bitcoincore.org RPC documentation update
- Update packaging repo
@@ -321,9 +352,11 @@ bitcoin.org (see below for bitcoin.org update instructions).
- This repo
- - Archive release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release)
+ - Archive the release notes for the new version to `doc/release-notes/` (branch `master` and branch of the release)
+
+ - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes
- - Create a [new GitHub release](https://github.com/bitcoin/bitcoin/releases/new) with a link to the archived release notes.
+ - Create a pinned meta-issue for testing the release candidate (see [this issue](https://github.com/bitcoin/bitcoin/issues/15555) for an example) and provide a link to it in the release announcements where useful
- Announce the release:
diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md
index dc363582cc..e960863a80 100644
--- a/doc/shared-libraries.md
+++ b/doc/shared-libraries.md
@@ -7,11 +7,11 @@ The purpose of this library is to make the verification functionality that is cr
### API
-The interface is defined in the C header `bitcoinconsensus.h` located in `src/script/bitcoinconsensus.h`.
+The interface is defined in the C header `bitcoinconsensus.h` located in `src/script/bitcoinconsensus.h`.
#### Version
-`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently at an experimental `0`)*.
+`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently `1`)*.
#### Script Validation
diff --git a/doc/tor.md b/doc/tor.md
index c46b7e9f60..cfb7f16666 100644
--- a/doc/tor.md
+++ b/doc/tor.md
@@ -16,7 +16,7 @@ outgoing connections, but more is possible.
-onion=ip:port Set the proxy server to use for Tor hidden services. You do not
need to set this if it's the same as -proxy. You can use -noonion
- to explicitly disable access to hidden service.
+ to explicitly disable access to hidden services.
-listen When using -proxy, listening is disabled by default. If you want
to run a hidden service (see next section), you'll need to enable
@@ -27,6 +27,11 @@ outgoing connections, but more is possible.
-seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with
other P2P nodes.
+ -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.
+
In a typical situation, this suffices to run behind a Tor proxy:
./bitcoind -proxy=127.0.0.1:9050
diff --git a/doc/travis-ci.md b/doc/travis-ci.md
deleted file mode 100644
index 38085cec35..0000000000
--- a/doc/travis-ci.md
+++ /dev/null
@@ -1,42 +0,0 @@
-Travis CI
-=========
-
-Support for using travis-ci has been added in order to automate pull-testing.
-See [travis-ci.org](https://travis-ci.org/) for more info
-
-This procedure is different than the pull-tester that came before it in a few
-ways.
-
-There is nothing to administer. This is a major feature as it means
-that builds have no local state. Because there is no ability to login to the
-builders to install packages (tools, dependencies, etc), the entire build
-procedure must instead be controlled by a declarative script `.travis.yml`.
-This script declares each build configuration, creates virtual machines as
-necessary, builds, then discards the virtual machines.
-
-A build matrix is constructed to test a wide range of configurations, rather
-than a single pass/fail. This helps to catch build failures and logic errors
-that present on platforms other than the ones the author has tested. This
-matrix is defined in the build script and can be changed at any time.
-
-All builders use the dependency-generator in the [depends dir](/depends), rather than
-using apt-get to install build dependencies. This guarantees that the tester
-is using the same versions as Gitian, so the build results are nearly identical
-to what would be found in a final release. However, this also means that builds
-will fail if new dependencies are introduced without being added to the
-dependency generator.
-
-In order to avoid rebuilding all dependencies for each build, the binaries are
-cached and re-used when possible. Changes in the dependency-generator will
-trigger cache-invalidation and rebuilds as necessary.
-
-These caches can be manually removed if necessary. This is one of the very few
-manual operations that is possible with Travis, and it can be done by the
-Bitcoin Core committer via the Travis web interface.
-
-In some cases, secure strings may be needed for hiding sensitive info such as
-private keys or URLs. The travis client may be used to create these strings:
-http://docs.travis-ci.com/user/encryption-keys/
-
-For the details of the build descriptor, see the official docs:
-http://docs.travis-ci.com/user/build-configuration/
diff --git a/share/setup.nsi.in b/share/setup.nsi.in
index 046deed9ea..acf9e86667 100644
--- a/share/setup.nsi.in
+++ b/share/setup.nsi.in
@@ -5,7 +5,6 @@ SetCompressor /SOLID lzma
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
-!define VERSION @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@
!define COMPANY "@PACKAGE_NAME@ project"
!define URL @PACKAGE_URL@
@@ -49,7 +48,7 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English
# Installer attributes
-OutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-${VERSION}-win@WINDOWS_BITS@-setup.exe
+OutFile @abs_top_srcdir@/@PACKAGE_TARNAME@-@PACKAGE_VERSION@-win@WINDOWS_BITS@-setup.exe
!if "@WINDOWS_BITS@" == "64"
InstallDir $PROGRAMFILES64\Bitcoin
!else
@@ -59,12 +58,12 @@ CRCCheck on
XPStyle on
BrandingText " "
ShowInstDetails show
-VIProductVersion ${VERSION}.@CLIENT_VERSION_BUILD@
+VIProductVersion @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@.@CLIENT_VERSION_BUILD@
VIAddVersionKey ProductName "@PACKAGE_NAME@"
-VIAddVersionKey ProductVersion "${VERSION}"
+VIAddVersionKey ProductVersion "@PACKAGE_VERSION@"
VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}"
-VIAddVersionKey FileVersion "${VERSION}"
+VIAddVersionKey FileVersion "@PACKAGE_VERSION@"
VIAddVersionKey FileDescription ""
VIAddVersionKey LegalCopyright ""
InstallDirRegKey HKCU "${REGKEY}" Path
@@ -99,7 +98,7 @@ Section -post SEC0001
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name).lnk" $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_END
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)"
- WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}"
+ WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "@PACKAGE_VERSION@"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe
diff --git a/src/Makefile.am b/src/Makefile.am
index 14db963253..39e8d3d689 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -113,7 +113,6 @@ BITCOIN_CORE_H = \
chainparams.h \
chainparamsbase.h \
chainparamsseeds.h \
- checkpoints.h \
checkqueue.h \
clientversion.h \
coins.h \
@@ -124,6 +123,7 @@ BITCOIN_CORE_H = \
compat/sanity.h \
compressor.h \
consensus/consensus.h \
+ consensus/tx_check.h \
consensus/tx_verify.h \
core_io.h \
core_memusage.h \
@@ -133,6 +133,7 @@ BITCOIN_CORE_H = \
httprpc.h \
httpserver.h \
index/base.h \
+ index/blockfilterindex.h \
index/txindex.h \
indirectmap.h \
init.h \
@@ -154,6 +155,8 @@ BITCOIN_CORE_H = \
netaddress.h \
netbase.h \
netmessagemaker.h \
+ node/coin.h \
+ node/psbt.h \
node/transaction.h \
noui.h \
optional.h \
@@ -162,6 +165,7 @@ BITCOIN_CORE_H = \
policy/fees.h \
policy/policy.h \
policy/rbf.h \
+ policy/settings.h \
pow.h \
protocol.h \
psbt.h \
@@ -170,15 +174,13 @@ BITCOIN_CORE_H = \
reverselock.h \
rpc/blockchain.h \
rpc/client.h \
- rpc/mining.h \
rpc/protocol.h \
rpc/server.h \
- rpc/rawtransaction.h \
+ rpc/rawtransaction_util.h \
rpc/register.h \
rpc/util.h \
scheduler.h \
script/descriptor.h \
- script/ismine.h \
script/sigcache.h \
script/sign.h \
script/standard.h \
@@ -200,10 +202,16 @@ BITCOIN_CORE_H = \
undo.h \
util/bip32.h \
util/bytevectorhash.h \
+ util/error.h \
+ util/fees.h \
util/system.h \
util/memory.h \
util/moneystr.h \
+ util/rbf.h \
+ util/threadnames.h \
util/time.h \
+ util/url.h \
+ util/validation.h \
validation.h \
validationinterface.h \
versionbits.h \
@@ -214,6 +222,8 @@ BITCOIN_CORE_H = \
wallet/db.h \
wallet/feebumper.h \
wallet/fees.h \
+ wallet/ismine.h \
+ wallet/load.h \
wallet/psbtwallet.h \
wallet/rpcwallet.h \
wallet/wallet.h \
@@ -236,38 +246,39 @@ obj/build.h: FORCE
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: shared between bitcoind and bitcoin-qt
+# Contains code accessing mempool and chain state that is meant to be separated
+# from wallet and gui code (see node/README.md). Shared code should go in
+# libbitcoin_common or libbitcoin_util libraries, instead.
libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_server_a_SOURCES = \
addrdb.cpp \
addrman.cpp \
banman.cpp \
- bloom.cpp \
blockencodings.cpp \
blockfilter.cpp \
chain.cpp \
- checkpoints.cpp \
consensus/tx_verify.cpp \
flatfile.cpp \
httprpc.cpp \
httpserver.cpp \
index/base.cpp \
+ index/blockfilterindex.cpp \
index/txindex.cpp \
interfaces/chain.cpp \
- interfaces/handler.cpp \
interfaces/node.cpp \
init.cpp \
dbwrapper.cpp \
- merkleblock.cpp \
miner.cpp \
net.cpp \
net_processing.cpp \
+ node/coin.cpp \
+ node/psbt.cpp \
node/transaction.cpp \
noui.cpp \
- outputtype.cpp \
policy/fees.cpp \
- policy/policy.cpp \
policy/rbf.cpp \
+ policy/settings.cpp \
pow.cpp \
rest.cpp \
rpc/blockchain.cpp \
@@ -276,7 +287,6 @@ libbitcoin_server_a_SOURCES = \
rpc/net.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
- rpc/util.cpp \
script/sigcache.cpp \
shutdown.cpp \
timedata.cpp \
@@ -289,6 +299,9 @@ libbitcoin_server_a_SOURCES = \
versionbits.cpp \
$(BITCOIN_CORE_H)
+if ENABLE_WALLET
+libbitcoin_server_a_SOURCES += wallet/init.cpp
+endif
if !ENABLE_WALLET
libbitcoin_server_a_SOURCES += dummywallet.cpp
endif
@@ -315,7 +328,8 @@ libbitcoin_wallet_a_SOURCES = \
wallet/db.cpp \
wallet/feebumper.cpp \
wallet/fees.cpp \
- wallet/init.cpp \
+ wallet/ismine.cpp \
+ wallet/load.cpp \
wallet/psbtwallet.cpp \
wallet/rpcdump.cpp \
wallet/rpcwallet.cpp \
@@ -340,10 +354,14 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/chacha20.h \
crypto/chacha20.cpp \
crypto/common.h \
+ crypto/hkdf_sha256_32.cpp \
+ crypto/hkdf_sha256_32.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
crypto/hmac_sha512.cpp \
crypto/hmac_sha512.h \
+ crypto/poly1305.h \
+ crypto/poly1305.cpp \
crypto/ripemd160.cpp \
crypto/ripemd160.h \
crypto/sha1.cpp \
@@ -387,6 +405,7 @@ libbitcoin_consensus_a_SOURCES = \
consensus/merkle.cpp \
consensus/merkle.h \
consensus/params.h \
+ consensus/tx_check.cpp \
consensus/validation.h \
hash.cpp \
hash.h \
@@ -419,6 +438,7 @@ libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \
base58.cpp \
bech32.cpp \
+ bloom.cpp \
chainparams.cpp \
coins.cpp \
compressor.cpp \
@@ -427,14 +447,18 @@ libbitcoin_common_a_SOURCES = \
key.cpp \
key_io.cpp \
keystore.cpp \
+ merkleblock.cpp \
netaddress.cpp \
netbase.cpp \
+ outputtype.cpp \
policy/feerate.cpp \
- psbt.cpp \
+ policy/policy.cpp \
protocol.cpp \
+ psbt.cpp \
+ rpc/rawtransaction_util.cpp \
+ rpc/util.cpp \
scheduler.cpp \
script/descriptor.cpp \
- script/ismine.cpp \
script/sign.cpp \
script/standard.cpp \
versionbitsinfo.cpp \
@@ -454,6 +478,7 @@ libbitcoin_util_a_SOURCES = \
compat/glibcxx_sanity.cpp \
compat/strnlen.cpp \
fs.cpp \
+ interfaces/handler.cpp \
logging.cpp \
random.cpp \
rpc/protocol.cpp \
@@ -462,10 +487,16 @@ libbitcoin_util_a_SOURCES = \
threadinterrupt.cpp \
util/bip32.cpp \
util/bytevectorhash.cpp \
+ util/error.cpp \
+ util/fees.cpp \
util/system.cpp \
util/moneystr.cpp \
+ util/rbf.cpp \
+ util/threadnames.cpp \
util/strencodings.cpp \
util/time.cpp \
+ util/url.cpp \
+ util/validation.cpp \
$(BITCOIN_CORE_H)
if GLIBC_BACK_COMPAT
@@ -493,6 +524,8 @@ if TARGET_WINDOWS
bitcoind_SOURCES += bitcoind-res.rc
endif
+# Libraries below may be listed more than once to resolve circular dependencies (see
+# https://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking#circular-dependency)
bitcoind_LDADD = \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_WALLET) \
@@ -563,7 +596,6 @@ endif
bitcoin_wallet_LDADD = \
$(LIBBITCOIN_WALLET_TOOL) \
$(LIBBITCOIN_WALLET) \
- $(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_CONSENSUS) \
$(LIBBITCOIN_UTIL) \
@@ -642,13 +674,13 @@ clean-local:
check-symbols: $(bin_PROGRAMS)
if GLIBC_BACK_COMPAT
@echo "Checking glibc back compat..."
- $(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py < $(bin_PROGRAMS)
+ $(AM_V_at) READELF=$(READELF) 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) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
+ $(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(PYTHON) $(top_srcdir)/contrib/devtools/security-check.py < $(bin_PROGRAMS)
endif
if ENABLE_BIP70
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 77fb416b9c..c6162b5caa 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -21,22 +21,31 @@ bench_bench_bitcoin_SOURCES = \
bench/duplicate_inputs.cpp \
bench/examples.cpp \
bench/rollingbloom.cpp \
+ bench/chacha20.cpp \
bench/crypto_hash.cpp \
bench/ccoins_caching.cpp \
bench/gcs_filter.cpp \
bench/merkle_root.cpp \
bench/mempool_eviction.cpp \
+ bench/rpc_mempool.cpp \
+ bench/util_time.cpp \
bench/verify_script.cpp \
bench/base58.cpp \
bench/bech32.cpp \
bench/lockedpool.cpp \
- bench/prevector.cpp
+ bench/poly1305.cpp \
+ bench/prevector.cpp \
+ test/setup_common.h \
+ test/setup_common.cpp \
+ test/util.h \
+ test/util.cpp
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
bench_bench_bitcoin_LDADD = \
+ $(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_WALLET) \
$(LIBBITCOIN_SERVER) \
$(LIBBITCOIN_COMMON) \
@@ -47,7 +56,9 @@ bench_bench_bitcoin_LDADD = \
$(LIBLEVELDB_SSE42) \
$(LIBMEMENV) \
$(LIBSECP256K1) \
- $(LIBUNIVALUE)
+ $(LIBUNIVALUE) \
+ $(EVENT_PTHREADS_LIBS) \
+ $(EVENT_LIBS)
if ENABLE_ZMQ
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
@@ -55,6 +66,7 @@ endif
if ENABLE_WALLET
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) $(CRYPTO_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS)
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index ba6523d7c2..c4c08487f3 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -140,6 +140,7 @@ QT_MOC_CPP = \
qt/moc_overviewpage.cpp \
qt/moc_peertablemodel.cpp \
qt/moc_paymentserver.cpp \
+ qt/moc_qrimagewidget.cpp \
qt/moc_qvalidatedlineedit.cpp \
qt/moc_qvaluecombobox.cpp \
qt/moc_receivecoinsdialog.cpp \
@@ -220,6 +221,7 @@ BITCOIN_QT_H = \
qt/paymentserver.h \
qt/peertablemodel.h \
qt/platformstyle.h \
+ qt/qrimagewidget.h \
qt/qvalidatedlineedit.h \
qt/qvaluecombobox.h \
qt/receivecoinsdialog.h \
@@ -340,6 +342,7 @@ BITCOIN_QT_WALLET_CPP = \
qt/openuridialog.cpp \
qt/overviewpage.cpp \
qt/paymentserver.cpp \
+ qt/qrimagewidget.cpp \
qt/receivecoinsdialog.cpp \
qt/receiverequestdialog.cpp \
qt/recentrequeststablemodel.cpp \
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index 61977b50cd..4acfff809e 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -33,10 +33,10 @@ TEST_QT_H = \
qt/test/wallettests.h
TEST_BITCOIN_CPP = \
- test/test_bitcoin.cpp
+ test/setup_common.cpp
TEST_BITCOIN_H = \
- test/test_bitcoin.h
+ test/setup_common.h
qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 09fef5a1dd..d3fe138133 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -51,14 +51,32 @@ RAW_TEST_FILES =
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
BITCOIN_TEST_SUITE = \
- test/test_bitcoin_main.cpp \
- test/test_bitcoin.h \
- test/test_bitcoin.cpp
+ test/main.cpp \
+ test/setup_common.h \
+ test/setup_common.cpp
FUZZ_SUITE = \
+ test/setup_common.h \
+ test/setup_common.cpp \
test/fuzz/fuzz.cpp \
test/fuzz/fuzz.h
+FUZZ_SUITE_LD_COMMON = \
+ $(LIBBITCOIN_SERVER) \
+ $(LIBBITCOIN_COMMON) \
+ $(LIBBITCOIN_UTIL) \
+ $(LIBBITCOIN_CONSENSUS) \
+ $(LIBBITCOIN_CRYPTO) \
+ $(LIBUNIVALUE) \
+ $(LIBLEVELDB) \
+ $(LIBLEVELDB_SSE42) \
+ $(BOOST_LIBS) \
+ $(LIBMEMENV) \
+ $(LIBSECP256K1) \
+ $(EVENT_LIBS) \
+ $(CRYPTO_LIBS) \
+ $(EVENT_PTHREADS_LIBS)
+
# test_bitcoin binary #
BITCOIN_TESTS =\
test/arith_uint256_tests.cpp \
@@ -74,10 +92,12 @@ BITCOIN_TESTS =\
test/blockchain_tests.cpp \
test/blockencodings_tests.cpp \
test/blockfilter_tests.cpp \
+ test/blockfilter_index_tests.cpp \
test/bloom_tests.cpp \
test/bswap_tests.cpp \
test/checkqueue_tests.cpp \
test/coins_tests.cpp \
+ test/compilerbug_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/cuckoocache_tests.cpp \
@@ -91,7 +111,7 @@ BITCOIN_TESTS =\
test/key_tests.cpp \
test/limitedmap_tests.cpp \
test/dbwrapper_tests.cpp \
- test/main_tests.cpp \
+ test/validation_tests.cpp \
test/mempool_tests.cpp \
test/merkle_tests.cpp \
test/merkleblock_tests.cpp \
@@ -119,6 +139,7 @@ BITCOIN_TESTS =\
test/skiplist_tests.cpp \
test/streams_tests.cpp \
test/sync_tests.cpp \
+ test/util_threadnames_tests.cpp \
test/timedata_tests.cpp \
test/torcontrol_tests.cpp \
test/transaction_tests.cpp \
@@ -146,7 +167,8 @@ BITCOIN_TESTS += \
wallet/test/wallet_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
wallet/test/coinselector_tests.cpp \
- wallet/test/init_tests.cpp
+ wallet/test/init_tests.cpp \
+ wallet/test/ismine_tests.cpp
BITCOIN_TEST_SUITE += \
wallet/test/wallet_test_fixture.cpp \
@@ -170,7 +192,7 @@ test_test_bitcoin_LDADD += $(BDB_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(RAPIDC
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
if ENABLE_ZMQ
-test_test_bitcoin_LDADD += $(ZMQ_LIBS)
+test_test_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_FUZZ
@@ -178,358 +200,127 @@ test_fuzz_block_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_block_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCK_DESERIALIZE=1
test_fuzz_block_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_block_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_block_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_block_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_block_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_transaction_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_transaction_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTRANSACTION_DESERIALIZE=1
test_fuzz_transaction_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_transaction_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_transaction_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_transaction_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_transaction_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_blocklocator_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_blocklocator_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKLOCATOR_DESERIALIZE=1
test_fuzz_blocklocator_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blocklocator_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_blocklocator_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_blocklocator_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_blocklocator_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_blockmerkleroot_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_blockmerkleroot_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKMERKLEROOT=1
test_fuzz_blockmerkleroot_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockmerkleroot_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_blockmerkleroot_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_blockmerkleroot_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_blockmerkleroot_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_addrman_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_addrman_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRMAN_DESERIALIZE=1
test_fuzz_addrman_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_addrman_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_addrman_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_addrman_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_addrman_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_blockheader_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_blockheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKHEADER_DESERIALIZE=1
test_fuzz_blockheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_blockheader_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_blockheader_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_blockheader_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_banentry_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_banentry_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBANENTRY_DESERIALIZE=1
test_fuzz_banentry_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_banentry_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_banentry_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_banentry_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_banentry_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_txundo_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_txundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXUNDO_DESERIALIZE=1
test_fuzz_txundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_txundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_txundo_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_txundo_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_txundo_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_blockundo_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_blockundo_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKUNDO_DESERIALIZE=1
test_fuzz_blockundo_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blockundo_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_blockundo_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_blockundo_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_blockundo_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_coins_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_coins_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DCOINS_DESERIALIZE=1
test_fuzz_coins_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_coins_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_coins_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_coins_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_coins_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_netaddr_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_netaddr_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DNETADDR_DESERIALIZE=1
test_fuzz_netaddr_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_netaddr_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_netaddr_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_netaddr_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_netaddr_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_script_flags_SOURCES = $(FUZZ_SUITE) test/fuzz/script_flags.cpp
test_fuzz_script_flags_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_script_flags_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_script_flags_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_script_flags_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_script_flags_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_script_flags_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_service_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_service_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DSERVICE_DESERIALIZE=1
test_fuzz_service_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_service_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_service_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_service_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_service_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_messageheader_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_messageheader_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DMESSAGEHEADER_DESERIALIZE=1
test_fuzz_messageheader_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_messageheader_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_messageheader_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_messageheader_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_messageheader_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_address_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_address_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DADDRESS_DESERIALIZE=1
test_fuzz_address_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_address_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_address_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_address_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_address_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_inv_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_inv_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DINV_DESERIALIZE=1
test_fuzz_inv_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_inv_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_inv_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_inv_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_inv_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_bloomfilter_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_bloomfilter_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOOMFILTER_DESERIALIZE=1
test_fuzz_bloomfilter_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_bloomfilter_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_bloomfilter_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_bloomfilter_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_bloomfilter_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_diskblockindex_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_diskblockindex_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DDISKBLOCKINDEX_DESERIALIZE=1
test_fuzz_diskblockindex_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_diskblockindex_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_diskblockindex_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_diskblockindex_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_diskblockindex_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_txoutcompressor_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_txoutcompressor_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DTXOUTCOMPRESSOR_DESERIALIZE=1
test_fuzz_txoutcompressor_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_txoutcompressor_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_txoutcompressor_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_txoutcompressor_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_txoutcompressor_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_blocktransactions_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_blocktransactions_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONS_DESERIALIZE=1
test_fuzz_blocktransactions_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blocktransactions_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_blocktransactions_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_blocktransactions_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_blocktransactions_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_blocktransactionsrequest_deserialize_SOURCES = $(FUZZ_SUITE) test/fuzz/deserialize.cpp
test_fuzz_blocktransactionsrequest_deserialize_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -DBLOCKTRANSACTIONSREQUEST_DESERIALIZE=1
test_fuzz_blocktransactionsrequest_deserialize_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_blocktransactionsrequest_deserialize_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
-test_fuzz_blocktransactionsrequest_deserialize_LDADD = \
- $(LIBUNIVALUE) \
- $(LIBBITCOIN_SERVER) \
- $(LIBBITCOIN_COMMON) \
- $(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CONSENSUS) \
- $(LIBBITCOIN_CRYPTO) \
- $(LIBBITCOIN_CRYPTO_SSE41) \
- $(LIBBITCOIN_CRYPTO_AVX2) \
- $(LIBBITCOIN_CRYPTO_SHANI) \
- $(LIBSECP256K1)
-test_fuzz_blocktransactionsrequest_deserialize_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS)
+test_fuzz_blocktransactionsrequest_deserialize_LDADD = $(FUZZ_SUITE_LD_COMMON)
endif # ENABLE_FUZZ
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/addrdb.cpp b/src/addrdb.cpp
index c6083f5554..db936486b6 100644
--- a/src/addrdb.cpp
+++ b/src/addrdb.cpp
@@ -44,18 +44,30 @@ bool SerializeFileDB(const std::string& prefix, const fs::path& path, const Data
fs::path pathTmp = GetDataDir() / tmpfn;
FILE *file = fsbridge::fopen(pathTmp, "wb");
CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
- if (fileout.IsNull())
+ if (fileout.IsNull()) {
+ fileout.fclose();
+ remove(pathTmp);
return error("%s: Failed to open file %s", __func__, pathTmp.string());
+ }
// Serialize
- if (!SerializeDB(fileout, data)) return false;
- if (!FileCommit(fileout.Get()))
+ if (!SerializeDB(fileout, data)) {
+ fileout.fclose();
+ remove(pathTmp);
+ return false;
+ }
+ if (!FileCommit(fileout.Get())) {
+ fileout.fclose();
+ remove(pathTmp);
return error("%s: Failed to flush file %s", __func__, pathTmp.string());
+ }
fileout.fclose();
// replace existing file, if any, with new file
- if (!RenameOver(pathTmp, path))
+ if (!RenameOver(pathTmp, path)) {
+ remove(pathTmp);
return error("%s: Rename-into-place failed", __func__);
+ }
return true;
}
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 06c342ba73..32676f8fa5 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -7,7 +7,6 @@
#include <hash.h>
#include <serialize.h>
-#include <streams.h>
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
@@ -239,7 +238,9 @@ void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime
// Will moving this address into tried evict another entry?
if (test_before_evict && (vvTried[tried_bucket][tried_bucket_pos] != -1)) {
- LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table, moving %s to m_tried_collisions=%d\n", addr.ToString(), m_tried_collisions.size());
+ // Output the entry we'd be colliding with, for debugging purposes
+ auto colliding_entry = mapInfo.find(vvTried[tried_bucket][tried_bucket_pos]);
+ LogPrint(BCLog::ADDRMAN, "Collision inserting element into tried table (%s), moving %s to m_tried_collisions=%d\n", colliding_entry != mapInfo.end() ? colliding_entry->second.ToString() : "", addr.ToString(), m_tried_collisions.size());
if (m_tried_collisions.size() < ADDRMAN_SET_TRIED_COLLISION_SIZE) {
m_tried_collisions.insert(nId);
}
@@ -561,12 +562,19 @@ void CAddrMan::ResolveCollisions_()
// Give address at least 60 seconds to successfully connect
if (GetAdjustedTime() - info_old.nLastTry > 60) {
- LogPrint(BCLog::ADDRMAN, "Swapping %s for %s in tried table\n", info_new.ToString(), info_old.ToString());
+ LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
// Replaces an existing address already in the tried table with the new address
Good_(info_new, false, GetAdjustedTime());
erase_collision = true;
}
+ } else if (GetAdjustedTime() - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
+ // If the collision hasn't resolved in some reasonable amount of time,
+ // just evict the old entry -- we must not be able to
+ // connect to it for some reason.
+ LogPrint(BCLog::ADDRMAN, "Unable to test; replacing %s with %s in tried table anyway\n", info_old.ToString(), info_new.ToString());
+ Good_(info_new, false, GetAdjustedTime());
+ erase_collision = true;
}
} else { // Collision is not actually a collision anymore
Good_(info_new, false, GetAdjustedTime());
diff --git a/src/addrman.h b/src/addrman.h
index 003bd059f8..e54184ce35 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -166,6 +166,9 @@ public:
//! the maximum number of tried addr collisions to store
#define ADDRMAN_SET_TRIED_COLLISION_SIZE 10
+//! the maximum time we'll spend trying to resolve a tried table collision, in seconds
+static const int64_t ADDRMAN_TEST_WINDOW = 40*60; // 40 minutes
+
/**
* Stochastical (IP) address manager
*/
diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp
index aa66d13102..be145a0e63 100644
--- a/src/arith_uint256.cpp
+++ b/src/arith_uint256.cpp
@@ -6,7 +6,6 @@
#include <arith_uint256.h>
#include <uint256.h>
-#include <util/strencodings.h>
#include <crypto/common.h>
#include <stdio.h>
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index e7702ec461..0f4b52cf79 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
-#include <validation.h>
#include <base58.h>
#include <array>
diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp
index 3c4b453a23..80f13eeb3b 100644
--- a/src/bench/bech32.cpp
+++ b/src/bench/bech32.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
-#include <validation.h>
#include <bech32.h>
#include <util/strencodings.h>
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 966b99f6c8..f2b520e893 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -1,15 +1,19 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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 <bench/bench.h>
+#include <chainparams.h>
+#include <test/setup_common.h>
+#include <validation.h>
+
+#include <algorithm>
#include <assert.h>
-#include <iostream>
#include <iomanip>
-#include <algorithm>
-#include <regex>
+#include <iostream>
#include <numeric>
+#include <regex>
void benchmark::ConsolePrinter::header()
{
@@ -108,6 +112,14 @@ void benchmark::BenchRunner::RunAll(Printer& printer, uint64_t num_evals, double
printer.header();
for (const auto& p : benchmarks()) {
+ TestingSetup test{CBaseChainParams::REGTEST};
+ {
+ LOCK(cs_main);
+ assert(::ChainActive().Height() == 0);
+ const bool witness_enabled{IsWitnessEnabled(::ChainActive().Tip(), Params().GetConsensus())};
+ assert(witness_enabled);
+ }
+
if (!std::regex_match(p.first, baseMatch, reFilter)) {
continue;
}
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index d67b2c5bc7..8eea96d930 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -1,19 +1,14 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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 <bench/bench.h>
-#include <crypto/sha256.h>
-#include <key.h>
-#include <util/system.h>
#include <util/strencodings.h>
-#include <validation.h>
+#include <util/system.h>
#include <memory>
-const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
-
static const int64_t DEFAULT_BENCH_EVALUATIONS = 5;
static const char* DEFAULT_BENCH_FILTER = ".*";
static const char* DEFAULT_BENCH_SCALING = "1.0";
@@ -36,20 +31,12 @@ static void SetupBenchArgs()
gArgs.AddArg("-plot-height=<x>", strprintf("Plot height in pixel (default: %u)", DEFAULT_PLOT_HEIGHT), false, OptionsCategory::OPTIONS);
}
-static fs::path SetDataDir()
-{
- fs::path ret = fs::temp_directory_path() / "bench_bitcoin" / fs::unique_path();
- fs::create_directories(ret);
- gArgs.ForceSetArg("-datadir", ret.string());
- return ret;
-}
-
int main(int argc, char** argv)
{
SetupBenchArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return EXIT_FAILURE;
}
@@ -59,13 +46,6 @@ int main(int argc, char** argv)
return EXIT_SUCCESS;
}
- // Set the datadir after parsing the bench options
- const fs::path bench_datadir{SetDataDir()};
-
- SHA256AutoDetect();
- ECC_Start();
- SetupEnvironment();
-
int64_t evaluations = gArgs.GetArg("-evals", DEFAULT_BENCH_EVALUATIONS);
std::string regex_filter = gArgs.GetArg("-filter", DEFAULT_BENCH_FILTER);
std::string scaling_str = gArgs.GetArg("-scaling", DEFAULT_BENCH_SCALING);
@@ -73,7 +53,7 @@ int main(int argc, char** argv)
double scaling_factor;
if (!ParseDouble(scaling_str, &scaling_factor)) {
- fprintf(stderr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str());
+ tfm::format(std::cerr, "Error parsing scaling factor as double: %s\n", scaling_str.c_str());
return EXIT_FAILURE;
}
@@ -88,9 +68,5 @@ int main(int argc, char** argv)
benchmark::BenchRunner::RunAll(*printer, evaluations, scaling_factor, regex_filter, is_list_only);
- fs::remove_all(bench_datadir);
-
- ECC_Stop();
-
return EXIT_SUCCESS;
}
diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index cd4543c012..fb33c09ab2 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -1,58 +1,18 @@
-// 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.
#include <bench/bench.h>
-#include <chainparams.h>
-#include <coins.h>
-#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
-#include <miner.h>
-#include <policy/policy.h>
-#include <pow.h>
-#include <scheduler.h>
-#include <txdb.h>
+#include <test/util.h>
#include <txmempool.h>
-#include <util/time.h>
#include <validation.h>
-#include <validationinterface.h>
-#include <boost/thread.hpp>
#include <list>
#include <vector>
-static std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey)
-{
- auto block = std::make_shared<CBlock>(
- BlockAssembler{Params()}
- .CreateNewBlock(coinbase_scriptPubKey)
- ->block);
-
- block->nTime = ::chainActive.Tip()->GetMedianTimePast() + 1;
- block->hashMerkleRoot = BlockMerkleRoot(*block);
-
- return block;
-}
-
-
-static CTxIn MineBlock(const CScript& coinbase_scriptPubKey)
-{
- auto block = PrepareBlock(coinbase_scriptPubKey);
-
- while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) {
- ++block->nNonce;
- assert(block->nNonce);
- }
-
- bool processed{ProcessNewBlock(Params(), block, true, nullptr)};
- assert(processed);
-
- return CTxIn{block->vtx[0]->GetHash(), 0};
-}
-
-
static void AssembleBlock(benchmark::State& state)
{
const std::vector<unsigned char> op_true{OP_TRUE};
@@ -64,32 +24,6 @@ static void AssembleBlock(benchmark::State& state)
const CScript SCRIPT_PUB{CScript(OP_0) << std::vector<unsigned char>{witness_program.begin(), witness_program.end()}};
- // Switch to regtest so we can mine faster
- // Also segwit is active, so we can include witness transactions
- SelectParams(CBaseChainParams::REGTEST);
-
- InitScriptExecutionCache();
-
- boost::thread_group thread_group;
- CScheduler scheduler;
- {
- LOCK(cs_main);
- ::pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
- ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
- }
- {
- const CChainParams& chainparams = Params();
- thread_group.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
- GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
- LoadGenesisBlock(chainparams);
- CValidationState state;
- ActivateBestChain(state, chainparams);
- assert(::chainActive.Tip() != nullptr);
- const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), chainparams.GetConsensus())};
- assert(witness_enabled);
- }
-
// Collect some loose transactions that spend the coinbases of our mined blocks
constexpr size_t NUM_BLOCKS{200};
std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY + 1> txs;
@@ -114,11 +48,6 @@ static void AssembleBlock(benchmark::State& state)
while (state.KeepRunning()) {
PrepareBlock(SCRIPT_PUB);
}
-
- thread_group.interrupt_all();
- thread_group.join_all();
- GetMainSignals().FlushBackgroundCallbacks();
- GetMainSignals().UnregisterBackgroundSignalScheduler();
}
BENCHMARK(AssembleBlock, 700);
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
index 9cfd5d23ef..1041a22303 100644
--- a/src/bench/ccoins_caching.cpp
+++ b/src/bench/ccoins_caching.cpp
@@ -39,9 +39,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
dummyTransactions[1].vout.resize(2);
dummyTransactions[1].vout[0].nValue = 21 * COIN;
- dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
+ dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey()));
dummyTransactions[1].vout[1].nValue = 22 * COIN;
- dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
+ dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey()));
AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0);
return dummyTransactions;
diff --git a/src/bench/chacha20.cpp b/src/bench/chacha20.cpp
new file mode 100644
index 0000000000..030067aca5
--- /dev/null
+++ b/src/bench/chacha20.cpp
@@ -0,0 +1,45 @@
+// 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 <iostream>
+
+#include <bench/bench.h>
+#include <crypto/chacha20.h>
+
+/* Number of bytes to process per iteration */
+static const uint64_t BUFFER_SIZE_TINY = 64;
+static const uint64_t BUFFER_SIZE_SMALL = 256;
+static const uint64_t BUFFER_SIZE_LARGE = 1024*1024;
+
+static void CHACHA20(benchmark::State& state, size_t buffersize)
+{
+ std::vector<uint8_t> key(32,0);
+ ChaCha20 ctx(key.data(), key.size());
+ ctx.SetIV(0);
+ ctx.Seek(0);
+ std::vector<uint8_t> in(buffersize,0);
+ std::vector<uint8_t> out(buffersize,0);
+ while (state.KeepRunning()) {
+ ctx.Crypt(in.data(), out.data(), in.size());
+ }
+}
+
+static void CHACHA20_64BYTES(benchmark::State& state)
+{
+ CHACHA20(state, BUFFER_SIZE_TINY);
+}
+
+static void CHACHA20_256BYTES(benchmark::State& state)
+{
+ CHACHA20(state, BUFFER_SIZE_SMALL);
+}
+
+static void CHACHA20_1MB(benchmark::State& state)
+{
+ CHACHA20(state, BUFFER_SIZE_LARGE);
+}
+
+BENCHMARK(CHACHA20_64BYTES, 500000);
+BENCHMARK(CHACHA20_256BYTES, 250000);
+BENCHMARK(CHACHA20_1MB, 340);
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
index 6ab542067a..000a0259bb 100644
--- a/src/bench/checkqueue.cpp
+++ b/src/bench/checkqueue.cpp
@@ -4,7 +4,6 @@
#include <bench/bench.h>
#include <util/system.h>
-#include <validation.h>
#include <checkqueue.h>
#include <prevector.h>
#include <vector>
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index 74641191a1..f2ab03e20e 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -29,7 +29,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<st
static void CoinSelection(benchmark::State& state)
{
auto chain = interfaces::MakeChain();
- const CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ const CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
std::vector<std::unique_ptr<CWalletTx>> wtxs;
LOCK(wallet.cs_wallet);
@@ -61,7 +61,7 @@ static void CoinSelection(benchmark::State& state)
typedef std::set<CInputCoin> CoinSet;
static auto testChain = interfaces::MakeChain();
-static const CWallet testWallet(*testChain, WalletLocation(), WalletDatabase::CreateDummy());
+static const CWallet testWallet(testChain.get(), WalletLocation(), WalletDatabase::CreateDummy());
std::vector<std::unique_ptr<CWalletTx>> wtxn;
// Copied from src/wallet/test/coinselector_tests.cpp
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index dc0b054420..fb2bab9dee 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -5,11 +5,9 @@
#include <iostream>
#include <bench/bench.h>
-#include <bloom.h>
#include <hash.h>
#include <random.h>
#include <uint256.h>
-#include <util/time.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp
index 1f6840d813..2440341287 100644
--- a/src/bench/duplicate_inputs.cpp
+++ b/src/bench/duplicate_inputs.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.
@@ -7,17 +7,9 @@
#include <coins.h>
#include <consensus/merkle.h>
#include <consensus/validation.h>
-#include <miner.h>
-#include <policy/policy.h>
#include <pow.h>
-#include <scheduler.h>
-#include <txdb.h>
#include <txmempool.h>
-#include <util/time.h>
#include <validation.h>
-#include <validationinterface.h>
-
-#include <boost/thread.hpp>
#include <list>
#include <vector>
@@ -27,37 +19,14 @@ static void DuplicateInputs(benchmark::State& state)
{
const CScript SCRIPT_PUB{CScript(OP_TRUE)};
- // Switch to regtest so we can mine faster
- // Also segwit is active, so we can include witness transactions
- SelectParams(CBaseChainParams::REGTEST);
-
- InitScriptExecutionCache();
-
- boost::thread_group thread_group;
- CScheduler scheduler;
const CChainParams& chainparams = Params();
- {
- LOCK(cs_main);
- ::pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- ::pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
- ::pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
- }
- {
- thread_group.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
- GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
- LoadGenesisBlock(chainparams);
- CValidationState cvstate;
- ActivateBestChain(cvstate, chainparams);
- assert(::chainActive.Tip() != nullptr);
- const bool witness_enabled{IsWitnessEnabled(::chainActive.Tip(), chainparams.GetConsensus())};
- assert(witness_enabled);
- }
CBlock block{};
CMutableTransaction coinbaseTx{};
CMutableTransaction naughtyTx{};
- CBlockIndex* pindexPrev = ::chainActive.Tip();
+ LOCK(cs_main);
+ CBlockIndex* pindexPrev = ::ChainActive().Tip();
assert(pindexPrev != nullptr);
block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus());
block.nNonce = 0;
@@ -92,11 +61,6 @@ static void DuplicateInputs(benchmark::State& state)
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
}
-
- thread_group.interrupt_all();
- thread_group.join_all();
- GetMainSignals().FlushBackgroundCallbacks();
- GetMainSignals().UnregisterBackgroundSignalScheduler();
}
BENCHMARK(DuplicateInputs, 10);
diff --git a/src/bench/examples.cpp b/src/bench/examples.cpp
index e7ddd5a938..3595249559 100644
--- a/src/bench/examples.cpp
+++ b/src/bench/examples.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
-#include <validation.h>
#include <util/time.h>
// Sanity test: this should loop ten times, and
diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp
new file mode 100644
index 0000000000..16342d0fbe
--- /dev/null
+++ b/src/bench/poly1305.cpp
@@ -0,0 +1,41 @@
+// 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 <iostream>
+
+#include <bench/bench.h>
+#include <crypto/poly1305.h>
+
+/* Number of bytes to process per iteration */
+static constexpr uint64_t BUFFER_SIZE_TINY = 64;
+static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
+static constexpr uint64_t BUFFER_SIZE_LARGE = 1024*1024;
+
+static void POLY1305(benchmark::State& state, size_t buffersize)
+{
+ std::vector<unsigned char> tag(POLY1305_TAGLEN, 0);
+ std::vector<unsigned char> key(POLY1305_KEYLEN, 0);
+ std::vector<unsigned char> in(buffersize, 0);
+ while (state.KeepRunning())
+ poly1305_auth(tag.data(), in.data(), in.size(), key.data());
+}
+
+static void POLY1305_64BYTES(benchmark::State& state)
+{
+ POLY1305(state, BUFFER_SIZE_TINY);
+}
+
+static void POLY1305_256BYTES(benchmark::State& state)
+{
+ POLY1305(state, BUFFER_SIZE_SMALL);
+}
+
+static void POLY1305_1MB(benchmark::State& state)
+{
+ POLY1305(state, BUFFER_SIZE_LARGE);
+}
+
+BENCHMARK(POLY1305_64BYTES, 500000);
+BENCHMARK(POLY1305_256BYTES, 250000);
+BENCHMARK(POLY1305_1MB, 340);
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 0a99ea3184..4016530dac 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -28,4 +28,13 @@ static void RollingBloom(benchmark::State& state)
}
}
+static void RollingBloomReset(benchmark::State& state)
+{
+ CRollingBloomFilter filter(120000, 0.000001);
+ while (state.KeepRunning()) {
+ filter.reset();
+ }
+}
+
BENCHMARK(RollingBloom, 1500 * 1000);
+BENCHMARK(RollingBloomReset, 20000);
diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp
new file mode 100644
index 0000000000..b35a744055
--- /dev/null
+++ b/src/bench/rpc_mempool.cpp
@@ -0,0 +1,42 @@
+// 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.
+
+#include <bench/bench.h>
+#include <rpc/blockchain.h>
+#include <txmempool.h>
+
+#include <univalue.h>
+
+#include <list>
+#include <vector>
+
+static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
+{
+ LockPoints lp;
+ pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
+}
+
+static void RpcMempool(benchmark::State& state)
+{
+ CTxMemPool pool;
+ LOCK2(cs_main, pool.cs);
+
+ for (int i = 0; i < 1000; ++i) {
+ CMutableTransaction tx = CMutableTransaction();
+ tx.vin.resize(1);
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vin[0].scriptWitness.stack.push_back({1});
+ tx.vout.resize(1);
+ tx.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
+ tx.vout[0].nValue = i;
+ const CTransactionRef tx_r{MakeTransactionRef(tx)};
+ AddTx(tx_r, /* fee */ i, pool);
+ }
+
+ while (state.KeepRunning()) {
+ (void)MempoolToJSON(pool, /*verbose*/ true);
+ }
+}
+
+BENCHMARK(RpcMempool, 40);
diff --git a/src/bench/util_time.cpp b/src/bench/util_time.cpp
new file mode 100644
index 0000000000..72d97354aa
--- /dev/null
+++ b/src/bench/util_time.cpp
@@ -0,0 +1,42 @@
+// 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 <bench/bench.h>
+
+#include <util/time.h>
+
+static void BenchTimeDeprecated(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ (void)GetTime();
+ }
+}
+
+static void BenchTimeMock(benchmark::State& state)
+{
+ SetMockTime(111);
+ while (state.KeepRunning()) {
+ (void)GetTime<std::chrono::seconds>();
+ }
+ SetMockTime(0);
+}
+
+static void BenchTimeMillis(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ (void)GetTime<std::chrono::milliseconds>();
+ }
+}
+
+static void BenchTimeMillisSys(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ (void)GetTimeMillis();
+ }
+}
+
+BENCHMARK(BenchTimeDeprecated, 100000000);
+BENCHMARK(BenchTimeMillis, 6000000);
+BENCHMARK(BenchTimeMillisSys, 6000000);
+BENCHMARK(BenchTimeMock, 300000000);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index 312b66e38a..4891c57b3a 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -8,7 +8,6 @@
#include <script/bitcoinconsensus.h>
#endif
#include <script/script.h>
-#include <script/sign.h>
#include <script/standard.h>
#include <streams.h>
diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp
new file mode 100644
index 0000000000..313b5a3ba0
--- /dev/null
+++ b/src/bench/wallet_balance.cpp
@@ -0,0 +1,52 @@
+// Copyright (c) 2012-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 <bench/bench.h>
+#include <interfaces/chain.h>
+#include <optional.h>
+#include <test/util.h>
+#include <validationinterface.h>
+#include <wallet/wallet.h>
+
+static void WalletBalance(benchmark::State& state, const bool set_dirty, const bool add_watchonly, const bool add_mine)
+{
+ const auto& ADDRESS_WATCHONLY = ADDRESS_BCRT1_UNSPENDABLE;
+
+ std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain();
+ CWallet wallet{chain.get(), WalletLocation(), WalletDatabase::CreateMock()};
+ {
+ bool first_run;
+ if (wallet.LoadWallet(first_run) != DBErrors::LOAD_OK) assert(false);
+ wallet.handleNotifications();
+ }
+
+
+ const Optional<std::string> address_mine{add_mine ? Optional<std::string>{getnewaddress(wallet)} : nullopt};
+ if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
+
+ for (int i = 0; i < 100; ++i) {
+ generatetoaddress(address_mine.get_value_or(ADDRESS_WATCHONLY));
+ generatetoaddress(ADDRESS_WATCHONLY);
+ }
+ SyncWithValidationInterfaceQueue();
+
+ auto bal = wallet.GetBalance(); // Cache
+
+ while (state.KeepRunning()) {
+ if (set_dirty) wallet.MarkDirty();
+ bal = wallet.GetBalance();
+ if (add_mine) assert(bal.m_mine_trusted > 0);
+ if (add_watchonly) assert(bal.m_watchonly_trusted > 0);
+ }
+}
+
+static void WalletBalanceDirty(benchmark::State& state) { WalletBalance(state, /* set_dirty */ true, /* add_watchonly */ true, /* add_mine */ true); }
+static void WalletBalanceClean(benchmark::State& state) { WalletBalance(state, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ true); }
+static void WalletBalanceMine(benchmark::State& state) { WalletBalance(state, /* set_dirty */ false, /* add_watchonly */ false, /* add_mine */ true); }
+static void WalletBalanceWatch(benchmark::State& state) { WalletBalance(state, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ false); }
+
+BENCHMARK(WalletBalanceDirty, 2500);
+BENCHMARK(WalletBalanceClean, 8000);
+BENCHMARK(WalletBalanceMine, 16000);
+BENCHMARK(WalletBalanceWatch, 8000);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index b0e1f67d93..38010c461e 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -101,7 +101,7 @@ static int AppInitRPC(int argc, char* argv[])
SetupCliArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return EXIT_FAILURE;
}
if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
@@ -115,26 +115,26 @@ static int AppInitRPC(int argc, char* argv[])
strUsage += "\n" + gArgs.GetHelpMessage();
}
- fprintf(stdout, "%s", strUsage.c_str());
+ tfm::format(std::cout, "%s", strUsage.c_str());
if (argc < 2) {
- fprintf(stderr, "Error: too few parameters\n");
+ tfm::format(std::cerr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
if (!fs::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return EXIT_FAILURE;
}
if (!gArgs.ReadConfigFiles(error, true)) {
- fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str());
return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
try {
SelectBaseParams(gArgs.GetChainName());
} catch (const std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
+ tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
return CONTINUE_EXECUTION;
@@ -253,16 +253,12 @@ public:
}
result.pushKV("version", batch[ID_NETWORKINFO]["result"]["version"]);
result.pushKV("protocolversion", batch[ID_NETWORKINFO]["result"]["protocolversion"]);
- if (!batch[ID_WALLETINFO].isNull()) {
- result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
- result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
- }
result.pushKV("blocks", batch[ID_BLOCKCHAININFO]["result"]["blocks"]);
result.pushKV("timeoffset", batch[ID_NETWORKINFO]["result"]["timeoffset"]);
result.pushKV("connections", batch[ID_NETWORKINFO]["result"]["connections"]);
result.pushKV("proxy", batch[ID_NETWORKINFO]["result"]["networks"][0]["proxy"]);
result.pushKV("difficulty", batch[ID_BLOCKCHAININFO]["result"]["difficulty"]);
- result.pushKV("testnet", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"].get_str() == "test"));
+ result.pushKV("chain", UniValue(batch[ID_BLOCKCHAININFO]["result"]["chain"]));
if (!batch[ID_WALLETINFO].isNull()) {
result.pushKV("walletversion", batch[ID_WALLETINFO]["result"]["walletversion"]);
result.pushKV("balance", batch[ID_WALLETINFO]["result"]["balance"]);
@@ -499,7 +495,7 @@ static int CommandLineRPC(int argc, char *argv[])
}
if (strPrint != "") {
- fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint.c_str());
}
return nRet;
}
@@ -512,7 +508,7 @@ int main(int argc, char* argv[])
#endif
SetupEnvironment();
if (!SetupNetworking()) {
- fprintf(stderr, "Error: Initializing networking failed\n");
+ tfm::format(std::cerr, "Error: Initializing networking failed\n");
return EXIT_FAILURE;
}
event_set_log_callback(&libevent_log_cb);
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 4be89aab6c..933b34744d 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -18,6 +18,7 @@
#include <script/script.h>
#include <script/sign.h>
#include <univalue.h>
+#include <util/rbf.h>
#include <util/system.h>
#include <util/moneystr.h>
#include <util/strencodings.h>
@@ -81,7 +82,7 @@ static int AppInitRawTx(int argc, char* argv[])
SetupBitcoinTxArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return EXIT_FAILURE;
}
@@ -89,7 +90,7 @@ static int AppInitRawTx(int argc, char* argv[])
try {
SelectParams(gArgs.GetChainName());
} catch (const std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
+ tfm::format(std::cerr, "Error: %s\n", e.what());
return EXIT_FAILURE;
}
@@ -103,10 +104,10 @@ static int AppInitRawTx(int argc, char* argv[])
"\n";
strUsage += gArgs.GetHelpMessage();
- fprintf(stdout, "%s", strUsage.c_str());
+ tfm::format(std::cout, "%s", strUsage.c_str());
if (argc < 2) {
- fprintf(stderr, "Error: too few parameters\n");
+ tfm::format(std::cerr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
@@ -322,7 +323,7 @@ static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& str
}
if (bScriptHash) {
// Get the ID for the script, and then construct a P2SH destination for it.
- scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
+ scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -396,7 +397,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
"redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
}
// Get the ID for the script, and then construct a P2SH destination for it.
- scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
+ scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -468,7 +469,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
throw std::runtime_error(strprintf(
"redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
}
- scriptPubKey = GetScriptForDestination(CScriptID(scriptPubKey));
+ scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
}
// construct TxOut, append to transaction output list
@@ -722,21 +723,21 @@ static void OutputTxJSON(const CTransaction& tx)
TxToUniv(tx, uint256(), entry);
std::string jsonOutput = entry.write(4);
- fprintf(stdout, "%s\n", jsonOutput.c_str());
+ tfm::format(std::cout, "%s\n", jsonOutput.c_str());
}
static void OutputTxHash(const CTransaction& tx)
{
std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
- fprintf(stdout, "%s\n", strHexHash.c_str());
+ tfm::format(std::cout, "%s\n", strHexHash.c_str());
}
static void OutputTxHex(const CTransaction& tx)
{
std::string strHex = EncodeHexTx(tx);
- fprintf(stdout, "%s\n", strHex.c_str());
+ tfm::format(std::cout, "%s\n", strHex.c_str());
}
static void OutputTx(const CTransaction& tx)
@@ -827,7 +828,7 @@ static int CommandLineRawTx(int argc, char* argv[])
}
if (strPrint != "") {
- fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
+ tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint.c_str());
}
return nRet;
}
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 32a539aac6..cbb4ea750c 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -8,7 +8,6 @@
#include <chainparams.h>
#include <chainparamsbase.h>
-#include <consensus/consensus.h>
#include <logging.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -37,7 +36,7 @@ static bool WalletAppInit(int argc, char* argv[])
SetupWalletToolArgs();
std::string error_message;
if (!gArgs.ParseParameters(argc, argv, error_message)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error_message.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error_message.c_str());
return false;
}
if (argc < 2 || HelpRequested(gArgs)) {
@@ -49,7 +48,7 @@ static bool WalletAppInit(int argc, char* argv[])
" bitcoin-wallet [options] <command>\n\n" +
gArgs.GetHelpMessage();
- fprintf(stdout, "%s", usage.c_str());
+ tfm::format(std::cout, "%s", usage.c_str());
return false;
}
@@ -57,7 +56,7 @@ static bool WalletAppInit(int argc, char* argv[])
LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", gArgs.GetBoolArg("-debug", false));
if (!fs::is_directory(GetDataDir(false))) {
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
@@ -88,7 +87,7 @@ int main(int argc, char* argv[])
for(int i = 1; i < argc; ++i) {
if (!IsSwitchChar(argv[i][0])) {
if (!method.empty()) {
- fprintf(stderr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method.c_str(), argv[i]);
+ tfm::format(std::cerr, "Error: two methods provided (%s and %s). Only one method should be provided.\n", method.c_str(), argv[i]);
return EXIT_FAILURE;
}
method = argv[i];
@@ -96,13 +95,13 @@ int main(int argc, char* argv[])
}
if (method.empty()) {
- fprintf(stderr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n");
+ tfm::format(std::cerr, "No method provided. Run `bitcoin-wallet -help` for valid methods.\n");
return EXIT_FAILURE;
}
// A name must be provided when creating a file
if (method == "create" && !gArgs.IsArgSet("-wallet")) {
- fprintf(stderr, "Wallet name must be provided when creating a new wallet.\n");
+ tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
return EXIT_FAILURE;
}
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index dde75c1b12..ba6de702e0 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -12,15 +12,12 @@
#include <compat.h>
#include <fs.h>
#include <interfaces/chain.h>
-#include <rpc/server.h>
#include <init.h>
#include <noui.h>
#include <shutdown.h>
#include <util/system.h>
-#include <httpserver.h>
-#include <httprpc.h>
+#include <util/threadnames.h>
#include <util/strencodings.h>
-#include <walletinitinterface.h>
#include <stdio.h>
@@ -64,6 +61,8 @@ static bool AppInit(int argc, char* argv[])
bool fRet = false;
+ util::ThreadRename("init");
+
//
// Parameters
//
@@ -71,7 +70,7 @@ static bool AppInit(int argc, char* argv[])
SetupServerArgs();
std::string error;
if (!gArgs.ParseParameters(argc, argv, error)) {
- fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str());
return false;
}
@@ -89,7 +88,7 @@ static bool AppInit(int argc, char* argv[])
strUsage += "\n" + gArgs.GetHelpMessage();
}
- fprintf(stdout, "%s", strUsage.c_str());
+ tfm::format(std::cout, "%s", strUsage.c_str());
return true;
}
@@ -97,25 +96,25 @@ static bool AppInit(int argc, char* argv[])
{
if (!fs::is_directory(GetDataDir(false)))
{
- fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
+ tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str());
return false;
}
if (!gArgs.ReadConfigFiles(error, true)) {
- fprintf(stderr, "Error reading configuration file: %s\n", error.c_str());
+ tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str());
return false;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
SelectParams(gArgs.GetChainName());
} catch (const std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
+ tfm::format(std::cerr, "Error: %s\n", e.what());
return false;
}
// Error out when loose non-argument tokens are encountered on command line
for (int i = 1; i < argc; i++) {
if (!IsSwitchChar(argv[i][0])) {
- fprintf(stderr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
+ tfm::format(std::cerr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]);
return false;
}
}
@@ -147,18 +146,18 @@ static bool AppInit(int argc, char* argv[])
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
- fprintf(stdout, "Bitcoin server starting\n");
+ tfm::format(std::cout, "Bitcoin server starting\n");
// Daemonize
if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
- fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
+ tfm::format(std::cerr, "Error: daemon() failed: %s\n", strerror(errno));
return false;
}
#if defined(MAC_OSX)
#pragma GCC diagnostic pop
#endif
#else
- fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
+ tfm::format(std::cerr, "Error: -daemon is not supported on this operating system\n");
return false;
#endif // HAVE_DECL_DAEMON
}
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index 10f51931f0..f0fcf675eb 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -203,7 +203,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
// but that is expensive, and CheckBlock caches a block's
// "checked-status" (in the CBlock?). CBlock should be able to
// check its own merkle root and cache that check.
- if (state.CorruptionPossible())
+ if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED)
return READ_STATUS_FAILED; // Possible Short ID collision
return READ_STATUS_CHECKBLOCK_FAILED;
}
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index bcf24047ff..787390be31 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -2,6 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <mutex>
+#include <sstream>
+
#include <blockfilter.h>
#include <crypto/siphash.h>
#include <hash.h>
@@ -15,6 +18,10 @@ static constexpr int GCS_SER_TYPE = SER_NETWORK;
/// Protocol version used to serialize parameters in GCS filter encoding.
static constexpr int GCS_SER_VERSION = 0;
+static const std::map<BlockFilterType, std::string> g_filter_types = {
+ {BlockFilterType::BASIC, "basic"},
+};
+
template <typename OStream>
static void GolombRiceEncode(BitStreamWriter<OStream>& bitwriter, uint8_t P, uint64_t x)
{
@@ -197,6 +204,57 @@ bool GCSFilter::MatchAny(const ElementSet& elements) const
return MatchInternal(queries.data(), queries.size());
}
+const std::string& BlockFilterTypeName(BlockFilterType filter_type)
+{
+ static std::string unknown_retval = "";
+ auto it = g_filter_types.find(filter_type);
+ return it != g_filter_types.end() ? it->second : unknown_retval;
+}
+
+bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type) {
+ for (const auto& entry : g_filter_types) {
+ if (entry.second == name) {
+ filter_type = entry.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+const std::vector<BlockFilterType>& AllBlockFilterTypes()
+{
+ static std::vector<BlockFilterType> types;
+
+ static std::once_flag flag;
+ std::call_once(flag, []() {
+ types.reserve(g_filter_types.size());
+ for (auto entry : g_filter_types) {
+ types.push_back(entry.first);
+ }
+ });
+
+ return types;
+}
+
+const std::string& ListBlockFilterTypes()
+{
+ static std::string type_list;
+
+ static std::once_flag flag;
+ std::call_once(flag, []() {
+ std::stringstream ret;
+ bool first = true;
+ for (auto entry : g_filter_types) {
+ if (!first) ret << ", ";
+ ret << entry.second;
+ first = false;
+ }
+ type_list = ret.str();
+ });
+
+ return type_list;
+}
+
static GCSFilter::ElementSet BasicFilterElements(const CBlock& block,
const CBlockUndo& block_undo)
{
@@ -251,6 +309,8 @@ bool BlockFilter::BuildParams(GCSFilter::Params& params) const
params.m_P = BASIC_FILTER_P;
params.m_M = BASIC_FILTER_M;
return true;
+ case BlockFilterType::INVALID:
+ return false;
}
return false;
diff --git a/src/blockfilter.h b/src/blockfilter.h
index 4d1f51dd60..914b94fec1 100644
--- a/src/blockfilter.h
+++ b/src/blockfilter.h
@@ -6,6 +6,7 @@
#define BITCOIN_BLOCKFILTER_H
#include <stdint.h>
+#include <string>
#include <unordered_set>
#include <vector>
@@ -83,11 +84,24 @@ public:
constexpr uint8_t BASIC_FILTER_P = 19;
constexpr uint32_t BASIC_FILTER_M = 784931;
-enum BlockFilterType : uint8_t
+enum class BlockFilterType : uint8_t
{
BASIC = 0,
+ INVALID = 255,
};
+/** Get the human-readable name for a filter type. Returns empty string for unknown types. */
+const std::string& BlockFilterTypeName(BlockFilterType filter_type);
+
+/** Find a filter type by its human-readable name. */
+bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type);
+
+/** Get a list of known filter types. */
+const std::vector<BlockFilterType>& AllBlockFilterTypes();
+
+/** Get a comma-separated list of known filter type names. */
+const std::string& ListBlockFilterTypes();
+
/**
* Complete block filter struct as defined in BIP 157. Serialization matches
* payload of "cfilter" messages.
@@ -95,7 +109,7 @@ enum BlockFilterType : uint8_t
class BlockFilter
{
private:
- BlockFilterType m_filter_type;
+ BlockFilterType m_filter_type = BlockFilterType::INVALID;
uint256 m_block_hash;
GCSFilter m_filter;
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 7732cee275..a061925089 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -14,6 +14,7 @@
#include <math.h>
#include <stdlib.h>
+#include <algorithm>
#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552
@@ -304,7 +305,5 @@ void CRollingBloomFilter::reset()
nTweak = GetRand(std::numeric_limits<unsigned int>::max());
nEntriesThisGeneration = 0;
nGeneration = 1;
- for (std::vector<uint64_t>::iterator it = data.begin(); it != data.end(); it++) {
- *it = 0;
- }
+ std::fill(data.begin(), data.end(), 0);
}
diff --git a/src/chain.cpp b/src/chain.cpp
index d462f94ab5..5520d8149a 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -59,10 +59,11 @@ const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
return pindex;
}
-CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
+CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime, int height) const
{
- std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
- [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
+ std::pair<int64_t, int> blockparams = std::make_pair(nTime, height);
+ std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), blockparams,
+ [](CBlockIndex* pBlock, const std::pair<int64_t, int>& blockparams) -> bool { return pBlock->GetBlockTimeMax() < blockparams.first || pBlock->nHeight < blockparams.second; });
return (lower == vChain.end() ? nullptr : *lower);
}
diff --git a/src/chain.h b/src/chain.h
index 2b6d2d082c..dd9cc2a598 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -465,8 +465,8 @@ public:
/** Find the last common block between this chain and a block index entry. */
const CBlockIndex *FindFork(const CBlockIndex *pindex) const;
- /** Find the earliest block with timestamp equal or greater than the given. */
- CBlockIndex* FindEarliestAtLeast(int64_t nTime) const;
+ /** Find the earliest block with timestamp equal or greater than the given time and height equal or greater than the given height. */
+ CBlockIndex* FindEarliestAtLeast(int64_t nTime, int height) const;
};
#endif // BITCOIN_CHAIN_H
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
deleted file mode 100644
index ad5edfeb39..0000000000
--- a/src/checkpoints.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2009-2018 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 <checkpoints.h>
-
-#include <chain.h>
-#include <chainparams.h>
-#include <reverse_iterator.h>
-#include <validation.h>
-
-#include <stdint.h>
-
-
-namespace Checkpoints {
-
- CBlockIndex* GetLastCheckpoint(const CCheckpointData& data)
- {
- const MapCheckpoints& checkpoints = data.mapCheckpoints;
-
- for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
- {
- const uint256& hash = i.second;
- CBlockIndex* pindex = LookupBlockIndex(hash);
- if (pindex) {
- return pindex;
- }
- }
- return nullptr;
- }
-
-} // namespace Checkpoints
diff --git a/src/checkpoints.h b/src/checkpoints.h
deleted file mode 100644
index a25e97e469..0000000000
--- a/src/checkpoints.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2009-2018 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_CHECKPOINTS_H
-#define BITCOIN_CHECKPOINTS_H
-
-#include <uint256.h>
-
-#include <map>
-
-class CBlockIndex;
-struct CCheckpointData;
-
-/**
- * Block-chain checkpoints are compiled-in sanity checks.
- * They are updated every release or three.
- */
-namespace Checkpoints
-{
-
-//! Returns last CBlockIndex* that is a checkpoint
-CBlockIndex* GetLastCheckpoint(const CCheckpointData& data);
-
-} //namespace Checkpoints
-
-#endif // BITCOIN_CHECKPOINTS_H
diff --git a/src/coins.h b/src/coins.h
index d39ebf9062..482e233e8c 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -294,6 +294,10 @@ public:
bool HaveInputs(const CTransaction& tx) const;
private:
+ /**
+ * @note this is marked const, but may actually append to `cacheCoins`, increasing
+ * memory usage.
+ */
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
};
diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h
index 820c9b93d9..6e7b4d3ded 100644
--- a/src/compat/assumptions.h
+++ b/src/compat/assumptions.h
@@ -17,6 +17,17 @@
# error "Bitcoin cannot be compiled without assertions."
#endif
+// Assumption: We assume a C++11 (ISO/IEC 14882:2011) compiler (minimum requirement).
+// Example(s): We assume the presence of C++11 features everywhere :-)
+// Note: MSVC does not report the expected __cplusplus value due to legacy
+// reasons.
+#if !defined(_MSC_VER)
+// ISO Standard C++11 [cpp.predefined]p1:
+// "The name __cplusplus is defined to the value 201103L when compiling a C++
+// translation unit."
+static_assert(__cplusplus >= 201103L, "C++11 standard assumed");
+#endif
+
// Assumption: We assume the floating-point types to fulfill the requirements of
// IEC 559 (IEEE 754) standard.
// Example(s): Floating-point division by zero in ConnectBlock, CreateTransaction
@@ -40,8 +51,13 @@ static_assert(sizeof(double) == 8, "64-bit double assumed");
static_assert(sizeof(short) == 2, "16-bit short assumed");
static_assert(sizeof(int) == 4, "32-bit int assumed");
+// Assumption: We assume size_t to be 32-bit or 64-bit.
+// Example(s): size_t assumed to be at least 32-bit in ecdsa_signature_parse_der_lax(...).
+// size_t assumed to be 32-bit or 64-bit in MallocUsage(...).
+static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t assumed to be 32-bit or 64-bit");
+static_assert(sizeof(size_t) == sizeof(void*), "Sizes of size_t and void* assumed to be equal");
+
// Some important things we are NOT assuming (non-exhaustive list):
-// * We are NOT assuming a specific value for sizeof(std::size_t).
// * We are NOT assuming a specific value for std::endian::native.
// * We are NOT assuming a specific value for std::locale("").name().
// * We are NOT assuming a specific value for std::numeric_limits<char>::is_signed.
diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp
index b47d9774ca..f87612edef 100644
--- a/src/consensus/merkle.cpp
+++ b/src/consensus/merkle.cpp
@@ -4,7 +4,6 @@
#include <consensus/merkle.h>
#include <hash.h>
-#include <util/strencodings.h>
/* WARNING! If you're reading this because you're learning about crypto
and/or designing a new system that will use merkle trees, keep in mind
diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp
new file mode 100644
index 0000000000..23ed3ecb53
--- /dev/null
+++ b/src/consensus/tx_check.cpp
@@ -0,0 +1,57 @@
+// Copyright (c) 2017-2018 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 <consensus/tx_check.h>
+
+#include <primitives/transaction.h>
+#include <consensus/validation.h>
+
+bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
+{
+ // Basic checks that don't depend on any context
+ if (tx.vin.empty())
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vin-empty");
+ if (tx.vout.empty())
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-empty");
+ // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
+ if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-oversize");
+
+ // Check for negative or overflow output values
+ CAmount nValueOut = 0;
+ for (const auto& txout : tx.vout)
+ {
+ if (txout.nValue < 0)
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-negative");
+ if (txout.nValue > MAX_MONEY)
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-vout-toolarge");
+ nValueOut += txout.nValue;
+ if (!MoneyRange(nValueOut))
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
+ }
+
+ // Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
+ if (fCheckDuplicateInputs) {
+ std::set<COutPoint> vInOutPoints;
+ for (const auto& txin : tx.vin)
+ {
+ if (!vInOutPoints.insert(txin.prevout).second)
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
+ }
+ }
+
+ if (tx.IsCoinBase())
+ {
+ if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-length");
+ }
+ else
+ {
+ for (const auto& txin : tx.vin)
+ if (txin.prevout.IsNull())
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-prevout-null");
+ }
+
+ return true;
+}
diff --git a/src/consensus/tx_check.h b/src/consensus/tx_check.h
new file mode 100644
index 0000000000..bcfdf36bf9
--- /dev/null
+++ b/src/consensus/tx_check.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2017-2018 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_CONSENSUS_TX_CHECK_H
+#define BITCOIN_CONSENSUS_TX_CHECK_H
+
+/**
+ * Context-independent transaction checking code that can be called outside the
+ * bitcoin server and doesn't depend on chain or mempool state. Transaction
+ * verification code that does call server functions or depend on server state
+ * belongs in tx_verify.h/cpp instead.
+ */
+
+class CTransaction;
+class CValidationState;
+
+bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
+
+#endif // BITCOIN_CONSENSUS_TX_CHECK_H
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index 0a7eacfb91..4b93cae848 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -156,60 +156,11 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
return nSigOps;
}
-bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fCheckDuplicateInputs)
-{
- // Basic checks that don't depend on any context
- if (tx.vin.empty())
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
- if (tx.vout.empty())
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
- // Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
- if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
-
- // Check for negative or overflow output values
- CAmount nValueOut = 0;
- for (const auto& txout : tx.vout)
- {
- if (txout.nValue < 0)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
- if (txout.nValue > MAX_MONEY)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
- nValueOut += txout.nValue;
- if (!MoneyRange(nValueOut))
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
- }
-
- // Check for duplicate inputs - note that this check is slow so we skip it in CheckBlock
- if (fCheckDuplicateInputs) {
- std::set<COutPoint> vInOutPoints;
- for (const auto& txin : tx.vin)
- {
- if (!vInOutPoints.insert(txin.prevout).second)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
- }
- }
-
- if (tx.IsCoinBase())
- {
- if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
- return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
- }
- else
- {
- for (const auto& txin : tx.vin)
- if (txin.prevout.IsNull())
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
- }
-
- return true;
-}
-
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
{
// are the actual inputs available?
if (!inputs.HaveInputs(tx)) {
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
+ return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent",
strprintf("%s: inputs missing/spent", __func__));
}
@@ -221,28 +172,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
// If prev is coinbase, check that it's matured
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
- return state.Invalid(false,
- REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
+ return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
}
// Check for negative or overflow input values
nValueIn += coin.out.nValue;
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
}
}
const CAmount value_out = tx.GetValueOut();
if (nValueIn < value_out) {
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-in-belowout",
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
}
// Tally transaction fees
const CAmount txfee_aux = nValueIn - value_out;
if (!MoneyRange(txfee_aux)) {
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-fee-outofrange");
}
txfee = txfee_aux;
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 0519cef8c0..3519fc555d 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -17,9 +17,6 @@ class CValidationState;
/** Transaction validation functions */
-/** Context-independent validity checks */
-bool CheckTransaction(const CTransaction& tx, CValidationState& state, bool fCheckDuplicateInputs=true);
-
namespace Consensus {
/**
* Check whether all inputs of this transaction are valid (no double spends and amounts)
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index f2e2c3585a..2e23f4b3a4 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -22,6 +22,78 @@ static const unsigned char REJECT_NONSTANDARD = 0x40;
static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
static const unsigned char REJECT_CHECKPOINT = 0x43;
+/** A "reason" why something was invalid, suitable for determining whether the
+ * provider of the object should be banned/ignored/disconnected/etc.
+ * These are much more granular than the rejection codes, which may be more
+ * useful for some other use-cases.
+ */
+enum class ValidationInvalidReason {
+ // txn and blocks:
+ NONE, //!< not actually invalid
+ CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
+ /**
+ * Invalid by a change to consensus rules more recent than SegWit.
+ * Currently unused as there are no such consensus rule changes, and any download
+ * sources realistically need to support SegWit in order to provide useful data,
+ * so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
+ * is uninteresting.
+ */
+ RECENT_CONSENSUS_CHANGE,
+ // Only blocks (or headers):
+ CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why
+ BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
+ BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
+ BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
+ BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
+ BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
+ BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
+ // Only loose txn:
+ TX_NOT_STANDARD, //!< didn't meet our local policy rules
+ TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs
+ TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
+ /**
+ * Transaction might be missing a witness, have a witness prior to SegWit
+ * activation, or witness may have been malleated (which includes
+ * non-standard witnesses).
+ */
+ TX_WITNESS_MUTATED,
+ /**
+ * Tx already in mempool or conflicts with a tx in the chain
+ * (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
+ * TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
+ * TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
+ */
+ TX_CONFLICT,
+ TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits
+};
+
+inline bool IsTransactionReason(ValidationInvalidReason r)
+{
+ return r == ValidationInvalidReason::NONE ||
+ r == ValidationInvalidReason::CONSENSUS ||
+ r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
+ r == ValidationInvalidReason::TX_NOT_STANDARD ||
+ r == ValidationInvalidReason::TX_PREMATURE_SPEND ||
+ r == ValidationInvalidReason::TX_MISSING_INPUTS ||
+ r == ValidationInvalidReason::TX_WITNESS_MUTATED ||
+ r == ValidationInvalidReason::TX_CONFLICT ||
+ r == ValidationInvalidReason::TX_MEMPOOL_POLICY;
+}
+
+inline bool IsBlockReason(ValidationInvalidReason r)
+{
+ return r == ValidationInvalidReason::NONE ||
+ r == ValidationInvalidReason::CONSENSUS ||
+ r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
+ r == ValidationInvalidReason::CACHED_INVALID ||
+ r == ValidationInvalidReason::BLOCK_INVALID_HEADER ||
+ r == ValidationInvalidReason::BLOCK_MUTATED ||
+ r == ValidationInvalidReason::BLOCK_MISSING_PREV ||
+ r == ValidationInvalidReason::BLOCK_INVALID_PREV ||
+ r == ValidationInvalidReason::BLOCK_TIME_FUTURE ||
+ r == ValidationInvalidReason::BLOCK_CHECKPOINT;
+}
+
/** Capture information about block/transaction validation */
class CValidationState {
private:
@@ -30,32 +102,24 @@ private:
MODE_INVALID, //!< network rule violation (DoS value may be set)
MODE_ERROR, //!< run-time error
} mode;
- int nDoS;
+ ValidationInvalidReason m_reason;
std::string strRejectReason;
unsigned int chRejectCode;
- bool corruptionPossible;
std::string strDebugMessage;
public:
- CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {}
- bool DoS(int level, bool ret = false,
- unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
- bool corruptionIn=false,
- const std::string &strDebugMessageIn="") {
+ CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE), chRejectCode(0) {}
+ bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
+ unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
+ const std::string &strDebugMessageIn="") {
+ m_reason = reasonIn;
chRejectCode = chRejectCodeIn;
strRejectReason = strRejectReasonIn;
- corruptionPossible = corruptionIn;
strDebugMessage = strDebugMessageIn;
if (mode == MODE_ERROR)
return ret;
- nDoS += level;
mode = MODE_INVALID;
return ret;
}
- bool Invalid(bool ret = false,
- unsigned int _chRejectCode=0, const std::string &_strRejectReason="",
- const std::string &_strDebugMessage="") {
- return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage);
- }
bool Error(const std::string& strRejectReasonIn) {
if (mode == MODE_VALID)
strRejectReason = strRejectReasonIn;
@@ -71,19 +135,7 @@ public:
bool IsError() const {
return mode == MODE_ERROR;
}
- bool IsInvalid(int &nDoSOut) const {
- if (IsInvalid()) {
- nDoSOut = nDoS;
- return true;
- }
- return false;
- }
- bool CorruptionPossible() const {
- return corruptionPossible;
- }
- void SetCorruptionPossible() {
- corruptionPossible = true;
- }
+ ValidationInvalidReason GetReason() const { return m_reason; }
unsigned int GetRejectCode() const { return chRejectCode; }
std::string GetRejectReason() const { return strRejectReason; }
std::string GetDebugMessage() const { return strDebugMessage; }
diff --git a/src/core_io.h b/src/core_io.h
index ae377eb6e8..19fb7b29f6 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -16,7 +16,6 @@ class CBlockHeader;
class CScript;
class CTransaction;
struct CMutableTransaction;
-struct PartiallySignedTransaction;
class uint256;
class UniValue;
@@ -37,11 +36,6 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
*/
bool ParseHashStr(const std::string& strHex, uint256& result);
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
-
-//! Decode a base64ed PSBT into a PartiallySignedTransaction
-NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
-//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
-NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
int ParseSighashString(const UniValue& sighash);
// core_write.cpp
diff --git a/src/core_read.cpp b/src/core_read.cpp
index 536a7f4f17..a3c9cf0159 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -4,7 +4,6 @@
#include <core_io.h>
-#include <psbt.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/script.h>
@@ -12,7 +11,6 @@
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
-#include <util/system.h>
#include <util/strencodings.h>
#include <version.h>
@@ -177,33 +175,6 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
return true;
}
-bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
-{
- bool invalid;
- std::string tx_data = DecodeBase64(base64_tx, &invalid);
- if (invalid) {
- error = "invalid base64";
- return false;
- }
- return DecodeRawPSBT(psbt, tx_data, error);
-}
-
-bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
-{
- CDataStream ss_data(tx_data.data(), tx_data.data() + tx_data.size(), SER_NETWORK, PROTOCOL_VERSION);
- try {
- ss_data >> psbt;
- if (!ss_data.empty()) {
- error = "extra data after PSBT";
- return false;
- }
- } catch (const std::exception& e) {
- error = e.what();
- return false;
- }
- return true;
-}
-
bool ParseHashStr(const std::string& strHex, uint256& result)
{
if ((strHex.size() != 64) || !IsHex(strHex))
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 765a170307..4d64446d7b 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -13,7 +13,6 @@
#include <streams.h>
#include <univalue.h>
#include <util/system.h>
-#include <util/moneystr.h>
#include <util/strencodings.h>
UniValue ValueFromAmount(const CAmount& amount)
diff --git a/src/crypto/aes.cpp b/src/crypto/aes.cpp
index 919ea593b7..b3fb927760 100644
--- a/src/crypto/aes.cpp
+++ b/src/crypto/aes.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <crypto/aes.h>
-#include <crypto/common.h>
#include <assert.h>
#include <string.h>
@@ -12,36 +11,6 @@ extern "C" {
#include <crypto/ctaes/ctaes.c>
}
-AES128Encrypt::AES128Encrypt(const unsigned char key[16])
-{
- AES128_init(&ctx, key);
-}
-
-AES128Encrypt::~AES128Encrypt()
-{
- memset(&ctx, 0, sizeof(ctx));
-}
-
-void AES128Encrypt::Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const
-{
- AES128_encrypt(&ctx, 1, ciphertext, plaintext);
-}
-
-AES128Decrypt::AES128Decrypt(const unsigned char key[16])
-{
- AES128_init(&ctx, key);
-}
-
-AES128Decrypt::~AES128Decrypt()
-{
- memset(&ctx, 0, sizeof(ctx));
-}
-
-void AES128Decrypt::Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const
-{
- AES128_decrypt(&ctx, 1, plaintext, ciphertext);
-}
-
AES256Encrypt::AES256Encrypt(const unsigned char key[32])
{
AES256_init(&ctx, key);
@@ -182,35 +151,3 @@ AES256CBCDecrypt::~AES256CBCDecrypt()
{
memset(iv, 0, sizeof(iv));
}
-
-AES128CBCEncrypt::AES128CBCEncrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
- : enc(key), pad(padIn)
-{
- memcpy(iv, ivIn, AES_BLOCKSIZE);
-}
-
-AES128CBCEncrypt::~AES128CBCEncrypt()
-{
- memset(iv, 0, AES_BLOCKSIZE);
-}
-
-int AES128CBCEncrypt::Encrypt(const unsigned char* data, int size, unsigned char* out) const
-{
- return CBCEncrypt(enc, iv, data, size, pad, out);
-}
-
-AES128CBCDecrypt::AES128CBCDecrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
- : dec(key), pad(padIn)
-{
- memcpy(iv, ivIn, AES_BLOCKSIZE);
-}
-
-AES128CBCDecrypt::~AES128CBCDecrypt()
-{
- memset(iv, 0, AES_BLOCKSIZE);
-}
-
-int AES128CBCDecrypt::Decrypt(const unsigned char* data, int size, unsigned char* out) const
-{
- return CBCDecrypt(dec, iv, data, size, pad, out);
-}
diff --git a/src/crypto/aes.h b/src/crypto/aes.h
index fdad70c593..e06c8de272 100644
--- a/src/crypto/aes.h
+++ b/src/crypto/aes.h
@@ -12,33 +12,8 @@ extern "C" {
}
static const int AES_BLOCKSIZE = 16;
-static const int AES128_KEYSIZE = 16;
static const int AES256_KEYSIZE = 32;
-/** An encryption class for AES-128. */
-class AES128Encrypt
-{
-private:
- AES128_ctx ctx;
-
-public:
- explicit AES128Encrypt(const unsigned char key[16]);
- ~AES128Encrypt();
- void Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const;
-};
-
-/** A decryption class for AES-128. */
-class AES128Decrypt
-{
-private:
- AES128_ctx ctx;
-
-public:
- explicit AES128Decrypt(const unsigned char key[16]);
- ~AES128Decrypt();
- void Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const;
-};
-
/** An encryption class for AES-256. */
class AES256Encrypt
{
@@ -89,30 +64,4 @@ private:
unsigned char iv[AES_BLOCKSIZE];
};
-class AES128CBCEncrypt
-{
-public:
- AES128CBCEncrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn);
- ~AES128CBCEncrypt();
- int Encrypt(const unsigned char* data, int size, unsigned char* out) const;
-
-private:
- const AES128Encrypt enc;
- const bool pad;
- unsigned char iv[AES_BLOCKSIZE];
-};
-
-class AES128CBCDecrypt
-{
-public:
- AES128CBCDecrypt(const unsigned char key[AES128_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn);
- ~AES128CBCDecrypt();
- int Decrypt(const unsigned char* data, int size, unsigned char* out) const;
-
-private:
- const AES128Decrypt dec;
- const bool pad;
- unsigned char iv[AES_BLOCKSIZE];
-};
-
#endif // BITCOIN_CRYPTO_AES_H
diff --git a/src/crypto/chacha20.cpp b/src/crypto/chacha20.cpp
index ac4470f04f..42a17f02ff 100644
--- a/src/crypto/chacha20.cpp
+++ b/src/crypto/chacha20.cpp
@@ -71,7 +71,7 @@ void ChaCha20::Seek(uint64_t pos)
input[13] = pos >> 32;
}
-void ChaCha20::Output(unsigned char* c, size_t bytes)
+void ChaCha20::Keystream(unsigned char* c, size_t bytes)
{
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
@@ -178,3 +178,133 @@ void ChaCha20::Output(unsigned char* c, size_t bytes)
c += 64;
}
}
+
+void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
+{
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ unsigned char *ctarget = nullptr;
+ unsigned char tmp[64];
+ unsigned int i;
+
+ if (!bytes) return;
+
+ j0 = input[0];
+ j1 = input[1];
+ j2 = input[2];
+ j3 = input[3];
+ j4 = input[4];
+ j5 = input[5];
+ j6 = input[6];
+ j7 = input[7];
+ j8 = input[8];
+ j9 = input[9];
+ j10 = input[10];
+ j11 = input[11];
+ j12 = input[12];
+ j13 = input[13];
+ j14 = input[14];
+ j15 = input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ // if m has fewer than 64 bytes available, copy m to tmp and
+ // read from tmp instead
+ for (i = 0;i < bytes;++i) tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20;i > 0;i -= 2) {
+ QUARTERROUND( x0, x4, x8,x12)
+ QUARTERROUND( x1, x5, x9,x13)
+ QUARTERROUND( x2, x6,x10,x14)
+ QUARTERROUND( x3, x7,x11,x15)
+ QUARTERROUND( x0, x5,x10,x15)
+ QUARTERROUND( x1, x6,x11,x12)
+ QUARTERROUND( x2, x7, x8,x13)
+ QUARTERROUND( x3, x4, x9,x14)
+ }
+ x0 += j0;
+ x1 += j1;
+ x2 += j2;
+ x3 += j3;
+ x4 += j4;
+ x5 += j5;
+ x6 += j6;
+ x7 += j7;
+ x8 += j8;
+ x9 += j9;
+ x10 += j10;
+ x11 += j11;
+ x12 += j12;
+ x13 += j13;
+ x14 += j14;
+ x15 += j15;
+
+ x0 ^= ReadLE32(m + 0);
+ x1 ^= ReadLE32(m + 4);
+ x2 ^= ReadLE32(m + 8);
+ x3 ^= ReadLE32(m + 12);
+ x4 ^= ReadLE32(m + 16);
+ x5 ^= ReadLE32(m + 20);
+ x6 ^= ReadLE32(m + 24);
+ x7 ^= ReadLE32(m + 28);
+ x8 ^= ReadLE32(m + 32);
+ x9 ^= ReadLE32(m + 36);
+ x10 ^= ReadLE32(m + 40);
+ x11 ^= ReadLE32(m + 44);
+ x12 ^= ReadLE32(m + 48);
+ x13 ^= ReadLE32(m + 52);
+ x14 ^= ReadLE32(m + 56);
+ x15 ^= ReadLE32(m + 60);
+
+ ++j12;
+ if (!j12) ++j13;
+
+ WriteLE32(c + 0, x0);
+ WriteLE32(c + 4, x1);
+ WriteLE32(c + 8, x2);
+ WriteLE32(c + 12, x3);
+ WriteLE32(c + 16, x4);
+ WriteLE32(c + 20, x5);
+ WriteLE32(c + 24, x6);
+ WriteLE32(c + 28, x7);
+ WriteLE32(c + 32, x8);
+ WriteLE32(c + 36, x9);
+ WriteLE32(c + 40, x10);
+ WriteLE32(c + 44, x11);
+ WriteLE32(c + 48, x12);
+ WriteLE32(c + 52, x13);
+ WriteLE32(c + 56, x14);
+ WriteLE32(c + 60, x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i) ctarget[i] = c[i];
+ }
+ input[12] = j12;
+ input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
+ m += 64;
+ }
+}
diff --git a/src/crypto/chacha20.h b/src/crypto/chacha20.h
index a305977bcd..5a4674f4a8 100644
--- a/src/crypto/chacha20.h
+++ b/src/crypto/chacha20.h
@@ -8,7 +8,8 @@
#include <stdint.h>
#include <stdlib.h>
-/** A PRNG class for ChaCha20. */
+/** A class for ChaCha20 256-bit stream cipher developed by Daniel J. Bernstein
+ https://cr.yp.to/chacha/chacha-20080128.pdf */
class ChaCha20
{
private:
@@ -17,10 +18,17 @@ private:
public:
ChaCha20();
ChaCha20(const unsigned char* key, size_t keylen);
- void SetKey(const unsigned char* key, size_t keylen);
- void SetIV(uint64_t iv);
- void Seek(uint64_t pos);
- void Output(unsigned char* output, size_t bytes);
+ void SetKey(const unsigned char* key, size_t keylen); //!< set key with flexible keylength; 256bit recommended */
+ void SetIV(uint64_t iv); // set the 64bit nonce
+ void Seek(uint64_t pos); // set the 64bit block counter
+
+ /** outputs the keystream of size <bytes> into <c> */
+ void Keystream(unsigned char* c, size_t bytes);
+
+ /** enciphers the message <input> of length <bytes> and write the enciphered representation into <output>
+ * Used for encryption and decryption (XOR)
+ */
+ void Crypt(const unsigned char* input, unsigned char* output, size_t bytes);
};
#endif // BITCOIN_CRYPTO_CHACHA20_H
diff --git a/src/crypto/hkdf_sha256_32.cpp b/src/crypto/hkdf_sha256_32.cpp
new file mode 100644
index 0000000000..9cea5995ec
--- /dev/null
+++ b/src/crypto/hkdf_sha256_32.cpp
@@ -0,0 +1,21 @@
+// Copyright (c) 2018 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/hkdf_sha256_32.h>
+
+#include <assert.h>
+#include <string.h>
+
+CHKDF_HMAC_SHA256_L32::CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt)
+{
+ CHMAC_SHA256((const unsigned char*)salt.c_str(), salt.size()).Write(ikm, ikmlen).Finalize(m_prk);
+}
+
+void CHKDF_HMAC_SHA256_L32::Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE])
+{
+ // expand a 32byte key (single round)
+ assert(info.size() <= 128);
+ static const unsigned char one[1] = {1};
+ CHMAC_SHA256(m_prk, 32).Write((const unsigned char*)info.data(), info.size()).Write(one, 1).Finalize(hash);
+}
diff --git a/src/crypto/hkdf_sha256_32.h b/src/crypto/hkdf_sha256_32.h
new file mode 100644
index 0000000000..fa1e42aec1
--- /dev/null
+++ b/src/crypto/hkdf_sha256_32.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2018 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_HKDF_SHA256_32_H
+#define BITCOIN_CRYPTO_HKDF_SHA256_32_H
+
+#include <crypto/hmac_sha256.h>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/** A rfc5869 HKDF implementation with HMAC_SHA256 and fixed key output length of 32 bytes (L=32) */
+class CHKDF_HMAC_SHA256_L32
+{
+private:
+ unsigned char m_prk[32];
+ static const size_t OUTPUT_SIZE = 32;
+
+public:
+ CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt);
+ void Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE]);
+};
+
+#endif // BITCOIN_CRYPTO_HKDF_SHA256_32_H
diff --git a/src/crypto/poly1305.cpp b/src/crypto/poly1305.cpp
new file mode 100644
index 0000000000..8a86c9601c
--- /dev/null
+++ b/src/crypto/poly1305.cpp
@@ -0,0 +1,141 @@
+// 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.
+
+// Based on the public domain implementation by Andrew Moon
+// poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
+
+#include <crypto/common.h>
+#include <crypto/poly1305.h>
+
+#include <string.h>
+
+#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
+
+void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
+ uint32_t t0,t1,t2,t3;
+ uint32_t h0,h1,h2,h3,h4;
+ uint32_t r0,r1,r2,r3,r4;
+ uint32_t s1,s2,s3,s4;
+ uint32_t b, nb;
+ size_t j;
+ uint64_t t[5];
+ uint64_t f0,f1,f2,f3;
+ uint64_t g0,g1,g2,g3,g4;
+ uint64_t c;
+ unsigned char mp[16];
+
+ /* clamp key */
+ t0 = ReadLE32(key+0);
+ t1 = ReadLE32(key+4);
+ t2 = ReadLE32(key+8);
+ t3 = ReadLE32(key+12);
+
+ /* precompute multipliers */
+ r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
+ r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
+ r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
+ r3 = t2 & 0x3f03fff; t3 >>= 8;
+ r4 = t3 & 0x00fffff;
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ /* init state */
+ h0 = 0;
+ h1 = 0;
+ h2 = 0;
+ h3 = 0;
+ h4 = 0;
+
+ /* full blocks */
+ if (inlen < 16) goto poly1305_donna_atmost15bytes;
+poly1305_donna_16bytes:
+ m += 16;
+ inlen -= 16;
+
+ t0 = ReadLE32(m-16);
+ t1 = ReadLE32(m-12);
+ t2 = ReadLE32(m-8);
+ t3 = ReadLE32(m-4);
+
+ h0 += t0 & 0x3ffffff;
+ h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
+ h4 += (t3 >> 8) | (1 << 24);
+
+
+poly1305_donna_mul:
+ t[0] = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
+ t[1] = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
+ t[2] = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
+ t[3] = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
+ t[4] = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
+
+ h0 = (uint32_t)t[0] & 0x3ffffff; c = (t[0] >> 26);
+ t[1] += c; h1 = (uint32_t)t[1] & 0x3ffffff; b = (uint32_t)(t[1] >> 26);
+ t[2] += b; h2 = (uint32_t)t[2] & 0x3ffffff; b = (uint32_t)(t[2] >> 26);
+ t[3] += b; h3 = (uint32_t)t[3] & 0x3ffffff; b = (uint32_t)(t[3] >> 26);
+ t[4] += b; h4 = (uint32_t)t[4] & 0x3ffffff; b = (uint32_t)(t[4] >> 26);
+ h0 += b * 5;
+
+ if (inlen >= 16) goto poly1305_donna_16bytes;
+
+ /* final bytes */
+poly1305_donna_atmost15bytes:
+ if (!inlen) goto poly1305_donna_finish;
+
+ for (j = 0; j < inlen; j++) mp[j] = m[j];
+ mp[j++] = 1;
+ for (; j < 16; j++) mp[j] = 0;
+ inlen = 0;
+
+ t0 = ReadLE32(mp+0);
+ t1 = ReadLE32(mp+4);
+ t2 = ReadLE32(mp+8);
+ t3 = ReadLE32(mp+12);
+
+ h0 += t0 & 0x3ffffff;
+ h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff;
+ h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff;
+ h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff;
+ h4 += (t3 >> 8);
+
+ goto poly1305_donna_mul;
+
+poly1305_donna_finish:
+ b = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
+ h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
+ h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
+ h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
+ h0 += b * 5; b = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += b;
+
+ g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
+ g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
+ g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
+ g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
+ g4 = h4 + b - (1 << 26);
+
+ b = (g4 >> 31) - 1;
+ nb = ~b;
+ h0 = (h0 & nb) | (g0 & b);
+ h1 = (h1 & nb) | (g1 & b);
+ h2 = (h2 & nb) | (g2 & b);
+ h3 = (h3 & nb) | (g3 & b);
+ h4 = (h4 & nb) | (g4 & b);
+
+ f0 = ((h0 ) | (h1 << 26)) + (uint64_t)ReadLE32(&key[16]);
+ f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)ReadLE32(&key[20]);
+ f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)ReadLE32(&key[24]);
+ f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)ReadLE32(&key[28]);
+
+ WriteLE32(&out[ 0], f0); f1 += (f0 >> 32);
+ WriteLE32(&out[ 4], f1); f2 += (f1 >> 32);
+ WriteLE32(&out[ 8], f2); f3 += (f2 >> 32);
+ WriteLE32(&out[12], f3);
+}
diff --git a/src/crypto/poly1305.h b/src/crypto/poly1305.h
new file mode 100644
index 0000000000..1598b013b9
--- /dev/null
+++ b/src/crypto/poly1305.h
@@ -0,0 +1,17 @@
+// 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_CRYPTO_POLY1305_H
+#define BITCOIN_CRYPTO_POLY1305_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#define POLY1305_KEYLEN 32
+#define POLY1305_TAGLEN 16
+
+void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen,
+ const unsigned char key[POLY1305_KEYLEN]);
+
+#endif // BITCOIN_CRYPTO_POLY1305_H
diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp
index a00331dcb7..edee06cc34 100644
--- a/src/crypto/ripemd160.cpp
+++ b/src/crypto/ripemd160.cpp
@@ -256,7 +256,7 @@ CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len)
ripemd160::Transform(s, buf);
bufsize = 0;
}
- while (end >= data + 64) {
+ while (end - data >= 64) {
// Process full chunks directly from the source.
ripemd160::Transform(s, data);
bytes += 64;
diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp
index 5c601c54a6..3dcdcb186e 100644
--- a/src/crypto/sha1.cpp
+++ b/src/crypto/sha1.cpp
@@ -163,7 +163,7 @@ CSHA1& CSHA1::Write(const unsigned char* data, size_t len)
sha1::Transform(s, buf);
bufsize = 0;
}
- while (end >= data + 64) {
+ while (end - data >= 64) {
// Process full chunks directly from the source.
sha1::Transform(s, data);
bytes += 64;
diff --git a/src/crypto/sha256_avx2.cpp b/src/crypto/sha256_avx2.cpp
index 068e0e5ff6..90a72516a4 100644
--- a/src/crypto/sha256_avx2.cpp
+++ b/src/crypto/sha256_avx2.cpp
@@ -3,7 +3,6 @@
#include <stdint.h>
#include <immintrin.h>
-#include <crypto/sha256.h>
#include <crypto/common.h>
namespace sha256d64_avx2 {
diff --git a/src/crypto/sha256_sse41.cpp b/src/crypto/sha256_sse41.cpp
index adca870e2d..fc79f46f7f 100644
--- a/src/crypto/sha256_sse41.cpp
+++ b/src/crypto/sha256_sse41.cpp
@@ -3,7 +3,6 @@
#include <stdint.h>
#include <immintrin.h>
-#include <crypto/sha256.h>
#include <crypto/common.h>
namespace sha256d64_sse41 {
diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp
index bc64135cae..4e6aa363f7 100644
--- a/src/crypto/sha512.cpp
+++ b/src/crypto/sha512.cpp
@@ -168,7 +168,7 @@ CSHA512& CSHA512::Write(const unsigned char* data, size_t len)
sha512::Transform(s, buf);
bufsize = 0;
}
- while (end >= data + 128) {
+ while (end - data >= 128) {
// Process full chunks directly from the source.
sha512::Transform(s, data);
data += 128;
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index 58d8cc2c9d..34896f7ab2 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -115,7 +115,7 @@ static leveldb::Options GetOptions(size_t nCacheSize)
}
CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate)
- : m_name(fs::basename(path))
+ : m_name{path.stem().string()}
{
penv = nullptr;
readoptions.verify_checksums = true;
diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp
index 8a76021a5b..eeec6dec25 100644
--- a/src/dummywallet.cpp
+++ b/src/dummywallet.cpp
@@ -23,11 +23,33 @@ public:
void DummyWalletInit::AddWalletOptions() const
{
- std::vector<std::string> opts = {"-addresstype", "-changetype", "-disablewallet", "-discardfee=<amt>", "-fallbackfee=<amt>",
- "-keypool=<n>", "-mintxfee=<amt>", "-paytxfee=<amt>", "-rescan", "-salvagewallet", "-spendzeroconfchange", "-txconfirmtarget=<n>",
- "-upgradewallet", "-wallet=<path>", "-walletbroadcast", "-walletdir=<dir>", "-walletnotify=<cmd>", "-walletrbf", "-zapwallettxes=<mode>",
- "-dblogsize=<n>", "-flushwallet", "-privdb", "-walletrejectlongchains"};
- gArgs.AddHiddenArgs(opts);
+ gArgs.AddHiddenArgs({
+ "-addresstype",
+ "-avoidpartialspends",
+ "-changetype",
+ "-disablewallet",
+ "-discardfee=<amt>",
+ "-fallbackfee=<amt>",
+ "-keypool=<n>",
+ "-maxtxfee=<amt>",
+ "-mintxfee=<amt>",
+ "-paytxfee=<amt>",
+ "-rescan",
+ "-salvagewallet",
+ "-spendzeroconfchange",
+ "-txconfirmtarget=<n>",
+ "-upgradewallet",
+ "-wallet=<path>",
+ "-walletbroadcast",
+ "-walletdir=<dir>",
+ "-walletnotify=<cmd>",
+ "-walletrbf",
+ "-zapwallettxes=<mode>",
+ "-dblogsize=<n>",
+ "-flushwallet",
+ "-privdb",
+ "-walletrejectlongchains",
+ });
}
const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
diff --git a/src/fs.cpp b/src/fs.cpp
index f937f64e04..7b422b8d70 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -3,7 +3,9 @@
#ifndef WIN32
#include <fcntl.h>
#else
+#ifndef NOMINMAX
#define NOMINMAX
+#endif
#include <codecvt>
#include <windows.h>
#endif
diff --git a/src/fs.h b/src/fs.h
index 8af81f173b..c713297d6e 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -11,6 +11,7 @@
#include <ext/stdio_filebuf.h>
#endif
+#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index fcf760a4c6..c7a119440b 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -9,7 +9,6 @@
#include <key_io.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
-#include <random.h>
#include <sync.h>
#include <util/system.h>
#include <util/strencodings.h>
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index b9ca037c9d..d17667223b 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -6,6 +6,7 @@
#include <chainparamsbase.h>
#include <compat.h>
+#include <util/threadnames.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <netbase.h>
@@ -17,7 +18,7 @@
#include <memory>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
+#include <string>
#include <sys/types.h>
#include <sys/stat.h>
@@ -138,15 +139,15 @@ struct HTTPPathHandler
//! libevent event loop
static struct event_base* eventBase = nullptr;
//! HTTP server
-struct evhttp* eventHTTP = nullptr;
+static struct evhttp* eventHTTP = nullptr;
//! List of subnets to allow RPC connections from
static std::vector<CSubNet> rpc_allow_subnets;
//! Work queue for handling longer requests off the event loop thread
static WorkQueue<HTTPClosure>* workQueue = nullptr;
//! Handlers for (sub)paths
-std::vector<HTTPPathHandler> pathHandlers;
+static std::vector<HTTPPathHandler> pathHandlers;
//! Bound listening sockets
-std::vector<evhttp_bound_socket *> boundSockets;
+static std::vector<evhttp_bound_socket *> boundSockets;
/** Check if a network address is allowed to access the HTTP server */
static bool ClientAllowed(const CNetAddr& netaddr)
@@ -284,7 +285,7 @@ static void http_reject_request_cb(struct evhttp_request* req, void*)
/** Event dispatcher thread */
static bool ThreadHTTP(struct event_base* base)
{
- RenameThread("bitcoin-http");
+ util::ThreadRename("http");
LogPrint(BCLog::HTTP, "Entering http event loop\n");
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
@@ -335,9 +336,9 @@ static bool HTTPBindAddresses(struct evhttp* http)
}
/** Simple wrapper to set thread name and run work queue */
-static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
+static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue, int worker_num)
{
- RenameThread("bitcoin-httpworker");
+ util::ThreadRename(strprintf("httpworker.%i", worker_num));
queue->Run();
}
@@ -419,7 +420,7 @@ bool UpdateHTTPServerLogging(bool enable) {
#endif
}
-std::thread threadHTTP;
+static std::thread threadHTTP;
static std::vector<std::thread> g_thread_http_workers;
void StartHTTPServer()
@@ -430,7 +431,7 @@ void StartHTTPServer()
threadHTTP = std::thread(ThreadHTTP, eventBase);
for (int i = 0; i < rpcThreads; i++) {
- g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
+ g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue, i);
}
}
@@ -655,15 +656,3 @@ void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
pathHandlers.erase(i);
}
}
-
-std::string urlDecode(const std::string &urlEncoded) {
- std::string res;
- if (!urlEncoded.empty()) {
- char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr);
- if (decoded) {
- res = std::string(decoded);
- free(decoded);
- }
- }
- return res;
-}
diff --git a/src/httpserver.h b/src/httpserver.h
index 63f96734f8..7943f0094b 100644
--- a/src/httpserver.h
+++ b/src/httpserver.h
@@ -148,6 +148,4 @@ private:
struct event* ev;
};
-std::string urlDecode(const std::string &urlEncoded);
-
#endif // BITCOIN_HTTPSERVER_H
diff --git a/src/index/base.cpp b/src/index/base.cpp
index f6f59572ce..bcc8e2ce7c 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -41,9 +41,9 @@ bool BaseIndex::DB::ReadBestBlock(CBlockLocator& locator) const
return success;
}
-bool BaseIndex::DB::WriteBestBlock(const CBlockLocator& locator)
+void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator)
{
- return Write(DB_BEST_BLOCK, locator);
+ batch.Write(DB_BEST_BLOCK, locator);
}
BaseIndex::~BaseIndex()
@@ -63,9 +63,9 @@ bool BaseIndex::Init()
if (locator.IsNull()) {
m_best_block_index = nullptr;
} else {
- m_best_block_index = FindForkInGlobalIndex(chainActive, locator);
+ m_best_block_index = FindForkInGlobalIndex(::ChainActive(), locator);
}
- m_synced = m_best_block_index.load() == chainActive.Tip();
+ m_synced = m_best_block_index.load() == ::ChainActive().Tip();
return true;
}
@@ -74,15 +74,15 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev) EXCLUSIV
AssertLockHeld(cs_main);
if (!pindex_prev) {
- return chainActive.Genesis();
+ return ::ChainActive().Genesis();
}
- const CBlockIndex* pindex = chainActive.Next(pindex_prev);
+ const CBlockIndex* pindex = ::ChainActive().Next(pindex_prev);
if (pindex) {
return pindex;
}
- return chainActive.Next(chainActive.FindFork(pindex_prev));
+ return ::ChainActive().Next(::ChainActive().FindFork(pindex_prev));
}
void BaseIndex::ThreadSync()
@@ -95,7 +95,11 @@ void BaseIndex::ThreadSync()
int64_t last_locator_write_time = 0;
while (true) {
if (m_interrupt) {
- WriteBestBlock(pindex);
+ m_best_block_index = pindex;
+ // No need to handle errors in Commit. If it fails, the error will be already be
+ // logged. The best way to recover is to continue, as index cannot be corrupted by
+ // a missed commit to disk for an advanced index state.
+ Commit();
return;
}
@@ -103,11 +107,17 @@ void BaseIndex::ThreadSync()
LOCK(cs_main);
const CBlockIndex* pindex_next = NextSyncBlock(pindex);
if (!pindex_next) {
- WriteBestBlock(pindex);
m_best_block_index = pindex;
m_synced = true;
+ // No need to handle errors in Commit. See rationale above.
+ Commit();
break;
}
+ if (pindex_next->pprev != pindex && !Rewind(pindex, pindex_next->pprev)) {
+ FatalError("%s: Failed to rewind index %s to a previous chain tip",
+ __func__, GetName());
+ return;
+ }
pindex = pindex_next;
}
@@ -119,8 +129,10 @@ void BaseIndex::ThreadSync()
}
if (last_locator_write_time + SYNC_LOCATOR_WRITE_INTERVAL < current_time) {
- WriteBestBlock(pindex);
+ m_best_block_index = pindex;
last_locator_write_time = current_time;
+ // No need to handle errors in Commit. See rationale above.
+ Commit();
}
CBlock block;
@@ -144,12 +156,35 @@ void BaseIndex::ThreadSync()
}
}
-bool BaseIndex::WriteBestBlock(const CBlockIndex* block_index)
+bool BaseIndex::Commit()
+{
+ CDBBatch batch(GetDB());
+ if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
+ return error("%s: Failed to commit latest %s state", __func__, GetName());
+ }
+ return true;
+}
+
+bool BaseIndex::CommitInternal(CDBBatch& batch)
{
LOCK(cs_main);
- if (!GetDB().WriteBestBlock(chainActive.GetLocator(block_index))) {
- return error("%s: Failed to write locator to disk", __func__);
+ GetDB().WriteBestBlock(batch, ::ChainActive().GetLocator(m_best_block_index));
+ return true;
+}
+
+bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
+{
+ assert(current_tip == m_best_block_index);
+ assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
+
+ // In the case of a reorg, ensure persisted block locator is not stale.
+ m_best_block_index = new_tip;
+ if (!Commit()) {
+ // If commit fails, revert the best block index to avoid corruption.
+ m_best_block_index = current_tip;
+ return false;
}
+
return true;
}
@@ -180,6 +215,11 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
best_block_index->GetBlockHash().ToString());
return;
}
+ if (best_block_index != pindex->pprev && !Rewind(best_block_index, pindex->pprev)) {
+ FatalError("%s: Failed to rewind index %s to a previous chain tip",
+ __func__, GetName());
+ return;
+ }
}
if (WriteBlock(*block, pindex)) {
@@ -224,9 +264,10 @@ void BaseIndex::ChainStateFlushed(const CBlockLocator& locator)
return;
}
- if (!GetDB().WriteBestBlock(locator)) {
- error("%s: Failed to write locator to disk", __func__);
- }
+ // No need to handle errors in Commit. If it fails, the error will be already be logged. The
+ // best way to recover is to continue, as index cannot be corrupted by a missed commit to disk
+ // for an advanced index state.
+ Commit();
}
bool BaseIndex::BlockUntilSyncedToCurrentChain()
@@ -239,9 +280,9 @@ bool BaseIndex::BlockUntilSyncedToCurrentChain()
{
// Skip the queue-draining stuff if we know we're caught up with
- // chainActive.Tip().
+ // ::ChainActive().Tip().
LOCK(cs_main);
- const CBlockIndex* chain_tip = chainActive.Tip();
+ const CBlockIndex* chain_tip = ::ChainActive().Tip();
const CBlockIndex* best_block_index = m_best_block_index.load();
if (best_block_index->GetAncestor(chain_tip->nHeight) == chain_tip) {
return true;
diff --git a/src/index/base.h b/src/index/base.h
index 04ee6e6cc2..31acbed0c1 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -32,7 +32,7 @@ protected:
bool ReadBestBlock(CBlockLocator& locator) const;
/// Write block locator of the chain that the txindex is in sync with.
- bool WriteBestBlock(const CBlockLocator& locator);
+ void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator);
};
private:
@@ -54,8 +54,15 @@ private:
/// over and the sync thread exits.
void ThreadSync();
- /// Write the current chain block locator to the DB.
- bool WriteBestBlock(const CBlockIndex* block_index);
+ /// Write the current index state (eg. chain block locator and subclass-specific items) to disk.
+ ///
+ /// Recommendations for error handling:
+ /// If called on a successor of the previous committed best block in the index, the index can
+ /// continue processing without risk of corruption, though the index state will need to catch up
+ /// from further behind on reboot. If the new state is not a successor of the previous state (due
+ /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up
+ /// getting corrupted.
+ bool Commit();
protected:
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
@@ -69,6 +76,14 @@ protected:
/// Write update index entries for a newly connected block.
virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; }
+ /// Virtual method called internally by Commit that can be overridden to atomically
+ /// commit more index state.
+ virtual bool CommitInternal(CDBBatch& batch);
+
+ /// Rewind index to an earlier chain tip during a chain reorg. The tip must
+ /// be an ancestor of the current best block.
+ virtual bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
+
virtual DB& GetDB() const = 0;
/// Get the name of the index for display in logs.
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
new file mode 100644
index 0000000000..20f33baf2c
--- /dev/null
+++ b/src/index/blockfilterindex.cpp
@@ -0,0 +1,467 @@
+// Copyright (c) 2018 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 <map>
+
+#include <dbwrapper.h>
+#include <index/blockfilterindex.h>
+#include <util/system.h>
+#include <validation.h>
+
+/* The index database stores three items for each block: the disk location of the encoded filter,
+ * its dSHA256 hash, and the header. Those belonging to blocks on the active chain are indexed by
+ * height, and those belonging to blocks that have been reorganized out of the active chain are
+ * indexed by block hash. This ensures that filter data for any block that becomes part of the
+ * active chain can always be retrieved, alleviating timing concerns.
+ *
+ * The filters themselves are stored in flat files and referenced by the LevelDB entries. This
+ * minimizes the amount of data written to LevelDB and keeps the database values constant size. The
+ * disk location of the next block filter to be written (represented as a FlatFilePos) is stored
+ * under the DB_FILTER_POS key.
+ *
+ * Keys for the height index have the type [DB_BLOCK_HEIGHT, uint32 (BE)]. The height is represented
+ * as big-endian so that sequential reads of filters by height are fast.
+ * Keys for the hash index have the type [DB_BLOCK_HASH, uint256].
+ */
+constexpr char DB_BLOCK_HASH = 's';
+constexpr char DB_BLOCK_HEIGHT = 't';
+constexpr char DB_FILTER_POS = 'P';
+
+constexpr unsigned int MAX_FLTR_FILE_SIZE = 0x1000000; // 16 MiB
+/** The pre-allocation chunk size for fltr?????.dat files */
+constexpr unsigned int FLTR_FILE_CHUNK_SIZE = 0x100000; // 1 MiB
+
+namespace {
+
+struct DBVal {
+ uint256 hash;
+ uint256 header;
+ FlatFilePos pos;
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ READWRITE(hash);
+ READWRITE(header);
+ READWRITE(pos);
+ }
+};
+
+struct DBHeightKey {
+ int height;
+
+ DBHeightKey() : height(0) {}
+ DBHeightKey(int height_in) : height(height_in) {}
+
+ template<typename Stream>
+ void Serialize(Stream& s) const
+ {
+ ser_writedata8(s, DB_BLOCK_HEIGHT);
+ ser_writedata32be(s, height);
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream& s)
+ {
+ char prefix = ser_readdata8(s);
+ if (prefix != DB_BLOCK_HEIGHT) {
+ throw std::ios_base::failure("Invalid format for block filter index DB height key");
+ }
+ height = ser_readdata32be(s);
+ }
+};
+
+struct DBHashKey {
+ uint256 hash;
+
+ DBHashKey(const uint256& hash_in) : hash(hash_in) {}
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action) {
+ char prefix = DB_BLOCK_HASH;
+ READWRITE(prefix);
+ if (prefix != DB_BLOCK_HASH) {
+ throw std::ios_base::failure("Invalid format for block filter index DB hash key");
+ }
+
+ READWRITE(hash);
+ }
+};
+
+}; // namespace
+
+static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
+
+BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
+ size_t n_cache_size, bool f_memory, bool f_wipe)
+ : m_filter_type(filter_type)
+{
+ const std::string& filter_name = BlockFilterTypeName(filter_type);
+ if (filter_name.empty()) throw std::invalid_argument("unknown filter_type");
+
+ fs::path path = GetDataDir() / "indexes" / "blockfilter" / filter_name;
+ fs::create_directories(path);
+
+ m_name = filter_name + " block filter index";
+ m_db = MakeUnique<BaseIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
+ m_filter_fileseq = MakeUnique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
+}
+
+bool BlockFilterIndex::Init()
+{
+ if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) {
+ // Check that the cause of the read failure is that the key does not exist. Any other errors
+ // indicate database corruption or a disk failure, and starting the index would cause
+ // further corruption.
+ if (m_db->Exists(DB_FILTER_POS)) {
+ return error("%s: Cannot read current %s state; index may be corrupted",
+ __func__, GetName());
+ }
+
+ // If the DB_FILTER_POS is not set, then initialize to the first location.
+ m_next_filter_pos.nFile = 0;
+ m_next_filter_pos.nPos = 0;
+ }
+ return BaseIndex::Init();
+}
+
+bool BlockFilterIndex::CommitInternal(CDBBatch& batch)
+{
+ const FlatFilePos& pos = m_next_filter_pos;
+
+ // Flush current filter file to disk.
+ CAutoFile file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ if (file.IsNull()) {
+ return error("%s: Failed to open filter file %d", __func__, pos.nFile);
+ }
+ if (!FileCommit(file.Get())) {
+ return error("%s: Failed to commit filter file %d", __func__, pos.nFile);
+ }
+
+ batch.Write(DB_FILTER_POS, pos);
+ return BaseIndex::CommitInternal(batch);
+}
+
+bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, BlockFilter& filter) const
+{
+ CAutoFile filein(m_filter_fileseq->Open(pos, true), SER_DISK, CLIENT_VERSION);
+ if (filein.IsNull()) {
+ return false;
+ }
+
+ uint256 block_hash;
+ std::vector<unsigned char> encoded_filter;
+ try {
+ filein >> block_hash >> encoded_filter;
+ filter = BlockFilter(GetFilterType(), block_hash, std::move(encoded_filter));
+ }
+ catch (const std::exception& e) {
+ return error("%s: Failed to deserialize block filter from disk: %s", __func__, e.what());
+ }
+
+ return true;
+}
+
+size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& filter)
+{
+ assert(filter.GetFilterType() == GetFilterType());
+
+ size_t data_size =
+ GetSerializeSize(filter.GetBlockHash(), CLIENT_VERSION) +
+ GetSerializeSize(filter.GetEncodedFilter(), CLIENT_VERSION);
+
+ // If writing the filter would overflow the file, flush and move to the next one.
+ if (pos.nPos + data_size > MAX_FLTR_FILE_SIZE) {
+ CAutoFile last_file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ if (last_file.IsNull()) {
+ LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
+ return 0;
+ }
+ if (!TruncateFile(last_file.Get(), pos.nPos)) {
+ LogPrintf("%s: Failed to truncate filter file %d\n", __func__, pos.nFile);
+ return 0;
+ }
+ if (!FileCommit(last_file.Get())) {
+ LogPrintf("%s: Failed to commit filter file %d\n", __func__, pos.nFile);
+ return 0;
+ }
+
+ pos.nFile++;
+ pos.nPos = 0;
+ }
+
+ // Pre-allocate sufficient space for filter data.
+ bool out_of_space;
+ m_filter_fileseq->Allocate(pos, data_size, out_of_space);
+ if (out_of_space) {
+ LogPrintf("%s: out of disk space\n", __func__);
+ return 0;
+ }
+
+ CAutoFile fileout(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ if (fileout.IsNull()) {
+ LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
+ return 0;
+ }
+
+ fileout << filter.GetBlockHash() << filter.GetEncodedFilter();
+ return data_size;
+}
+
+bool BlockFilterIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+{
+ CBlockUndo block_undo;
+ uint256 prev_header;
+
+ if (pindex->nHeight > 0) {
+ if (!UndoReadFromDisk(block_undo, pindex)) {
+ return false;
+ }
+
+ std::pair<uint256, DBVal> read_out;
+ if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
+ return false;
+ }
+
+ uint256 expected_block_hash = pindex->pprev->GetBlockHash();
+ if (read_out.first != expected_block_hash) {
+ return error("%s: previous block header belongs to unexpected block %s; expected %s",
+ __func__, read_out.first.ToString(), expected_block_hash.ToString());
+ }
+
+ prev_header = read_out.second.header;
+ }
+
+ BlockFilter filter(m_filter_type, block, block_undo);
+
+ size_t bytes_written = WriteFilterToDisk(m_next_filter_pos, filter);
+ if (bytes_written == 0) return false;
+
+ std::pair<uint256, DBVal> value;
+ value.first = pindex->GetBlockHash();
+ value.second.hash = filter.GetHash();
+ value.second.header = filter.ComputeHeader(prev_header);
+ value.second.pos = m_next_filter_pos;
+
+ if (!m_db->Write(DBHeightKey(pindex->nHeight), value)) {
+ return false;
+ }
+
+ m_next_filter_pos.nPos += bytes_written;
+ return true;
+}
+
+static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
+ const std::string& index_name,
+ int start_height, int stop_height)
+{
+ DBHeightKey key(start_height);
+ db_it.Seek(key);
+
+ for (int height = start_height; height <= stop_height; ++height) {
+ if (!db_it.GetKey(key) || key.height != height) {
+ return error("%s: unexpected key in %s: expected (%c, %d)",
+ __func__, index_name, DB_BLOCK_HEIGHT, height);
+ }
+
+ std::pair<uint256, DBVal> value;
+ if (!db_it.GetValue(value)) {
+ return error("%s: unable to read value in %s at key (%c, %d)",
+ __func__, index_name, DB_BLOCK_HEIGHT, height);
+ }
+
+ batch.Write(DBHashKey(value.first), std::move(value.second));
+
+ db_it.Next();
+ }
+ return true;
+}
+
+bool BlockFilterIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
+{
+ assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
+
+ CDBBatch batch(*m_db);
+ std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
+
+ // During a reorg, we need to copy all filters for blocks that are getting disconnected from the
+ // height index to the hash index so we can still find them when the height index entries are
+ // overwritten.
+ if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight, current_tip->nHeight)) {
+ return false;
+ }
+
+ // The latest filter position gets written in Commit by the call to the BaseIndex::Rewind.
+ // But since this creates new references to the filter, the position should get updated here
+ // atomically as well in case Commit fails.
+ batch.Write(DB_FILTER_POS, m_next_filter_pos);
+ if (!m_db->WriteBatch(batch)) return false;
+
+ return BaseIndex::Rewind(current_tip, new_tip);
+}
+
+static bool LookupOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
+{
+ // First check if the result is stored under the height index and the value there matches the
+ // block hash. This should be the case if the block is on the active chain.
+ std::pair<uint256, DBVal> read_out;
+ if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
+ return false;
+ }
+ if (read_out.first == block_index->GetBlockHash()) {
+ result = std::move(read_out.second);
+ return true;
+ }
+
+ // If value at the height index corresponds to an different block, the result will be stored in
+ // the hash index.
+ return db.Read(DBHashKey(block_index->GetBlockHash()), result);
+}
+
+static bool LookupRange(CDBWrapper& db, const std::string& index_name, int start_height,
+ const CBlockIndex* stop_index, std::vector<DBVal>& results)
+{
+ if (start_height < 0) {
+ return error("%s: start height (%d) is negative", __func__, start_height);
+ }
+ if (start_height > stop_index->nHeight) {
+ return error("%s: start height (%d) is greater than stop height (%d)",
+ __func__, start_height, stop_index->nHeight);
+ }
+
+ size_t results_size = static_cast<size_t>(stop_index->nHeight - start_height + 1);
+ std::vector<std::pair<uint256, DBVal>> values(results_size);
+
+ DBHeightKey key(start_height);
+ std::unique_ptr<CDBIterator> db_it(db.NewIterator());
+ db_it->Seek(DBHeightKey(start_height));
+ for (int height = start_height; height <= stop_index->nHeight; ++height) {
+ if (!db_it->Valid() || !db_it->GetKey(key) || key.height != height) {
+ return false;
+ }
+
+ size_t i = static_cast<size_t>(height - start_height);
+ if (!db_it->GetValue(values[i])) {
+ return error("%s: unable to read value in %s at key (%c, %d)",
+ __func__, index_name, DB_BLOCK_HEIGHT, height);
+ }
+
+ db_it->Next();
+ }
+
+ results.resize(results_size);
+
+ // Iterate backwards through block indexes collecting results in order to access the block hash
+ // of each entry in case we need to look it up in the hash index.
+ for (const CBlockIndex* block_index = stop_index;
+ block_index && block_index->nHeight >= start_height;
+ block_index = block_index->pprev) {
+ uint256 block_hash = block_index->GetBlockHash();
+
+ size_t i = static_cast<size_t>(block_index->nHeight - start_height);
+ if (block_hash == values[i].first) {
+ results[i] = std::move(values[i].second);
+ continue;
+ }
+
+ if (!db.Read(DBHashKey(block_hash), results[i])) {
+ return error("%s: unable to read value in %s at key (%c, %s)",
+ __func__, index_name, DB_BLOCK_HASH, block_hash.ToString());
+ }
+ }
+
+ return true;
+}
+
+bool BlockFilterIndex::LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const
+{
+ DBVal entry;
+ if (!LookupOne(*m_db, block_index, entry)) {
+ return false;
+ }
+
+ return ReadFilterFromDisk(entry.pos, filter_out);
+}
+
+bool BlockFilterIndex::LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) const
+{
+ DBVal entry;
+ if (!LookupOne(*m_db, block_index, entry)) {
+ return false;
+ }
+
+ header_out = entry.header;
+ return true;
+}
+
+bool BlockFilterIndex::LookupFilterRange(int start_height, const CBlockIndex* stop_index,
+ std::vector<BlockFilter>& filters_out) const
+{
+ std::vector<DBVal> entries;
+ if (!LookupRange(*m_db, m_name, start_height, stop_index, entries)) {
+ return false;
+ }
+
+ filters_out.resize(entries.size());
+ auto filter_pos_it = filters_out.begin();
+ for (const auto& entry : entries) {
+ if (!ReadFilterFromDisk(entry.pos, *filter_pos_it)) {
+ return false;
+ }
+ ++filter_pos_it;
+ }
+
+ return true;
+}
+
+bool BlockFilterIndex::LookupFilterHashRange(int start_height, const CBlockIndex* stop_index,
+ std::vector<uint256>& hashes_out) const
+
+{
+ std::vector<DBVal> entries;
+ if (!LookupRange(*m_db, m_name, start_height, stop_index, entries)) {
+ return false;
+ }
+
+ hashes_out.clear();
+ hashes_out.reserve(entries.size());
+ for (const auto& entry : entries) {
+ hashes_out.push_back(entry.hash);
+ }
+ return true;
+}
+
+BlockFilterIndex* GetBlockFilterIndex(BlockFilterType filter_type)
+{
+ auto it = g_filter_indexes.find(filter_type);
+ return it != g_filter_indexes.end() ? &it->second : nullptr;
+}
+
+void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn)
+{
+ for (auto& entry : g_filter_indexes) fn(entry.second);
+}
+
+bool InitBlockFilterIndex(BlockFilterType filter_type,
+ size_t n_cache_size, bool f_memory, bool f_wipe)
+{
+ auto result = g_filter_indexes.emplace(std::piecewise_construct,
+ std::forward_as_tuple(filter_type),
+ std::forward_as_tuple(filter_type,
+ n_cache_size, f_memory, f_wipe));
+ return result.second;
+}
+
+bool DestroyBlockFilterIndex(BlockFilterType filter_type)
+{
+ return g_filter_indexes.erase(filter_type);
+}
+
+void DestroyAllBlockFilterIndexes()
+{
+ g_filter_indexes.clear();
+}
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
new file mode 100644
index 0000000000..436d52515f
--- /dev/null
+++ b/src/index/blockfilterindex.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2018 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_INDEX_BLOCKFILTERINDEX_H
+#define BITCOIN_INDEX_BLOCKFILTERINDEX_H
+
+#include <blockfilter.h>
+#include <chain.h>
+#include <flatfile.h>
+#include <index/base.h>
+
+/**
+ * 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
+ * (ie. filter data for different types are stored in separate databases).
+ *
+ * This index is used to serve BIP 157 net requests.
+ */
+class BlockFilterIndex final : public BaseIndex
+{
+private:
+ BlockFilterType m_filter_type;
+ std::string m_name;
+ std::unique_ptr<BaseIndex::DB> m_db;
+
+ FlatFilePos m_next_filter_pos;
+ std::unique_ptr<FlatFileSeq> m_filter_fileseq;
+
+ bool ReadFilterFromDisk(const FlatFilePos& pos, BlockFilter& filter) const;
+ size_t WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& filter);
+
+protected:
+ bool Init() override;
+
+ bool CommitInternal(CDBBatch& batch) override;
+
+ bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+
+ bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) override;
+
+ BaseIndex::DB& GetDB() const override { return *m_db; }
+
+ const char* GetName() const override { return m_name.c_str(); }
+
+public:
+ /** Constructs the index, which becomes available to be queried. */
+ explicit BlockFilterIndex(BlockFilterType filter_type,
+ size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
+
+ BlockFilterType GetFilterType() const { return m_filter_type; }
+
+ /** Get a single filter by block. */
+ bool LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const;
+
+ /** Get a single filter header by block. */
+ bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) const;
+
+ /** Get a range of filters between two heights on a chain. */
+ bool LookupFilterRange(int start_height, const CBlockIndex* stop_index,
+ std::vector<BlockFilter>& filters_out) const;
+
+ /** Get a range of filter hashes between two heights on a chain. */
+ bool LookupFilterHashRange(int start_height, const CBlockIndex* stop_index,
+ std::vector<uint256>& hashes_out) const;
+};
+
+/**
+ * Get a block filter index by type. Returns nullptr if index has not been initialized or was
+ * already destroyed.
+ */
+BlockFilterIndex* GetBlockFilterIndex(BlockFilterType filter_type);
+
+/** Iterate over all running block filter indexes, invoking fn on each. */
+void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn);
+
+/**
+ * Initialize a block filter index for the given type if one does not already exist. Returns true if
+ * a new index is created and false if one has already been initialized.
+ */
+bool InitBlockFilterIndex(BlockFilterType filter_type,
+ size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
+
+/**
+ * Destroy the block filter index with the given type. Returns false if no such index exists. This
+ * just releases the allocated memory and closes the database connection, it does not delete the
+ * index data.
+ */
+bool DestroyBlockFilterIndex(BlockFilterType filter_type);
+
+/** Destroy all open block filter indexes. */
+void DestroyAllBlockFilterIndexes();
+
+#endif // BITCOIN_INDEX_BLOCKFILTERINDEX_H
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 7367ec7cb6..929b85bfb5 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -236,7 +236,7 @@ bool TxIndex::Init()
// Attempt to migrate txindex from the old database to the new one. Even if
// chain_tip is null, the node could be reindexing and we still want to
// delete txindex records in the old database.
- if (!m_db->MigrateData(*pblocktree, chainActive.GetLocator())) {
+ if (!m_db->MigrateData(*pblocktree, ::ChainActive().GetLocator())) {
return false;
}
diff --git a/src/init.cpp b/src/init.cpp
index ee9a451d0b..6625080c6e 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -12,14 +12,15 @@
#include <addrman.h>
#include <amount.h>
#include <banman.h>
+#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
-#include <checkpoints.h>
#include <compat/sanity.h>
#include <consensus/validation.h>
#include <fs.h>
#include <httpserver.h>
#include <httprpc.h>
+#include <index/blockfilterindex.h>
#include <interfaces/chain.h>
#include <index/txindex.h>
#include <key.h>
@@ -31,6 +32,7 @@
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/policy.h>
+#include <policy/settings.h>
#include <rpc/server.h>
#include <rpc/register.h>
#include <rpc/blockchain.h>
@@ -39,6 +41,7 @@
#include <script/sigcache.h>
#include <scheduler.h>
#include <shutdown.h>
+#include <util/threadnames.h>
#include <timedata.h>
#include <txdb.h>
#include <txmempool.h>
@@ -46,8 +49,8 @@
#include <ui_interface.h>
#include <util/system.h>
#include <util/moneystr.h>
+#include <util/validation.h>
#include <validationinterface.h>
-#include <warnings.h>
#include <walletinitinterface.h>
#include <stdint.h>
#include <stdio.h>
@@ -63,7 +66,6 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/thread.hpp>
-#include <openssl/crypto.h>
#if ENABLE_ZMQ
#include <zmq/zmqabstractnotifier.h>
@@ -71,7 +73,7 @@
#include <zmq/zmqrpc.h>
#endif
-bool fFeeEstimatesInitialized = false;
+static bool fFeeEstimatesInitialized = false;
static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
@@ -106,14 +108,13 @@ static fs::path GetPidFile()
NODISCARD static bool CreatePidFile()
{
- FILE* file = fsbridge::fopen(GetPidFile(), "w");
+ fsbridge::ofstream file{GetPidFile()};
if (file) {
#ifdef WIN32
- fprintf(file, "%d\n", GetCurrentProcessId());
+ tfm::format(file, "%d\n", GetCurrentProcessId());
#else
- fprintf(file, "%d\n", getpid());
+ tfm::format(file, "%d\n", getpid());
#endif
- fclose(file);
return true;
} else {
return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno)));
@@ -189,6 +190,7 @@ void Interrupt()
if (g_txindex) {
g_txindex->Interrupt();
}
+ ForEachBlockFilterIndex([](BlockFilterIndex& index) { index.Interrupt(); });
}
void Shutdown(InitInterfaces& interfaces)
@@ -203,7 +205,7 @@ void Shutdown(InitInterfaces& interfaces)
/// for example if the data directory was found to be locked.
/// Be sure that anything that writes files or flushes caches only does this if the respective
/// module was initialized.
- RenameThread("bitcoin-shutoff");
+ util::ThreadRename("shutoff");
mempool.AddTransactionsUpdated(1);
StopHTTPRPC();
@@ -220,6 +222,7 @@ void Shutdown(InitInterfaces& interfaces)
if (peerLogic) UnregisterValidationInterface(peerLogic.get());
if (g_connman) g_connman->Stop();
if (g_txindex) g_txindex->Stop();
+ ForEachBlockFilterIndex([](BlockFilterIndex& index) { index.Stop(); });
StopTorControl();
@@ -234,9 +237,10 @@ void Shutdown(InitInterfaces& interfaces)
g_connman.reset();
g_banman.reset();
g_txindex.reset();
+ DestroyAllBlockFilterIndexes();
- if (g_is_mempool_loaded && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
- DumpMempool();
+ if (::mempool.IsLoaded() && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
+ DumpMempool(::mempool);
}
if (fFeeEstimatesInitialized)
@@ -253,7 +257,7 @@ void Shutdown(InitInterfaces& interfaces)
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
if (pcoinsTip != nullptr) {
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
}
// After there are no more peers/RPC left to give us new data which may generate
@@ -269,7 +273,7 @@ void Shutdown(InitInterfaces& interfaces)
{
LOCK(cs_main);
if (pcoinsTip != nullptr) {
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
}
pcoinsTip.reset();
pcoinscatcher.reset();
@@ -339,14 +343,15 @@ static void registerSignalHandler(int signal, void(*handler)(int))
}
#endif
+static boost::signals2::connection rpc_notify_block_change_connection;
static void OnRPCStarted()
{
- uiInterface.NotifyBlockTip_connect(&RPCNotifyBlockChange);
+ rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(&RPCNotifyBlockChange);
}
static void OnRPCStopped()
{
- uiInterface.NotifyBlockTip_disconnect(&RPCNotifyBlockChange);
+ rpc_notify_block_change_connection.disconnect();
RPCNotifyBlockChange(false, nullptr);
g_best_block_cv.notify_all();
LogPrint(BCLog::RPC, "RPC stopped.\n");
@@ -373,10 +378,10 @@ void SetupServerArgs()
gArgs.AddArg("-version", "Print version and exit", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-alertnotify=<cmd>", "Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-assumevalid=<hex>", strprintf("If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)", defaultChainParams->GetConsensus().defaultAssumeValid.GetHex(), testnetChainParams->GetConsensus().defaultAssumeValid.GetHex()), false, OptionsCategory::OPTIONS);
- gArgs.AddArg("-blocksdir=<dir>", "Specify blocks directory (default: <datadir>/blocks)", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-blocksdir=<dir>", "Specify directory to hold blocks subdirectory for *.dat files (default: <datadir>)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-blocknotify=<cmd>", "Execute command when the best block changes (%s in cmd is replaced by block hash)", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-blockreconstructionextratxn=<n>", strprintf("Extra transactions to keep in memory for compact block reconstructions (default: %u)", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN), false, OptionsCategory::OPTIONS);
- gArgs.AddArg("-blocksonly", strprintf("Whether to operate in a blocks only mode (default: %u)", DEFAULT_BLOCKSONLY), true, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-blocksonly", strprintf("Whether to reject transactions from network peers. Transactions from the wallet or RPC are not affected. (default: %u)", DEFAULT_BLOCKSONLY), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), false, OptionsCategory::OPTIONS);
gArgs.AddArg("-datadir=<dir>", "Specify data directory", false, OptionsCategory::OPTIONS);
gArgs.AddArg("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize), true, OptionsCategory::OPTIONS);
@@ -404,6 +409,10 @@ void SetupServerArgs()
hidden_args.emplace_back("-sysperms");
#endif
gArgs.AddArg("-txindex", strprintf("Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)", DEFAULT_TXINDEX), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-blockfilterindex=<type>",
+ strprintf("Maintain an index of compact filters by block (default: %s, values: %s).", DEFAULT_BLOCKFILTERINDEX, ListBlockFilterTypes()) +
+ " If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
+ false, OptionsCategory::OPTIONS);
gArgs.AddArg("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info). This option can be specified multiple times to add multiple nodes.", false, OptionsCategory::CONNECTION);
gArgs.AddArg("-banscore=<n>", strprintf("Threshold for disconnecting misbehaving peers (default: %u)", DEFAULT_BANSCORE_THRESHOLD), false, OptionsCategory::CONNECTION);
@@ -446,7 +455,7 @@ void SetupServerArgs()
#endif
gArgs.AddArg("-whitebind=<addr>", "Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6", false, OptionsCategory::CONNECTION);
gArgs.AddArg("-whitelist=<IP address or network>", "Whitelist peers connecting from the given IP address (e.g. 1.2.3.4) or CIDR notated network (e.g. 1.2.3.0/24). Can be specified multiple times."
- " Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway", false, OptionsCategory::CONNECTION);
+ " Whitelisted peers cannot be DoS banned", false, OptionsCategory::CONNECTION);
g_wallet_init_interface.AddWalletOptions();
@@ -479,7 +488,7 @@ void SetupServerArgs()
"and level 4 tries to reconnect the blocks, "
"each level includes the checks of the previous levels "
"(0-4, default: %u)", DEFAULT_CHECKLEVEL), true, OptionsCategory::DEBUG_TEST);
- gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, chainActive and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-checkblockindex", strprintf("Do a full consistency check for mapBlockIndex, setBlockIndexCandidates, ::ChainActive() and mapBlocksUnlinked occasionally. (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-checkmempool=<n>", strprintf("Run checks every <n> transactions (default: %u, regtest: %u)", defaultChainParams->DefaultConsistencyChecks(), regtestChainParams->DefaultConsistencyChecks()), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", DEFAULT_CHECKPOINTS_ENABLED), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-deprecatedrpc=<method>", "Allows deprecated RPC method(s) to be used", true, OptionsCategory::DEBUG_TEST);
@@ -496,12 +505,11 @@ void SetupServerArgs()
gArgs.AddArg("-debugexclude=<category>", strprintf("Exclude debugging information for a category. Can be used in conjunction with -debug=1 to output debug logs for all categories except one or more specified categories."), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-logips", strprintf("Include IP addresses in debug output (default: %u)", DEFAULT_LOGIPS), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-logtimestamps", strprintf("Prepend debug output with timestamp (default: %u)", DEFAULT_LOGTIMESTAMPS), false, OptionsCategory::DEBUG_TEST);
+ gArgs.AddArg("-logthreadnames", strprintf("Prepend debug output with name of the originating thread (only available on platforms supporting thread_local) (default: %u)", DEFAULT_LOGTHREADNAMES), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)", true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), true, OptionsCategory::DEBUG_TEST);
- gArgs.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)",
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), true, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-printtoconsole", "Send trace/debug info to console (default: 1 when no -daemon. To disable logging to file, set -nodebuglogfile)", false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-shrinkdebugfile", "Shrink debug.log file on client startup (default: 1 when no -debug)", false, OptionsCategory::DEBUG_TEST);
@@ -511,14 +519,13 @@ void SetupServerArgs()
gArgs.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), true, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), true, OptionsCategory::NODE_RELAY);
- gArgs.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), true, OptionsCategory::NODE_RELAY);
+ gArgs.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), true, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), false, OptionsCategory::NODE_RELAY);
- gArgs.AddArg("-mempoolreplacement", strprintf("Enable transaction replacement in the memory pool (default: %u)", DEFAULT_ENABLE_REPLACEMENT), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), false, OptionsCategory::NODE_RELAY);
- gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY);
+ gArgs.AddArg("-whitelistforcerelay", strprintf("Force relay of transactions from whitelisted peers even if the transactions were already in the mempool or violate local relay policy (default: %d)", DEFAULT_WHITELISTFORCERELAY), false, OptionsCategory::NODE_RELAY);
gArgs.AddArg("-whitelistrelay", strprintf("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), false, OptionsCategory::NODE_RELAY);
@@ -658,7 +665,7 @@ static void CleanupBlockRevFiles()
static void ThreadImport(std::vector<fs::path> vImportFiles)
{
const CChainParams& chainparams = Params();
- RenameThread("bitcoin-loadblk");
+ util::ThreadRename("loadblk");
ScheduleBatchPriority();
{
@@ -725,9 +732,9 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
}
} // End scope of CImportingNow
if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
- LoadMempool();
+ LoadMempool(::mempool);
}
- g_is_mempool_loaded = !ShutdownRequested();
+ ::mempool.SetIsLoaded(!ShutdownRequested());
}
/** Sanity checks
@@ -828,19 +835,6 @@ void InitParameterInteraction()
if (gArgs.SoftSetBoolArg("-whitelistrelay", true))
LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__);
}
-
- // Warn if network-specific options (-addnode, -connect, etc) are
- // specified in default section of config file, but not overridden
- // on the command line or in this network's section of the config file.
- std::string network = gArgs.GetChainName();
- for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) {
- InitWarning(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network));
- }
-
- // Warn if unrecognized section name are present in the config file.
- for (const auto& section : gArgs.GetUnrecognizedSections()) {
- InitWarning(strprintf("%s:%i " + _("Section [%s] is not recognized."), section.m_file, section.m_line, section.m_name));
- }
}
static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
@@ -858,15 +852,10 @@ void InitLogging()
{
LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile");
LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE));
-
- // Add newlines to the logfile to distinguish this execution from the last
- // one; called before console logging is set up, so this is only sent to
- // debug.log.
- LogPrintf("\n\n\n\n\n");
-
LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false));
LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS);
LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS);
+ LogInstance().m_log_threadnames = gArgs.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES);
fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS);
@@ -886,6 +875,7 @@ int nUserMaxConnections;
int nFD;
ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED);
int64_t peer_connect_timeout;
+std::vector<BlockFilterType> g_enabled_filter_types;
} // namespace
@@ -950,14 +940,46 @@ bool AppInitParameterInteraction()
// also see: InitParameterInteraction()
+ // Warn if network-specific options (-addnode, -connect, etc) are
+ // specified in default section of config file, but not overridden
+ // on the command line or in this network's section of the config file.
+ std::string network = gArgs.GetChainName();
+ for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) {
+ return InitError(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network));
+ }
+
+ // Warn if unrecognized section name are present in the config file.
+ for (const auto& section : gArgs.GetUnrecognizedSections()) {
+ InitWarning(strprintf("%s:%i " + _("Section [%s] is not recognized."), section.m_file, section.m_line, section.m_name));
+ }
+
if (!fs::is_directory(GetBlocksDir())) {
return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "").c_str()));
}
+ // parse and validate enabled filter types
+ std::string blockfilterindex_value = gArgs.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX);
+ if (blockfilterindex_value == "" || blockfilterindex_value == "1") {
+ g_enabled_filter_types = AllBlockFilterTypes();
+ } else if (blockfilterindex_value != "0") {
+ const std::vector<std::string> names = gArgs.GetArgs("-blockfilterindex");
+ g_enabled_filter_types.reserve(names.size());
+ for (const auto& name : names) {
+ BlockFilterType filter_type;
+ if (!BlockFilterTypeByName(name, filter_type)) {
+ return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name));
+ }
+ g_enabled_filter_types.push_back(filter_type);
+ }
+ }
+
// if using block pruning, then disallow txindex
if (gArgs.GetArg("-prune", 0)) {
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
+ if (!g_enabled_filter_types.empty()) {
+ return InitError(_("Prune mode is incompatible with -blockfilterindex."));
+ }
}
// -bind and -whitebind can't be set when not listening
@@ -1121,22 +1143,6 @@ bool AppInitParameterInteraction()
dustRelayFee = CFeeRate(n);
}
- // This is required by both the wallet and node
- if (gArgs.IsArgSet("-maxtxfee"))
- {
- CAmount nMaxFee = 0;
- if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee))
- return InitError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
- if (nMaxFee > HIGH_MAX_TX_FEE)
- InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
- maxTxFee = nMaxFee;
- if (CFeeRate(maxTxFee, 1000) < ::minRelayTxFee)
- {
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
- gArgs.GetArg("-maxtxfee", ""), ::minRelayTxFee.ToString()));
- }
- }
-
fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
if (chainparams.RequireStandard() && !fRequireStandard)
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
@@ -1162,15 +1168,6 @@ bool AppInitParameterInteraction()
nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
- fEnableReplacement = gArgs.GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT);
- if ((!fEnableReplacement) && gArgs.IsArgSet("-mempoolreplacement")) {
- // Minimal effort at forwards compatibility
- std::string strReplacementModeList = gArgs.GetArg("-mempoolreplacement", ""); // default is impossible
- std::vector<std::string> vstrReplacementModes;
- boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(","));
- fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end());
- }
-
return true;
}
@@ -1234,10 +1231,10 @@ bool AppInitMain(InitInterfaces& interfaces)
// and because this needs to happen before any other debug.log printing
LogInstance().ShrinkDebugFile();
}
- if (!LogInstance().OpenDebugLog()) {
+ }
+ if (!LogInstance().StartLogging()) {
return InitError(strprintf("Could not open debug log file %s",
LogInstance().m_file_path.string()));
- }
}
if (!LogInstance().m_log_timestamps)
@@ -1274,7 +1271,7 @@ bool AppInitMain(InitInterfaces& interfaces)
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
if (nScriptCheckThreads) {
for (int i=0; i<nScriptCheckThreads-1; i++)
- threadGroup.create_thread(&ThreadScriptCheck);
+ threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
}
// Start the lightweight task scheduler thread
@@ -1411,7 +1408,7 @@ bool AppInitMain(InitInterfaces& interfaces)
// see Step 2: parameter interactions for more information about these
fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = gArgs.GetBoolArg("-discover", true);
- fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
+ g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
for (const std::string& strAddr : gArgs.GetArgs("-externalip")) {
CService addrLocal;
@@ -1448,6 +1445,13 @@ bool AppInitMain(InitInterfaces& interfaces)
nTotalCache -= nBlockTreeDBCache;
int64_t nTxIndexCache = std::min(nTotalCache / 8, gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0);
nTotalCache -= nTxIndexCache;
+ int64_t filter_index_cache = 0;
+ if (!g_enabled_filter_types.empty()) {
+ size_t n_indexes = g_enabled_filter_types.size();
+ int64_t max_cache = std::min(nTotalCache / 8, max_filter_index_cache << 20);
+ filter_index_cache = max_cache / n_indexes;
+ nTotalCache -= filter_index_cache * n_indexes;
+ }
int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache
nTotalCache -= nCoinDBCache;
@@ -1458,6 +1462,10 @@ bool AppInitMain(InitInterfaces& interfaces)
if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
LogPrintf("* Using %.1f MiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024));
}
+ for (BlockFilterType filter_type : g_enabled_filter_types) {
+ LogPrintf("* Using %.1f MiB for %s block filter index database\n",
+ filter_index_cache * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type));
+ }
LogPrintf("* Using %.1f MiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
@@ -1468,11 +1476,11 @@ bool AppInitMain(InitInterfaces& interfaces)
uiInterface.InitMessage(_("Loading block index..."));
- LOCK(cs_main);
-
do {
const int64_t load_block_index_start_time = GetTimeMillis();
+ bool is_coinsview_empty;
try {
+ LOCK(cs_main);
UnloadBlockIndex();
pcoinsTip.reset();
pcoinsdbview.reset();
@@ -1496,6 +1504,7 @@ bool AppInitMain(InitInterfaces& interfaces)
// Note that it also sets fReindex based on the disk flag!
// From here on out fReindex and fReset mean something different!
if (!LoadBlockIndex(chainparams)) {
+ if (ShutdownRequested()) break;
strLoadError = _("Error loading block database");
break;
}
@@ -1544,27 +1553,34 @@ bool AppInitMain(InitInterfaces& interfaces)
// The on-disk coinsdb is now in a good state, create the cache
pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
- bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
+ is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
if (!is_coinsview_empty) {
- // LoadChainTip sets chainActive based on pcoinsTip's best block
+ // LoadChainTip sets ::ChainActive() based on pcoinsTip's best block
if (!LoadChainTip(chainparams)) {
strLoadError = _("Error initializing block database");
break;
}
- assert(chainActive.Tip() != nullptr);
+ assert(::ChainActive().Tip() != nullptr);
}
+ } catch (const std::exception& e) {
+ LogPrintf("%s\n", e.what());
+ strLoadError = _("Error opening block database");
+ break;
+ }
- if (!fReset) {
- // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
- // It both disconnects blocks based on chainActive, and drops block data in
- // mapBlockIndex based on lack of available witness data.
- uiInterface.InitMessage(_("Rewinding blocks..."));
- if (!RewindBlockIndex(chainparams)) {
- strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
- break;
- }
+ if (!fReset) {
+ // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
+ // It both disconnects blocks based on ::ChainActive(), and drops block data in
+ // mapBlockIndex based on lack of available witness data.
+ uiInterface.InitMessage(_("Rewinding blocks..."));
+ if (!RewindBlockIndex(chainparams)) {
+ strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain");
+ break;
}
+ }
+ try {
+ LOCK(cs_main);
if (!is_coinsview_empty) {
uiInterface.InitMessage(_("Verifying blocks..."));
if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
@@ -1572,7 +1588,7 @@ bool AppInitMain(InitInterfaces& interfaces)
MIN_BLOCKS_TO_KEEP);
}
- CBlockIndex* tip = chainActive.Tip();
+ CBlockIndex* tip = ::ChainActive().Tip();
RPCNotifyBlockChange(true, tip);
if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
strLoadError = _("The block database contains a block which appears to be from the future. "
@@ -1638,6 +1654,11 @@ bool AppInitMain(InitInterfaces& interfaces)
g_txindex->Start();
}
+ for (const auto& filter_type : g_enabled_filter_types) {
+ InitBlockFilterIndex(filter_type, filter_index_cache, false, fReindex);
+ GetBlockFilterIndex(filter_type)->Start();
+ }
+
// ********************************************************* Step 9: load wallet
for (const auto& client : interfaces.chain_clients) {
if (!client->load()) {
@@ -1654,7 +1675,7 @@ bool AppInitMain(InitInterfaces& interfaces)
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
if (!fReindex) {
uiInterface.InitMessage(_("Pruning blockstore..."));
- PruneAndFlush();
+ ::ChainstateActive().PruneAndFlush();
}
}
@@ -1680,8 +1701,9 @@ bool AppInitMain(InitInterfaces& interfaces)
// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
- if (chainActive.Tip() == nullptr) {
- uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait);
+ boost::signals2::connection block_notify_genesis_wait_connection;
+ if (::ChainActive().Tip() == nullptr) {
+ block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(BlockNotifyGenesisWait);
} else {
fHaveGenesis = true;
}
@@ -1705,7 +1727,7 @@ bool AppInitMain(InitInterfaces& interfaces)
while (!fHaveGenesis && !ShutdownRequested()) {
g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500));
}
- uiInterface.NotifyBlockTip_disconnect(BlockNotifyGenesisWait);
+ block_notify_genesis_wait_connection.disconnect();
}
if (ShutdownRequested()) {
@@ -1720,7 +1742,7 @@ bool AppInitMain(InitInterfaces& interfaces)
{
LOCK(cs_main);
LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size());
- chain_active_height = chainActive.Height();
+ chain_active_height = ::ChainActive().Height();
}
LogPrintf("nBestHeight = %d\n", chain_active_height);
diff --git a/src/interfaces/README.md b/src/interfaces/README.md
index 57d41df746..f77d172153 100644
--- a/src/interfaces/README.md
+++ b/src/interfaces/README.md
@@ -2,9 +2,9 @@
The following interfaces are defined here:
-* [`Chain`](chain.h) — used by wallet to access blockchain and mempool state. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
+* [`Chain`](chain.h) — used by wallet to access blockchain and mempool state. Added in [#14437](https://github.com/bitcoin/bitcoin/pull/14437), [#14711](https://github.com/bitcoin/bitcoin/pull/14711), [#15288](https://github.com/bitcoin/bitcoin/pull/15288), and [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
-* [`ChainClient`](chain.h) — used by node to start & stop `Chain` clients. Added in [#10973](https://github.com/bitcoin/bitcoin/pull/10973).
+* [`ChainClient`](chain.h) — used by node to start & stop `Chain` clients. Added in [#14437](https://github.com/bitcoin/bitcoin/pull/14437).
* [`Node`](node.h) — used by GUI to start & stop bitcoin node. Added in [#10244](https://github.com/bitcoin/bitcoin/pull/10244).
diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp
index fb634e73da..161dd01ffe 100644
--- a/src/interfaces/chain.cpp
+++ b/src/interfaces/chain.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
@@ -6,22 +6,30 @@
#include <chain.h>
#include <chainparams.h>
+#include <interfaces/handler.h>
#include <interfaces/wallet.h>
#include <net.h>
+#include <node/coin.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/rbf.h>
+#include <policy/settings.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <protocol.h>
+#include <rpc/protocol.h>
+#include <rpc/server.h>
+#include <shutdown.h>
#include <sync.h>
#include <threadsafety.h>
#include <timedata.h>
#include <txmempool.h>
#include <ui_interface.h>
#include <uint256.h>
+#include <univalue.h>
#include <util/system.h>
#include <validation.h>
+#include <validationinterface.h>
#include <memory>
#include <utility>
@@ -29,11 +37,12 @@
namespace interfaces {
namespace {
-class LockImpl : public Chain::Lock
+class LockImpl : public Chain::Lock, public UniqueLock<CCriticalSection>
{
Optional<int> getHeight() override
{
- int height = ::chainActive.Height();
+ LockAssertion lock(::cs_main);
+ int height = ::ChainActive().Height();
if (height >= 0) {
return height;
}
@@ -41,8 +50,9 @@ class LockImpl : public Chain::Lock
}
Optional<int> getBlockHeight(const uint256& hash) override
{
+ LockAssertion lock(::cs_main);
CBlockIndex* block = LookupBlockIndex(hash);
- if (block && ::chainActive.Contains(block)) {
+ if (block && ::ChainActive().Contains(block)) {
return block->nHeight;
}
return nullopt;
@@ -55,54 +65,46 @@ class LockImpl : public Chain::Lock
}
uint256 getBlockHash(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
assert(block != nullptr);
return block->GetBlockHash();
}
int64_t getBlockTime(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
assert(block != nullptr);
return block->GetBlockTime();
}
int64_t getBlockMedianTimePast(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
assert(block != nullptr);
return block->GetMedianTimePast();
}
bool haveBlockOnDisk(int height) override
{
- CBlockIndex* block = ::chainActive[height];
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive()[height];
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
}
- Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
+ Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override
{
- CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
+ LockAssertion lock(::cs_main);
+ CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height);
if (block) {
if (hash) *hash = block->GetBlockHash();
return block->nHeight;
}
return nullopt;
}
- Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override
- {
- // TODO: Could update CChain::FindEarliestAtLeast() to take a height
- // parameter and use it with std::lower_bound() to make this
- // implementation more efficient and allow combining
- // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one
- // method.
- for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) {
- if (block->GetBlockTime() >= time) {
- return block->nHeight;
- }
- }
- return nullopt;
- }
Optional<int> findPruned(int start_height, Optional<int> stop_height) override
{
+ LockAssertion lock(::cs_main);
if (::fPruneMode) {
- CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip();
+ CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip();
while (block && block->nHeight >= start_height) {
if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
return block->nHeight;
@@ -114,8 +116,9 @@ class LockImpl : public Chain::Lock
}
Optional<int> findFork(const uint256& hash, Optional<int>* height) override
{
+ LockAssertion lock(::cs_main);
const CBlockIndex* block = LookupBlockIndex(hash);
- const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
+ const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr;
if (height) {
if (block) {
*height = block->nHeight;
@@ -128,37 +131,114 @@ class LockImpl : public Chain::Lock
}
return nullopt;
}
- bool isPotentialTip(const uint256& hash) override
+ CBlockLocator getTipLocator() override
{
- if (::chainActive.Tip()->GetBlockHash() == hash) return true;
- CBlockIndex* block = LookupBlockIndex(hash);
- return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
+ LockAssertion lock(::cs_main);
+ return ::ChainActive().GetLocator();
}
- CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); }
Optional<int> findLocatorFork(const CBlockLocator& locator) override
{
- LockAnnotation lock(::cs_main);
- if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
+ LockAssertion lock(::cs_main);
+ if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) {
return fork->nHeight;
}
return nullopt;
}
bool checkFinalTx(const CTransaction& tx) override
{
- LockAnnotation lock(::cs_main);
+ LockAssertion lock(::cs_main);
return CheckFinalTx(tx);
}
- bool submitToMemoryPool(CTransactionRef tx, CAmount absurd_fee, CValidationState& state) override
+ bool submitToMemoryPool(const CTransactionRef& tx, CAmount absurd_fee, CValidationState& state) override
{
- LockAnnotation lock(::cs_main);
+ LockAssertion lock(::cs_main);
return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */,
false /* bypass limits */, absurd_fee);
}
+
+ using UniqueLock::UniqueLock;
};
-class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
+class NotificationsHandlerImpl : public Handler, CValidationInterface
{
- using UniqueLock::UniqueLock;
+public:
+ explicit NotificationsHandlerImpl(Chain& chain, Chain::Notifications& notifications)
+ : m_chain(chain), m_notifications(&notifications)
+ {
+ RegisterValidationInterface(this);
+ }
+ ~NotificationsHandlerImpl() override { disconnect(); }
+ void disconnect() override
+ {
+ if (m_notifications) {
+ m_notifications = nullptr;
+ UnregisterValidationInterface(this);
+ }
+ }
+ void TransactionAddedToMempool(const CTransactionRef& tx) override
+ {
+ m_notifications->TransactionAddedToMempool(tx);
+ }
+ void TransactionRemovedFromMempool(const CTransactionRef& tx) override
+ {
+ m_notifications->TransactionRemovedFromMempool(tx);
+ }
+ void BlockConnected(const std::shared_ptr<const CBlock>& block,
+ const CBlockIndex* index,
+ const std::vector<CTransactionRef>& tx_conflicted) override
+ {
+ m_notifications->BlockConnected(*block, tx_conflicted);
+ }
+ void BlockDisconnected(const std::shared_ptr<const CBlock>& block) override
+ {
+ m_notifications->BlockDisconnected(*block);
+ }
+ void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
+ {
+ m_notifications->UpdatedBlockTip();
+ }
+ void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->ChainStateFlushed(locator); }
+ Chain& m_chain;
+ Chain::Notifications* m_notifications;
+};
+
+class RpcHandlerImpl : public Handler
+{
+public:
+ RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
+ {
+ m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
+ if (!m_wrapped_command) return false;
+ try {
+ return m_wrapped_command->actor(request, result, last_handler);
+ } catch (const UniValue& e) {
+ // If this is not the last handler and a wallet not found
+ // exception was thrown, return false so the next handler can
+ // try to handle the request. Otherwise, reraise the exception.
+ if (!last_handler) {
+ const UniValue& code = e["code"];
+ if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) {
+ return false;
+ }
+ }
+ throw;
+ }
+ };
+ ::tableRPC.appendCommand(m_command.name, &m_command);
+ }
+
+ void disconnect() override final
+ {
+ if (m_wrapped_command) {
+ m_wrapped_command = nullptr;
+ ::tableRPC.removeCommand(m_command.name, &m_command);
+ }
+ }
+
+ ~RpcHandlerImpl() override { disconnect(); }
+
+ CRPCCommand m_command;
+ const CRPCCommand* m_wrapped_command;
};
class ChainImpl : public Chain
@@ -166,13 +246,12 @@ class ChainImpl : public Chain
public:
std::unique_ptr<Chain::Lock> lock(bool try_lock) override
{
- auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
+ auto result = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
if (try_lock && result && !*result) return {};
// std::move necessary on some compilers due to conversion from
- // LockingStateImpl to Lock pointer
+ // LockImpl to Lock pointer
return std::move(result);
}
- std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
{
CBlockIndex* index;
@@ -194,6 +273,7 @@ public:
}
return true;
}
+ void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(coins); }
double guessVerificationProgress(const uint256& block_hash) override
{
LOCK(cs_main);
@@ -207,8 +287,8 @@ public:
bool hasDescendantsInMempool(const uint256& txid) override
{
LOCK(::mempool.cs);
- auto it_mp = ::mempool.mapTx.find(txid);
- return it_mp != ::mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1;
+ auto it = ::mempool.GetIter(txid);
+ return it && (*it)->GetCountWithDescendants() > 1;
}
void relayTransaction(const uint256& txid) override
{
@@ -219,7 +299,7 @@ public:
{
::mempool.GetTransactionAncestry(txid, ancestors, descendants);
}
- bool checkChainLimits(CTransactionRef tx) override
+ bool checkChainLimits(const CTransactionRef& tx) override
{
LockPoints lp;
CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
@@ -245,17 +325,59 @@ public:
{
return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
}
- CAmount maxTxFee() override { return ::maxTxFee; }
- bool getPruneMode() override { return ::fPruneMode; }
+ CFeeRate relayMinFee() override { return ::minRelayTxFee; }
+ CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
+ CFeeRate relayDustFee() override { return ::dustRelayFee; }
+ bool havePruned() override
+ {
+ LOCK(cs_main);
+ return ::fHavePruned;
+ }
bool p2pEnabled() override { return g_connman != nullptr; }
- bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
+ bool shutdownRequested() override { return ShutdownRequested(); }
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
void initWarning(const std::string& message) override { InitWarning(message); }
void initError(const std::string& message) override { InitError(message); }
void loadWallet(std::unique_ptr<Wallet> wallet) override { ::uiInterface.LoadWallet(wallet); }
+ void showProgress(const std::string& title, int progress, bool resume_possible) override
+ {
+ ::uiInterface.ShowProgress(title, progress, resume_possible);
+ }
+ std::unique_ptr<Handler> handleNotifications(Notifications& notifications) override
+ {
+ return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
+ }
+ void waitForNotificationsIfNewBlocksConnected(const uint256& old_tip) override
+ {
+ if (!old_tip.IsNull()) {
+ LOCK(::cs_main);
+ if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return;
+ CBlockIndex* block = LookupBlockIndex(old_tip);
+ if (block && block->GetAncestor(::ChainActive().Height()) == ::ChainActive().Tip()) return;
+ }
+ SyncWithValidationInterfaceQueue();
+ }
+ std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
+ {
+ return MakeUnique<RpcHandlerImpl>(command);
+ }
+ bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
+ void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
+ {
+ RPCRunLater(name, std::move(fn), seconds);
+ }
+ int rpcSerializationFlags() override { return RPCSerializationFlags(); }
+ void requestMempoolTransactions(Notifications& notifications) override
+ {
+ LOCK2(::cs_main, ::mempool.cs);
+ for (const CTxMemPoolEntry& entry : ::mempool.mapTx) {
+ notifications.TransactionAddedToMempool(entry.GetSharedTx());
+ }
+ }
};
-
} // namespace
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 60f8570e36..e675defd47 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
@@ -6,7 +6,6 @@
#define BITCOIN_INTERFACES_CHAIN_H
#include <optional.h> // For Optional and nullopt
-#include <policy/rbf.h> // For RBFTransactionState
#include <primitives/transaction.h> // For CTransactionRef
#include <memory>
@@ -16,17 +15,46 @@
#include <vector>
class CBlock;
+class CFeeRate;
+class CRPCCommand;
class CScheduler;
class CValidationState;
+class Coin;
class uint256;
+enum class RBFTransactionState;
struct CBlockLocator;
struct FeeCalculation;
namespace interfaces {
+class Handler;
class Wallet;
-//! Interface for giving wallet processes access to blockchain state.
+//! Interface giving clients (wallet processes, maybe other analysis tools in
+//! the future) ability to access to the chain state, receive notifications,
+//! estimate fees, and submit transactions.
+//!
+//! TODO: Current chain methods are too low level, exposing too much of the
+//! internal workings of the bitcoin node, and not being very convenient to use.
+//! Chain methods should be cleaned up and simplified over time. Examples:
+//!
+//! * The Chain::lock() method, which lets clients delay chain tip updates
+//! should be removed when clients are able to respond to updates
+//! asynchronously
+//! (https://github.com/bitcoin/bitcoin/pull/10973#issuecomment-380101269).
+//!
+//! * The relayTransactions() and submitToMemoryPool() methods could be replaced
+//! with a higher-level broadcastTransaction method
+//! (https://github.com/bitcoin/bitcoin/pull/14978#issuecomment-459373984).
+//!
+//! * The initMessages() and loadWallet() methods which the wallet uses to send
+//! notifications to the GUI should go away when GUI and wallet can directly
+//! communicate with each other without going through the node
+//! (https://github.com/bitcoin/bitcoin/pull/15288#discussion_r253321096).
+//!
+//! * The handleRpc, registerRpcs, rpcEnableDeprecated methods and other RPC
+//! methods can go away if wallets listen for HTTP requests on their own
+//! ports instead of registering to handle requests on the node HTTP port.
class Chain
{
public:
@@ -71,62 +99,45 @@ public:
virtual bool haveBlockOnDisk(int height) = 0;
//! Return height of the first block in the chain with timestamp equal
- //! or greater than the given time, or nullopt if there is no block with
- //! a high enough timestamp. Also return the block hash as an optional
- //! output parameter (to avoid the cost of a second lookup in case this
- //! information is needed.)
- virtual Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) = 0;
-
- //! Return height of the first block in the chain with timestamp equal
//! or greater than the given time and height equal or greater than the
- //! given height, or nullopt if there is no such block.
- //!
- //! Calling this with height 0 is equivalent to calling
- //! findFirstBlockWithTime, but less efficient because it requires a
- //! linear instead of a binary search.
- virtual Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) = 0;
+ //! given height, or nullopt if there is no block with a high enough
+ //! timestamp and height. Also return the block hash as an optional output parameter
+ //! (to avoid the cost of a second lookup in case this information is needed.)
+ virtual Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) = 0;
//! Return height of last block in the specified range which is pruned, or
//! nullopt if no block in the range is pruned. Range is inclusive.
virtual Optional<int> findPruned(int start_height = 0, Optional<int> stop_height = nullopt) = 0;
- //! Return height of the highest block on the chain that is an ancestor
- //! of the specified block, or nullopt if no common ancestor is found.
+ //! Return height of the specified block if it is on the chain, otherwise
+ //! return the height of the highest block on chain that's an ancestor
+ //! of the specified block, or nullopt if there is no common ancestor.
//! Also return the height of the specified block as an optional output
//! parameter (to avoid the cost of a second hash lookup in case this
//! information is desired).
virtual Optional<int> findFork(const uint256& hash, Optional<int>* height) = 0;
- //! Return true if block hash points to the current chain tip, or to a
- //! possible descendant of the current chain tip that isn't currently
- //! connected.
- virtual bool isPotentialTip(const uint256& hash) = 0;
-
//! Get locator for the current chain tip.
virtual CBlockLocator getTipLocator() = 0;
- //! Return height of the latest block common to locator and chain, which
- //! is guaranteed to be an ancestor of the block used to create the
- //! locator.
+ //! Return height of the highest block on chain in common with the locator,
+ //! which will either be the original block used to create the locator,
+ //! or one of its ancestors.
virtual Optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
//! Check if transaction will be final given chain height current time.
virtual bool checkFinalTx(const CTransaction& tx) = 0;
//! Add transaction to memory pool if the transaction fee is below the
- //! amount specified by absurd_fee (as a safeguard). */
- virtual bool submitToMemoryPool(CTransactionRef tx, CAmount absurd_fee, CValidationState& state) = 0;
+ //! amount specified by absurd_fee. Returns false if the transaction
+ //! could not be added due to the fee or for another reason.
+ virtual bool submitToMemoryPool(const CTransactionRef& tx, CAmount absurd_fee, CValidationState& state) = 0;
};
//! Return Lock interface. Chain is locked when this is called, and
//! unlocked when the returned interface is freed.
virtual std::unique_ptr<Lock> lock(bool try_lock = false) = 0;
- //! Return Lock interface assuming chain is already locked. This
- //! method is temporary and is only used in a few places to avoid changing
- //! behavior while code is transitioned to use the Chain::Lock interface.
- virtual std::unique_ptr<Lock> assumeLocked() = 0;
-
//! Return whether node has the block and optionally return block metadata
//! or contents.
//!
@@ -138,6 +149,11 @@ public:
int64_t* time = nullptr,
int64_t* max_time = nullptr) = 0;
+ //! Look up unspent output information. Returns coins in the mempool and in
+ //! the current chain UTXO set. Iterates through all the keys in the map and
+ //! populates the values.
+ virtual void findCoins(std::map<COutPoint, Coin>& coins) = 0;
+
//! Estimate fraction of total transactions verified if blocks up to
//! the specified block hash are verified.
virtual double guessVerificationProgress(const uint256& block_hash) = 0;
@@ -154,8 +170,8 @@ public:
//! Calculate mempool ancestor and descendant counts for the given transaction.
virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0;
- //! Check chain limits.
- virtual bool checkChainLimits(CTransactionRef tx) = 0;
+ //! Check if transaction will pass the mempool's chain limits.
+ virtual bool checkChainLimits(const CTransactionRef& tx) = 0;
//! Estimate smart fee.
virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc = nullptr) = 0;
@@ -163,24 +179,33 @@ public:
//! Fee estimator max target.
virtual unsigned int estimateMaxBlocks() = 0;
- //! Pool min fee.
+ //! Mempool minimum fee.
virtual CFeeRate mempoolMinFee() = 0;
- //! Get node max tx fee setting (-maxtxfee).
- //! This could be replaced by a per-wallet max fee, as proposed at
- //! https://github.com/bitcoin/bitcoin/issues/15355
- //! But for the time being, wallets call this to access the node setting.
- virtual CAmount maxTxFee() = 0;
+ //! Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
+ virtual CFeeRate relayMinFee() = 0;
- //! Check if pruning is enabled.
- virtual bool getPruneMode() = 0;
+ //! Relay incremental fee setting (-incrementalrelayfee), reflecting cost of relay.
+ virtual CFeeRate relayIncrementalFee() = 0;
+
+ //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
+ virtual CFeeRate relayDustFee() = 0;
+
+ //! Check if any block has been pruned.
+ virtual bool havePruned() = 0;
//! Check if p2p enabled.
virtual bool p2pEnabled() = 0;
- // Check if in IBD.
+ //! Check if the node is ready to broadcast transactions.
+ virtual bool isReadyToBroadcast() = 0;
+
+ //! Check if in IBD.
virtual bool isInitialBlockDownload() = 0;
+ //! Check if shutdown requested.
+ virtual bool shutdownRequested() = 0;
+
//! Get adjusted time.
virtual int64_t getAdjustedTime() = 0;
@@ -195,6 +220,53 @@ public:
//! Send wallet load notification to the GUI.
virtual void loadWallet(std::unique_ptr<Wallet> wallet) = 0;
+
+ //! Send progress indicator.
+ virtual void showProgress(const std::string& title, int progress, bool resume_possible) = 0;
+
+ //! Chain notifications.
+ class Notifications
+ {
+ public:
+ virtual ~Notifications() {}
+ virtual void TransactionAddedToMempool(const CTransactionRef& tx) {}
+ virtual void TransactionRemovedFromMempool(const CTransactionRef& ptx) {}
+ virtual void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& tx_conflicted) {}
+ virtual void BlockDisconnected(const CBlock& block) {}
+ virtual void UpdatedBlockTip() {}
+ virtual void ChainStateFlushed(const CBlockLocator& locator) {}
+ };
+
+ //! Register handler for notifications.
+ virtual std::unique_ptr<Handler> handleNotifications(Notifications& notifications) = 0;
+
+ //! Wait for pending notifications to be processed unless block hash points to the current
+ //! chain tip, or to a possible descendant of the current chain tip that isn't currently
+ //! connected.
+ virtual void waitForNotificationsIfNewBlocksConnected(const uint256& old_tip) = 0;
+
+ //! Register handler for RPC. Command is not copied, so reference
+ //! needs to remain valid until Handler is disconnected.
+ virtual std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) = 0;
+
+ //! Check if deprecated RPC is enabled.
+ virtual bool rpcEnableDeprecated(const std::string& method) = 0;
+
+ //! Run function after given number of seconds. Cancel any previous calls with same name.
+ virtual void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) = 0;
+
+ //! Current RPC serialization flags.
+ virtual int rpcSerializationFlags() = 0;
+
+ //! Synchronously send TransactionAddedToMempool notifications about all
+ //! current mempool transactions to the specified handler and return after
+ //! the last one is sent. These notifications aren't coordinated with async
+ //! notifications sent by handleNotifications, so out of date async
+ //! notifications from handleNotifications can arrive during and after
+ //! synchronous notifications from requestMempoolTransactions. Clients need
+ //! to be prepared to handle this by ignoring notifications about unknown
+ //! removed transactions and already added new transactions.
+ virtual void requestMempoolTransactions(Notifications& notifications) = 0;
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp
index 6f7dce0c24..584d218dba 100644
--- a/src/interfaces/node.cpp
+++ b/src/interfaces/node.cpp
@@ -20,9 +20,9 @@
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/policy.h>
+#include <policy/settings.h>
#include <primitives/block.h>
#include <rpc/server.h>
-#include <scheduler.h>
#include <shutdown.h>
#include <sync.h>
#include <txmempool.h>
@@ -177,13 +177,13 @@ public:
int getNumBlocks() override
{
LOCK(::cs_main);
- return ::chainActive.Height();
+ return ::ChainActive().Height();
}
int64_t getLastBlockTime() override
{
LOCK(::cs_main);
- if (::chainActive.Tip()) {
- return ::chainActive.Tip()->GetBlockTime();
+ if (::ChainActive().Tip()) {
+ return ::ChainActive().Tip()->GetBlockTime();
}
return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
}
@@ -192,11 +192,11 @@ public:
const CBlockIndex* tip;
{
LOCK(::cs_main);
- tip = ::chainActive.Tip();
+ tip = ::ChainActive().Tip();
}
return GuessVerificationProgress(Params().TxData(), tip);
}
- bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
+ bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
bool getReindex() override { return ::fReindex; }
bool getImporting() override { return ::fImporting; }
void setNetworkActive(bool active) override
@@ -206,7 +206,6 @@ public:
}
}
bool getNetworkActive() override { return g_connman && g_connman->GetNetworkActive(); }
- CAmount getMaxTxFee() override { return ::maxTxFee; }
CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
{
FeeCalculation fee_calc;
diff --git a/src/interfaces/node.h b/src/interfaces/node.h
index 76b93af234..1ccd2a31b7 100644
--- a/src/interfaces/node.h
+++ b/src/interfaces/node.h
@@ -159,9 +159,6 @@ public:
//! Get network active.
virtual bool getNetworkActive() = 0;
- //! Get max tx fee.
- virtual CAmount getMaxTxFee() = 0;
-
//! Estimate smart fee.
virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0;
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 7abbee0912..34c982e1e6 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -5,30 +5,23 @@
#include <interfaces/wallet.h>
#include <amount.h>
-#include <chain.h>
#include <consensus/validation.h>
-#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
-#include <net.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
#include <primitives/transaction.h>
-#include <rpc/server.h>
-#include <scheduler.h>
-#include <script/ismine.h>
#include <script/standard.h>
#include <support/allocators/secure.h>
#include <sync.h>
-#include <timedata.h>
#include <ui_interface.h>
#include <uint256.h>
#include <util/system.h>
-#include <validation.h>
#include <wallet/feebumper.h>
#include <wallet/fees.h>
+#include <wallet/ismine.h>
#include <wallet/rpcwallet.h>
+#include <wallet/load.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>
@@ -47,8 +40,6 @@ public:
const CTransaction& get() override { return *m_tx; }
- int64_t getVirtualSize() override { return GetVirtualTransactionSize(*m_tx); }
-
bool commit(WalletValueMap value_map,
WalletOrderForm order_form,
std::string& reject_reason) override
@@ -99,12 +90,8 @@ WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, co
//! Construct wallet tx status struct.
WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock& locked_chain, const CWalletTx& wtx)
{
- LockAnnotation lock(::cs_main); // Temporary, for mapBlockIndex below. Removed in upcoming commit.
-
WalletTxStatus result;
- auto mi = ::mapBlockIndex.find(wtx.hashBlock);
- CBlockIndex* block = mi != ::mapBlockIndex.end() ? mi->second : nullptr;
- result.block_height = (block ? block->nHeight : std::numeric_limits<int>::max());
+ result.block_height = locked_chain.getBlockHeight(wtx.hashBlock).get_value_or(std::numeric_limits<int>::max());
result.blocks_to_maturity = wtx.GetBlocksToMaturity(locked_chain);
result.depth_in_main_chain = wtx.GetDepthInMainChain(locked_chain);
result.time_received = wtx.nTimeReceived;
@@ -274,8 +261,13 @@ public:
CAmount& new_fee,
CMutableTransaction& mtx) override
{
- return feebumper::CreateTransaction(m_wallet.get(), txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) ==
- feebumper::Result::OK;
+ if (total_fee > 0) {
+ return feebumper::CreateTotalBumpTransaction(m_wallet.get(), txid, coin_control, total_fee, errors, old_fee, new_fee, mtx) ==
+ feebumper::Result::OK;
+ } else {
+ return feebumper::CreateRateBumpTransaction(m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) ==
+ feebumper::Result::OK;
+ }
}
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(m_wallet.get(), mtx); }
bool commitBumpTransaction(const uint256& txid,
@@ -364,15 +356,16 @@ public:
}
WalletBalances getBalances() override
{
+ const auto bal = m_wallet->GetBalance();
WalletBalances result;
- result.balance = m_wallet->GetBalance();
- result.unconfirmed_balance = m_wallet->GetUnconfirmedBalance();
- result.immature_balance = m_wallet->GetImmatureBalance();
+ result.balance = bal.m_mine_trusted;
+ result.unconfirmed_balance = bal.m_mine_untrusted_pending;
+ result.immature_balance = bal.m_mine_immature;
result.have_watch_only = m_wallet->HaveWatchOnly();
if (result.have_watch_only) {
- result.watch_only_balance = m_wallet->GetBalance(ISMINE_WATCH_ONLY);
- result.unconfirmed_watch_only_balance = m_wallet->GetUnconfirmedWatchOnlyBalance();
- result.immature_watch_only_balance = m_wallet->GetImmatureWatchOnlyBalance();
+ result.watch_only_balance = bal.m_watchonly_trusted;
+ result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
+ result.immature_watch_only_balance = bal.m_watchonly_immature;
}
return result;
}
@@ -388,7 +381,7 @@ public:
num_blocks = locked_chain->getHeight().get_value_or(-1);
return true;
}
- CAmount getBalance() override { return m_wallet->GetBalance(); }
+ CAmount getBalance() override { return m_wallet->GetBalance().m_mine_trusted; }
CAmount getAvailableBalance(const CCoinControl& coin_control) override
{
return m_wallet->GetAvailableBalance(&coin_control);
@@ -468,6 +461,7 @@ public:
bool IsWalletFlagSet(uint64_t flag) override { return m_wallet->IsWalletFlagSet(flag); }
OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; }
OutputType getDefaultChangeType() override { return m_wallet->m_default_change_type; }
+ CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
void remove() override
{
RemoveWallet(m_wallet);
@@ -514,7 +508,7 @@ public:
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
{
}
- void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); }
+ void registerRpcs() override { return RegisterWalletRPCCommands(m_chain, m_rpc_handlers); }
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
@@ -524,6 +518,7 @@ public:
Chain& m_chain;
std::vector<std::string> m_wallet_filenames;
+ std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
};
} // namespace
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index a931e5fafb..9c9b29a813 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -7,7 +7,6 @@
#include <amount.h> // For CAmount
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
-#include <script/ismine.h> // For isminefilter, isminetype
#include <script/standard.h> // For CTxDestination
#include <support/allocators/secure.h> // For SecureString
#include <ui_interface.h> // For ChangeType
@@ -25,7 +24,10 @@ class CCoinControl;
class CFeeRate;
class CKey;
class CWallet;
+enum isminetype : unsigned int;
enum class FeeReason;
+typedef uint8_t isminefilter;
+
enum class OutputType;
struct CRecipient;
@@ -247,6 +249,9 @@ public:
// Get default change type.
virtual OutputType getDefaultChangeType() = 0;
+ //! Get max tx fee.
+ virtual CAmount getDefaultMaxTxFee() = 0;
+
// Remove wallet.
virtual void remove() = 0;
@@ -292,9 +297,6 @@ public:
//! Get transaction data.
virtual const CTransaction& get() = 0;
- //! Get virtual transaction size.
- virtual int64_t getVirtualSize() = 0;
-
//! Send pending transaction and commit to wallet.
virtual bool commit(WalletValueMap value_map,
WalletOrderForm order_form,
diff --git a/src/key.cpp b/src/key.cpp
index 9d982fc44f..3ba21753a2 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -5,7 +5,6 @@
#include <key.h>
-#include <arith_uint256.h>
#include <crypto/common.h>
#include <crypto/hmac_sha512.h>
#include <random.h>
@@ -163,6 +162,12 @@ void CKey::MakeNewKey(bool fCompressedIn) {
fCompressed = fCompressedIn;
}
+bool CKey::Negate()
+{
+ assert(fValid);
+ return secp256k1_ec_privkey_negate(secp256k1_context_sign, keydata.data());
+}
+
CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
diff --git a/src/key.h b/src/key.h
index 0f695c07b7..67e2cfc094 100644
--- a/src/key.h
+++ b/src/key.h
@@ -98,6 +98,9 @@ public:
//! Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed);
+ //! Negate private key
+ bool Negate();
+
/**
* Convert the private key to a CPrivKey (serialized OpenSSL private key data).
* This is expensive.
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 1d53a5e074..cd41a93549 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -26,14 +26,14 @@ private:
public:
explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
- std::string operator()(const CKeyID& id) const
+ std::string operator()(const PKHash& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
return EncodeBase58Check(data);
}
- std::string operator()(const CScriptID& id) const
+ std::string operator()(const ScriptHash& id) const
{
std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
data.insert(data.end(), id.begin(), id.end());
@@ -81,14 +81,14 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
- return CKeyID(hash);
+ return PKHash(hash);
}
// Script-hash-addresses have version 5 (or 196 testnet).
// The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
- return CScriptID(hash);
+ return ScriptHash(hash);
}
}
data.clear();
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 148979cf35..f6d19416ce 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -178,16 +178,17 @@ CKeyID GetKeyForDestination(const CKeyStore& store, const CTxDestination& dest)
{
// Only supports destinations which map to single public keys, i.e. P2PKH,
// P2WPKH, and P2SH-P2WPKH.
- if (auto id = boost::get<CKeyID>(&dest)) {
- return *id;
+ if (auto id = boost::get<PKHash>(&dest)) {
+ return CKeyID(*id);
}
if (auto witness_id = boost::get<WitnessV0KeyHash>(&dest)) {
return CKeyID(*witness_id);
}
- if (auto script_id = boost::get<CScriptID>(&dest)) {
+ if (auto script_hash = boost::get<ScriptHash>(&dest)) {
CScript script;
+ CScriptID script_id(*script_hash);
CTxDestination inner_dest;
- if (store.GetCScript(*script_id, script) && ExtractDestination(script, inner_dest)) {
+ if (store.GetCScript(script_id, script) && ExtractDestination(script, inner_dest)) {
if (auto inner_witness_id = boost::get<WitnessV0KeyHash>(&inner_dest)) {
return CKeyID(*inner_witness_id);
}
diff --git a/src/logging.cpp b/src/logging.cpp
index 36cad6573a..dc2d130a2a 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -4,8 +4,11 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <logging.h>
+#include <util/threadnames.h>
#include <util/time.h>
+#include <mutex>
+
const char * const DEFAULT_DEBUGLOGFILE = "debug.log";
BCLog::Logger& LogInstance()
@@ -36,28 +39,50 @@ static int FileWriteStr(const std::string &str, FILE *fp)
return fwrite(str.data(), 1, str.size(), fp);
}
-bool BCLog::Logger::OpenDebugLog()
+bool BCLog::Logger::StartLogging()
{
- std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ assert(m_buffering);
assert(m_fileout == nullptr);
- assert(!m_file_path.empty());
- m_fileout = fsbridge::fopen(m_file_path, "a");
- if (!m_fileout) {
- return false;
+ if (m_print_to_file) {
+ assert(!m_file_path.empty());
+ m_fileout = fsbridge::fopen(m_file_path, "a");
+ if (!m_fileout) {
+ return false;
+ }
+
+ setbuf(m_fileout, nullptr); // unbuffered
+
+ // Add newlines to the logfile to distinguish this execution from the
+ // last one.
+ FileWriteStr("\n\n\n\n\n", m_fileout);
}
- setbuf(m_fileout, nullptr); // unbuffered
// dump buffered messages from before we opened the log
+ m_buffering = false;
while (!m_msgs_before_open.empty()) {
- FileWriteStr(m_msgs_before_open.front(), m_fileout);
+ const std::string& s = m_msgs_before_open.front();
+
+ if (m_print_to_file) FileWriteStr(s, m_fileout);
+ if (m_print_to_console) fwrite(s.data(), 1, s.size(), stdout);
+
m_msgs_before_open.pop_front();
}
+ if (m_print_to_console) fflush(stdout);
return true;
}
+void BCLog::Logger::DisconnectTestLogger()
+{
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ m_buffering = true;
+ if (m_fileout != nullptr) fclose(m_fileout);
+ m_fileout = nullptr;
+}
+
void BCLog::Logger::EnableCategory(BCLog::LogFlags flag)
{
m_categories |= flag;
@@ -174,7 +199,7 @@ std::vector<CLogCategoryActive> ListActiveLogCategories()
return ret;
}
-std::string BCLog::Logger::LogTimestampStr(const std::string &str)
+std::string BCLog::Logger::LogTimestampStr(const std::string& str)
{
std::string strStamped;
@@ -196,44 +221,47 @@ std::string BCLog::Logger::LogTimestampStr(const std::string &str)
} else
strStamped = str;
- if (!str.empty() && str[str.size()-1] == '\n')
- m_started_new_line = true;
- else
- m_started_new_line = false;
-
return strStamped;
}
-void BCLog::Logger::LogPrintStr(const std::string &str)
+void BCLog::Logger::LogPrintStr(const std::string& str)
{
- std::string strTimestamped = LogTimestampStr(str);
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ std::string str_prefixed = str;
+
+ if (m_log_threadnames && m_started_new_line) {
+ str_prefixed.insert(0, "[" + util::ThreadGetInternalName() + "] ");
+ }
+
+ str_prefixed = LogTimestampStr(str_prefixed);
+
+ m_started_new_line = !str.empty() && str[str.size()-1] == '\n';
+
+ if (m_buffering) {
+ // buffer if we haven't started logging yet
+ m_msgs_before_open.push_back(str_prefixed);
+ return;
+ }
if (m_print_to_console) {
// print to console
- fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
+ fwrite(str_prefixed.data(), 1, str_prefixed.size(), stdout);
fflush(stdout);
}
if (m_print_to_file) {
- std::lock_guard<std::mutex> scoped_lock(m_file_mutex);
-
- // buffer if we haven't opened the log yet
- if (m_fileout == nullptr) {
- m_msgs_before_open.push_back(strTimestamped);
- }
- else
- {
- // reopen the log file, if requested
- if (m_reopen_file) {
- m_reopen_file = false;
- FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
- if (new_fileout) {
- setbuf(new_fileout, nullptr); // unbuffered
- fclose(m_fileout);
- m_fileout = new_fileout;
- }
+ assert(m_fileout != nullptr);
+
+ // reopen the log file, if requested
+ if (m_reopen_file) {
+ m_reopen_file = false;
+ FILE* new_fileout = fsbridge::fopen(m_file_path, "a");
+ if (new_fileout) {
+ setbuf(new_fileout, nullptr); // unbuffered
+ fclose(m_fileout);
+ m_fileout = new_fileout;
}
- FileWriteStr(strTimestamped, m_fileout);
}
+ FileWriteStr(str_prefixed, m_fileout);
}
}
diff --git a/src/logging.h b/src/logging.h
index ac9d0dc0c7..75cd5353c0 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -19,6 +19,7 @@
static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true;
+static const bool DEFAULT_LOGTHREADNAMES = false;
extern const char * const DEFAULT_DEBUGLOGFILE;
extern bool fLogIPs;
@@ -59,9 +60,10 @@ namespace BCLog {
class Logger
{
private:
- FILE* m_fileout = nullptr;
- std::mutex m_file_mutex;
- std::list<std::string> m_msgs_before_open;
+ mutable std::mutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected
+ FILE* m_fileout = nullptr; // GUARDED_BY(m_cs)
+ std::list<std::string> m_msgs_before_open; // GUARDED_BY(m_cs)
+ bool m_buffering{true}; //!< Buffer messages before logging can be started. GUARDED_BY(m_cs)
/**
* m_started_new_line is a state variable that will suppress printing of
@@ -81,17 +83,26 @@ namespace BCLog {
bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS;
bool m_log_time_micros = DEFAULT_LOGTIMEMICROS;
+ bool m_log_threadnames = DEFAULT_LOGTHREADNAMES;
fs::path m_file_path;
std::atomic<bool> m_reopen_file{false};
/** Send a string to the log output */
- void LogPrintStr(const std::string &str);
+ void LogPrintStr(const std::string& str);
/** Returns whether logs will be written to any output */
- bool Enabled() const { return m_print_to_console || m_print_to_file; }
+ bool Enabled() const
+ {
+ std::lock_guard<std::mutex> scoped_lock(m_cs);
+ return m_buffering || m_print_to_console || m_print_to_file;
+ }
+
+ /** Start logging (and flush all buffered messages) */
+ bool StartLogging();
+ /** Only for testing */
+ void DisconnectTestLogger();
- bool OpenDebugLog();
void ShrinkDebugFile();
uint32_t GetCategoryMask() const { return m_categories.load(); }
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index a54268d655..052aebbc80 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -7,7 +7,6 @@
#include <hash.h>
#include <consensus/consensus.h>
-#include <util/strencodings.h>
CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter* filter, const std::set<uint256>* txids)
diff --git a/src/miner.cpp b/src/miner.cpp
index 80a2f8f018..015645c9c6 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -13,8 +13,6 @@
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
-#include <hash.h>
-#include <net.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <pow.h>
@@ -23,7 +21,7 @@
#include <timedata.h>
#include <util/moneystr.h>
#include <util/system.h>
-#include <validationinterface.h>
+#include <util/validation.h>
#include <algorithm>
#include <queue>
@@ -108,7 +106,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
LOCK2(cs_main, mempool.cs);
- CBlockIndex* pindexPrev = chainActive.Tip();
+ CBlockIndex* pindexPrev = ::ChainActive().Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
diff --git a/src/net.cpp b/src/net.cpp
index 87f1ef0577..75a47d7ad2 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -79,7 +79,7 @@ static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // S
//
bool fDiscover = true;
bool fListen = true;
-bool fRelayTxes = true;
+bool g_relay_txes = !DEFAULT_BLOCKSONLY;
CCriticalSection cs_mapLocalHost;
std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost);
static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {};
@@ -1765,9 +1765,15 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
addr = addrman.Select(fFeeler);
}
- // if we selected an invalid address, restart
- if (!addr.IsValid() || setConnected.count(addr.GetGroup()) || IsLocal(addr))
+ // Require outbound connections, other than feelers, to be to distinct network groups
+ if (!fFeeler && setConnected.count(addr.GetGroup())) {
break;
+ }
+
+ // if we selected an invalid or local address, restart
+ if (!addr.IsValid() || IsLocal(addr)) {
+ break;
+ }
// If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,
// stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates
@@ -2281,8 +2287,8 @@ public:
WSACleanup();
#endif
}
-}
-instance_of_cnetcleanup;
+};
+static CNetCleanup instance_of_cnetcleanup;
void CConnman::Interrupt()
{
@@ -2621,7 +2627,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
{
hSocket = hSocketIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
- strSubVer = "";
hashContinue = uint256();
filterInventoryKnown.reset();
pfilter = MakeUnique<CBloomFilter>();
diff --git a/src/net.h b/src/net.h
index f4a90e01f1..37aaf1a63b 100644
--- a/src/net.h
+++ b/src/net.h
@@ -53,7 +53,7 @@ static const unsigned int MAX_LOCATOR_SZ = 101;
static const unsigned int MAX_ADDR_TO_SEND = 1000;
/** Maximum length of incoming protocol messages (no message over 4 MB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1000 * 1000;
-/** Maximum length of strSubVer in `version` message */
+/** Maximum length of the user agent string in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** Maximum number of automatic outgoing nodes */
static const int MAX_OUTBOUND_CONNECTIONS = 8;
@@ -519,7 +519,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
extern bool fDiscover;
extern bool fListen;
-extern bool fRelayTxes;
+extern bool g_relay_txes;
/** Subversion as sent to the P2P network in `version` messages */
extern std::string strSubVersion;
@@ -650,12 +650,12 @@ public:
// Bind address of our side of the connection
const CAddress addrBind;
std::atomic<int> nVersion{0};
- // strSubVer is whatever byte array we read from the wire. However, this field is intended
- // to be printed out, displayed to humans in various forms and so on. So we sanitize it and
- // store the sanitized version in cleanSubVer. The original should be used when dealing with
- // the network or wire types and the cleaned string used when displayed or logged.
- std::string strSubVer GUARDED_BY(cs_SubVer), cleanSubVer GUARDED_BY(cs_SubVer);
- CCriticalSection cs_SubVer; // used for both cleanSubVer and strSubVer
+ RecursiveMutex cs_SubVer;
+ /**
+ * cleanSubVer is a sanitized string of the user agent byte array we read
+ * from the wire. This cleaned string can safely be logged or displayed.
+ */
+ std::string cleanSubVer GUARDED_BY(cs_SubVer){};
bool m_prefer_evict{false}; // This peer is preferred for eviction.
bool fWhitelisted{false}; // This peer can bypass DoS banning.
bool fFeeler{false}; // If true this node is being used as a short lived feeler.
@@ -739,6 +739,8 @@ public:
CAmount lastSentFeeFilter{0};
int64_t nextSendTimeFeeFilter{0};
+ std::set<uint256> orphan_work_set;
+
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 = "", bool fInboundIn = false);
~CNode();
CNode(const CNode&) = delete;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 18dd2f010c..4b43b2cdf2 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -25,10 +25,9 @@
#include <scheduler.h>
#include <tinyformat.h>
#include <txmempool.h>
-#include <ui_interface.h>
#include <util/system.h>
-#include <util/moneystr.h>
#include <util/strencodings.h>
+#include <util/validation.h>
#include <memory>
@@ -69,11 +68,13 @@ static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100;
/** Maximum number of announced transactions from a peer */
static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 2 * MAX_INV_SZ;
/** How many microseconds to delay requesting transactions from inbound peers */
-static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000;
+static constexpr int64_t INBOUND_PEER_TX_DELAY = 2 * 1000000; // 2 seconds
/** How long to wait (in microseconds) before downloading a transaction from an additional peer */
-static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000;
+static constexpr int64_t GETDATA_TX_INTERVAL = 60 * 1000000; // 1 minute
/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */
-static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000;
+static constexpr int64_t MAX_GETDATA_RANDOM_DELAY = 2 * 1000000; // 2 seconds
+/** How long to wait (in microseconds) before expiring an in-flight getdata request to a peer */
+static constexpr int64_t TX_EXPIRY_INTERVAL = 10 * GETDATA_TX_INTERVAL;
static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY,
"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY");
/** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */
@@ -175,8 +176,6 @@ namespace {
/** Expiration-time ordered list of (expire time, relay map entry) pairs. */
std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration GUARDED_BY(cs_main);
- std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
-
struct IteratorComparator
{
template<typename I>
@@ -346,13 +345,25 @@ struct CNodeState {
//! Store all the transactions a peer has recently announced
std::set<uint256> m_tx_announced;
- //! Store transactions which were requested by us
- std::set<uint256> m_tx_in_flight;
+ //! Store transactions which were requested by us, with timestamp
+ std::map<uint256, int64_t> m_tx_in_flight;
+
+ //! Periodically check for stuck getdata requests
+ int64_t m_check_expiry_timer{0};
};
TxDownloadState m_tx_download;
- CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) {
+ //! Whether this peer is an inbound connection
+ bool m_is_inbound;
+
+ //! Whether this peer is a manual connection
+ bool m_is_manual_connection;
+
+ CNodeState(CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) :
+ address(addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound),
+ m_is_manual_connection (is_manual)
+ {
fCurrentlyConnected = false;
nMisbehavior = 0;
fShouldBan = false;
@@ -414,7 +425,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
CAddress addrMe = CAddress(CService(), nLocalNodeServices);
connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
- nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes));
+ nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes));
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);
@@ -571,7 +582,7 @@ static bool TipMayBeStale(const Consensus::Params &consensusParams) EXCLUSIVE_LO
static bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
+ return ::ChainActive().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
}
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -597,7 +608,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < ::ChainActive().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting.
return;
}
@@ -605,7 +616,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
if (state->pindexLastCommonBlock == nullptr) {
// Bootstrap quickly by guessing a parent of our best tip is the forking point.
// Guessing wrong in either direction is not a problem.
- state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())];
+ state->pindexLastCommonBlock = ::ChainActive()[std::min(state->pindexBestKnownBlock->nHeight, ::ChainActive().Height())];
}
// If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
@@ -647,7 +658,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec
// We wouldn't download this block or its descendants from this peer.
return;
}
- if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
+ if (pindex->nStatus & BLOCK_HAVE_DATA || ::ChainActive().Contains(pindex)) {
if (pindex->HaveTxsDownloaded())
state->pindexLastCommonBlock = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
@@ -696,30 +707,40 @@ void UpdateTxRequestTime(const uint256& txid, int64_t request_time) EXCLUSIVE_LO
}
}
-
-void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+int64_t CalculateTxGetDataTime(const uint256& txid, int64_t current_time, bool use_inbound_delay) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- CNodeState::TxDownloadState& peer_download_state = state->m_tx_download;
- if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS || peer_download_state.m_tx_announced.count(txid)) {
- // Too many queued announcements from this peer, or we already have
- // this announcement
- return;
- }
- peer_download_state.m_tx_announced.insert(txid);
-
int64_t process_time;
int64_t last_request_time = GetTxRequestTime(txid);
// First time requesting this tx
if (last_request_time == 0) {
- process_time = nNow;
+ process_time = current_time;
} else {
// Randomize the delay to avoid biasing some peers over others (such as due to
// fixed ordering of peer processing in ThreadMessageHandler)
process_time = last_request_time + GETDATA_TX_INTERVAL + GetRand(MAX_GETDATA_RANDOM_DELAY);
}
- // We delay processing announcements from non-preferred (eg inbound) peers
- if (!state->fPreferredDownload) process_time += INBOUND_PEER_TX_DELAY;
+ // We delay processing announcements from inbound peers
+ if (use_inbound_delay) process_time += INBOUND_PEER_TX_DELAY;
+
+ return process_time;
+}
+
+void RequestTx(CNodeState* state, const uint256& txid, int64_t nNow) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ CNodeState::TxDownloadState& peer_download_state = state->m_tx_download;
+ if (peer_download_state.m_tx_announced.size() >= MAX_PEER_TX_ANNOUNCEMENTS ||
+ peer_download_state.m_tx_process_time.size() >= MAX_PEER_TX_ANNOUNCEMENTS ||
+ peer_download_state.m_tx_announced.count(txid)) {
+ // Too many queued announcements from this peer, or we already have
+ // this announcement
+ return;
+ }
+ peer_download_state.m_tx_announced.insert(txid);
+
+ // Calculate the time to try requesting this transaction. Use
+ // fPreferredDownload as a proxy for outbound peers.
+ int64_t process_time = CalculateTxGetDataTime(txid, nNow, !state->fPreferredDownload);
peer_download_state.m_tx_process_time.emplace(process_time, txid);
}
@@ -748,7 +769,7 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
NodeId nodeid = pnode->GetId();
{
LOCK(cs_main);
- mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName)));
+ mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->fInbound, pnode->m_manual_connection));
}
if(!pnode->fInbound)
PushNodeVersion(pnode, connman, GetTime());
@@ -960,6 +981,90 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
LogPrint(BCLog::NET, "%s: %s peer=%d (%d -> %d)%s\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior, message_prefixed);
}
+/**
+ * Returns true if the given validation state result may result in a peer
+ * banning/disconnecting us. We use this to determine which unaccepted
+ * transactions from a whitelisted peer that we can safely relay.
+ */
+static bool TxRelayMayResultInDisconnect(const CValidationState& state)
+{
+ assert(IsTransactionReason(state.GetReason()));
+ return state.GetReason() == ValidationInvalidReason::CONSENSUS;
+}
+
+/**
+ * Potentially ban a node based on the contents of a CValidationState 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)
+ *
+ * Changes here may need to be reflected in TxRelayMayResultInDisconnect().
+ */
+static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") {
+ switch (state.GetReason()) {
+ case ValidationInvalidReason::NONE:
+ break;
+ // The node is providing invalid data:
+ case ValidationInvalidReason::CONSENSUS:
+ case ValidationInvalidReason::BLOCK_MUTATED:
+ if (!via_compact_block) {
+ LOCK(cs_main);
+ Misbehaving(nodeid, 100, message);
+ return true;
+ }
+ break;
+ case ValidationInvalidReason::CACHED_INVALID:
+ {
+ LOCK(cs_main);
+ CNodeState *node_state = State(nodeid);
+ if (node_state == nullptr) {
+ break;
+ }
+
+ // Ban outbound (but not inbound) peers if on an invalid chain.
+ // Exempt HB compact block peers and manual connections.
+ if (!via_compact_block && !node_state->m_is_inbound && !node_state->m_is_manual_connection) {
+ Misbehaving(nodeid, 100, message);
+ return true;
+ }
+ break;
+ }
+ case ValidationInvalidReason::BLOCK_INVALID_HEADER:
+ case ValidationInvalidReason::BLOCK_CHECKPOINT:
+ case ValidationInvalidReason::BLOCK_INVALID_PREV:
+ {
+ LOCK(cs_main);
+ Misbehaving(nodeid, 100, message);
+ }
+ return true;
+ // Conflicting (but not necessarily invalid) data or different policy:
+ case ValidationInvalidReason::BLOCK_MISSING_PREV:
+ {
+ // TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
+ LOCK(cs_main);
+ Misbehaving(nodeid, 10, message);
+ }
+ return true;
+ case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
+ case ValidationInvalidReason::BLOCK_TIME_FUTURE:
+ case ValidationInvalidReason::TX_NOT_STANDARD:
+ case ValidationInvalidReason::TX_MISSING_INPUTS:
+ case ValidationInvalidReason::TX_PREMATURE_SPEND:
+ case ValidationInvalidReason::TX_WITNESS_MUTATED:
+ case ValidationInvalidReason::TX_CONFLICT:
+ case ValidationInvalidReason::TX_MEMPOOL_POLICY:
+ break;
+ }
+ if (message != "") {
+ LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
+ }
+ return false;
+}
+
@@ -979,7 +1084,7 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
- if (chainActive.Contains(pindex)) return true;
+ if (::ChainActive().Contains(pindex)) return true;
return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
(pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
@@ -1091,7 +1196,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
/**
* Update our best height and announce any block hashes which weren't previously
- * in chainActive to our peers.
+ * in ::ChainActive() to our peers.
*/
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
const int nNewHeight = pindexNew->nHeight;
@@ -1121,8 +1226,6 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
});
connman->WakeMessageHandler();
}
-
- nTimeBestReceived = GetTime();
}
/**
@@ -1135,14 +1238,12 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
const uint256 hash(block.GetHash());
std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash);
- int nDoS = 0;
- if (state.IsInvalid(nDoS)) {
+ if (state.IsInvalid()) {
// Don't send reject message with code 0 or an internal reject code.
if (it != mapBlockSource.end() && State(it->second.first) && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) {
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};
State(it->second.first)->rejects.push_back(reject);
- if (nDoS > 0 && it->second.second)
- Misbehaving(it->second.first, nDoS);
+ MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
}
}
// Check that:
@@ -1152,7 +1253,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
// the tip yet so we have no way to check this directly here. Instead we
// just check that there are currently no other blocks in flight.
else if (state.IsValid() &&
- !IsInitialBlockDownload() &&
+ !::ChainstateActive().IsInitialBlockDownload() &&
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) {
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman);
@@ -1176,13 +1277,13 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
case MSG_WITNESS_TX:
{
assert(recentRejects);
- if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
+ if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip)
{
// If the chain tip has changed previously rejected transactions
// might be now valid, e.g. due to a nLockTime'd tx becoming valid,
// or a double-spend. Reset the rejects filter and give those
// txs a second chance.
- hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash();
+ hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash();
recentRejects->reset();
}
@@ -1307,7 +1408,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
if (send && !pfrom->fWhitelisted && (
- (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
+ (((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
@@ -1377,7 +1478,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
// instead we respond with the full, non-compact block.
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
- if (CanDirectFetch(consensusParams) && pindex->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
+ if (CanDirectFetch(consensusParams) && pindex->nHeight >= ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) {
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else {
@@ -1397,7 +1498,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
// 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()));
+ vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash()));
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::INV, vInv));
pfrom->hashContinue.SetNull();
}
@@ -1454,16 +1555,28 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
}
}
+ // Unknown types in the GetData stay in vRecvGetData and block any future
+ // message from this peer, see vRecvGetData check in ProcessMessages().
+ // Depending on future p2p changes, we might either drop unknown getdata on
+ // the floor or disconnect the peer.
+
pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);
if (!vNotFound.empty()) {
// Let the peer know that we didn't find what it asked for, so it doesn't
- // have to wait around forever. Currently only SPV clients actually care
- // about this message: it's needed when they are recursively walking the
- // dependencies of relevant unconfirmed transactions. SPV clients want to
- // do that because they want to know about (and store and rebroadcast and
- // risk analyze) the dependencies of transactions relevant to them, without
- // having to download the entire memory pool.
+ // have to wait around forever.
+ // SPV clients care about this message: it's needed when they are
+ // recursively walking the dependencies of relevant unconfirmed
+ // transactions. SPV clients want to do that because they want to know
+ // about (and store and rebroadcast and risk analyze) the dependencies
+ // of transactions relevant to them, without having to download the
+ // entire memory pool.
+ // Also, other nodes can use these messages to automatically request a
+ // transaction from some other peer that annnounced it, and stop
+ // waiting for us to respond.
+ // In normal operation, we often send NOTFOUND messages for parents of
+ // transactions that we relay; if a peer is missing a parent, they may
+ // assume we have them and request the parents from us.
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::NOTFOUND, vNotFound));
}
}
@@ -1492,7 +1605,7 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::BLOCKTXN, resp));
}
-bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool punish_duplicate_invalid)
+bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::vector<CBlockHeader>& headers, const CChainParams& chainparams, bool via_compact_block)
{
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
size_t nCount = headers.size();
@@ -1518,7 +1631,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// nUnconnectingHeaders gets reset back to 0.
if (!LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++;
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(),
@@ -1554,48 +1667,8 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
CValidationState state;
CBlockHeader first_invalid_header;
if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- LOCK(cs_main);
- if (nDoS > 0) {
- Misbehaving(pfrom->GetId(), nDoS, "invalid header received");
- } else {
- LogPrint(BCLog::NET, "peer=%d: invalid header received\n", pfrom->GetId());
- }
- if (punish_duplicate_invalid && LookupBlockIndex(first_invalid_header.GetHash())) {
- // Goal: don't allow outbound peers to use up our outbound
- // connection slots if they are on incompatible chains.
- //
- // We ask the caller to set punish_invalid appropriately based
- // on the peer and the method of header delivery (compact
- // blocks are allowed to be invalid in some circumstances,
- // under BIP 152).
- // Here, we try to detect the narrow situation that we have a
- // valid block header (ie it was valid at the time the header
- // was received, and hence stored in mapBlockIndex) but know the
- // block is invalid, and that a peer has announced that same
- // block as being on its active chain.
- // Disconnect the peer in such a situation.
- //
- // Note: if the header that is invalid was not accepted to our
- // mapBlockIndex at all, that may also be grounds for
- // disconnecting the peer, as the chain they are on is likely
- // to be incompatible. However, there is a circumstance where
- // that does not hold: if the header's timestamp is more than
- // 2 hours ahead of our current time. In that case, the header
- // may become valid in the future, and we don't want to
- // disconnect a peer merely for serving us one too-far-ahead
- // block header, to prevent an attacker from splitting the
- // network by mining a block right at the 2 hour boundary.
- //
- // TODO: update the DoS logic (or, rather, rewrite the
- // DoS-interface between validation and net_processing) so that
- // the interface is cleaner, and so that we disconnect on all the
- // reasons that a peer's headers chain is incompatible
- // with ours (eg block->nVersion softforks, MTP violations,
- // etc), and not just the duplicate-invalid case.
- pfrom->fDisconnect = true;
- }
+ if (state.IsInvalid()) {
+ MaybePunishNode(pfrom->GetId(), state, via_compact_block, "invalid header received");
return false;
}
}
@@ -1615,26 +1688,26 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// because it is set in UpdateBlockAvailability. Some nullptr checks
// are still present, however, as belt-and-suspenders.
- if (received_new_header && pindexLast->nChainWork > chainActive.Tip()->nChainWork) {
+ if (received_new_header && pindexLast->nChainWork > ::ChainActive().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime();
}
if (nCount == MAX_HEADERS_RESULTS) {
// Headers message had its maximum size; the peer may have more headers.
- // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
+ // TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue
// from there instead.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->GetId(), pfrom->nStartingHeight);
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256()));
}
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
// If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible.
- if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
+ if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) {
std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = pindexLast;
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
- while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ while (pindexWalk && !::ChainActive().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
!mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
(!IsWitnessEnabled(pindexWalk->pprev, chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
@@ -1647,7 +1720,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// very large reorg at a time we think we're close to caught up to
// the main chain -- this shouldn't really happen. Bail out on the
// direct fetch and rely on parallel download instead.
- if (!chainActive.Contains(pindexWalk)) {
+ if (!::ChainActive().Contains(pindexWalk)) {
LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
pindexLast->GetBlockHash().ToString(),
pindexLast->nHeight);
@@ -1680,7 +1753,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
}
// If we're in IBD, we want outbound peers that will serve us a useful
// chain. Disconnect peers that are on chains with insufficient work.
- if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
+ if (::ChainstateActive().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
// When nCount < MAX_HEADERS_RESULTS, we know we have no more
// headers to fetch from this peer.
if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
@@ -1688,7 +1761,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
// us sync -- disconnect if using an outbound slot (unless
// whitelisted or addnode).
// Note: We compare their tip to nMinimumChainWork (rather than
- // chainActive.Tip()) because we won't start block download
+ // ::ChainActive().Tip()) because we won't start block download
// until we have a headers chain that has at least
// nMinimumChainWork, even if a peer has a chain past our tip,
// as an anti-DoS measure.
@@ -1702,7 +1775,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
if (!pfrom->fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr) {
// If this is an outbound peer, check to see if we should protect
// it from the bad/lagging chain logic.
- if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
+ if (g_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom->GetId());
nodestate->m_chain_sync.m_protect = true;
++g_outbound_peers_with_protect_from_disconnect;
@@ -1713,6 +1786,68 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
return true;
}
+void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_set, std::list<CTransactionRef>& removed_txn) EXCLUSIVE_LOCKS_REQUIRED(cs_main, g_cs_orphans)
+{
+ AssertLockHeld(cs_main);
+ AssertLockHeld(g_cs_orphans);
+ std::set<NodeId> setMisbehaving;
+ bool done = false;
+ while (!done && !orphan_work_set.empty()) {
+ const uint256 orphanHash = *orphan_work_set.begin();
+ orphan_work_set.erase(orphan_work_set.begin());
+
+ auto orphan_it = mapOrphanTransactions.find(orphanHash);
+ if (orphan_it == mapOrphanTransactions.end()) continue;
+
+ const CTransactionRef porphanTx = orphan_it->second.tx;
+ const CTransaction& orphanTx = *porphanTx;
+ NodeId fromPeer = orphan_it->second.fromPeer;
+ bool fMissingInputs2 = false;
+ // Use a new CValidationState because orphans come from different peers (and we call
+ // MaybePunishNode based on the source peer from the orphan map, not based on the peer
+ // that relayed the previous transaction).
+ CValidationState orphan_state;
+
+ if (setMisbehaving.count(fromPeer)) continue;
+ if (AcceptToMemoryPool(mempool, orphan_state, porphanTx, &fMissingInputs2, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
+ LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
+ RelayTransaction(orphanTx, connman);
+ for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
+ auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(orphanHash, i));
+ if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
+ for (const auto& elem : it_by_prev->second) {
+ orphan_work_set.insert(elem->first);
+ }
+ }
+ }
+ EraseOrphanTx(orphanHash);
+ done = true;
+ } else if (!fMissingInputs2) {
+ if (orphan_state.IsInvalid()) {
+ // Punish peer that gave us an invalid orphan tx
+ if (MaybePunishNode(fromPeer, orphan_state, /*via_compact_block*/ false)) {
+ setMisbehaving.insert(fromPeer);
+ }
+ LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
+ }
+ // Has inputs but not accepted to mempool
+ // Probably non-standard or insufficient fee
+ LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
+ assert(IsTransactionReason(orphan_state.GetReason()));
+ if (!orphanTx.HasWitness() && orphan_state.GetReason() != ValidationInvalidReason::TX_WITNESS_MUTATED) {
+ // Do not use rejection cache for witness transactions or
+ // witness-stripped transactions, as they can have been malleated.
+ // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
+ assert(recentRejects);
+ recentRejects->insert(orphanHash);
+ }
+ EraseOrphanTx(orphanHash);
+ done = true;
+ }
+ mempool.check(pcoinsTip.get());
+ }
+}
+
bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc, bool enable_bip61)
{
LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
@@ -1782,7 +1917,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
ServiceFlags nServices;
int nVersion;
int nSendVersion;
- std::string strSubVer;
std::string cleanSubVer;
int nStartingHeight = -1;
bool fRelay = true;
@@ -1819,6 +1953,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
+ std::string strSubVer;
vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
cleanSubVer = SanitizeString(strSubVer);
}
@@ -1850,7 +1985,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->SetAddrLocal(addrMe);
{
LOCK(pfrom->cs_SubVer);
- pfrom->strSubVer = strSubVer;
pfrom->cleanSubVer = cleanSubVer;
}
pfrom->nStartingHeight = nStartingHeight;
@@ -1885,7 +2019,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!pfrom->fInbound)
{
// Advertise our address
- if (fListen && !IsInitialBlockDownload())
+ if (fListen && !::ChainstateActive().IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
FastRandomContext insecure_rand;
@@ -2022,6 +2156,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
addr.nTime = nNow - 5 * 24 * 60 * 60;
pfrom->AddAddressKnown(addr);
+ if (g_banman->IsBanned(addr)) continue; // Do not process banned addresses beyond remembering we received them
bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
@@ -2079,7 +2214,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return false;
}
- bool fBlocksOnly = !fRelayTxes;
+ bool fBlocksOnly = !g_relay_txes;
// Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true
if (pfrom->fWhitelisted && gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))
@@ -2110,7 +2245,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// fell back to inv we probably have a reorg which we should get the headers for first,
// we now only provide a getheaders response here. When we receive the headers, we will
// then ask for the blocks we need.
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), inv.hash));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
}
}
@@ -2119,7 +2254,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->AddInventoryKnown(inv);
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
- } else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) {
+ } else if (!fAlreadyHave && !fImporting && !fReindex && !::ChainstateActive().IsInitialBlockDownload()) {
RequestTx(State(pfrom->GetId()), inv.hash, nNow);
}
}
@@ -2181,14 +2316,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LOCK(cs_main);
// Find the last block the caller has in the main chain
- const CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator);
+ const CBlockIndex* pindex = FindForkInGlobalIndex(::ChainActive(), locator);
// Send the rest of the chain
if (pindex)
- pindex = chainActive.Next(pindex);
+ pindex = ::ChainActive().Next(pindex);
int nLimit = 500;
LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->GetId());
- for (; pindex; pindex = chainActive.Next(pindex))
+ for (; pindex; pindex = ::ChainActive().Next(pindex))
{
if (pindex->GetBlockHash() == hashStop)
{
@@ -2198,7 +2333,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// If pruning, don't inv blocks unless we have on disk and are likely to still have
// for some reasonable time window (1 hour) that block relay might require.
const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing;
- if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave))
+ if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= ::ChainActive().Tip()->nHeight - nPrunedBlocksLikelyToHave))
{
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break;
@@ -2240,7 +2375,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (pindex->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
+ if (pindex->nHeight < ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) {
// If an older block is requested (should never happen in practice,
// but can happen in tests) send a block response instead of a
// blocktxn response. Sending a full block response instead of a
@@ -2277,7 +2412,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
LOCK(cs_main);
- if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
+ if (::ChainstateActive().IsInitialBlockDownload() && !pfrom->fWhitelisted) {
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
return true;
}
@@ -2300,23 +2435,23 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
else
{
// Find the last block the caller has in the main chain
- pindex = FindForkInGlobalIndex(chainActive, locator);
+ pindex = FindForkInGlobalIndex(::ChainActive(), locator);
if (pindex)
- pindex = chainActive.Next(pindex);
+ pindex = ::ChainActive().Next(pindex);
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
std::vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS;
LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom->GetId());
- for (; pindex; pindex = chainActive.Next(pindex))
+ for (; pindex; pindex = ::ChainActive().Next(pindex))
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
break;
}
- // pindex can be nullptr either if we sent chainActive.Tip() OR
- // if our peer has chainActive.Tip() (and thus we are sending an empty
+ // pindex can be nullptr either if we sent ::ChainActive().Tip() OR
+ // if our peer has ::ChainActive().Tip() (and thus we are sending an empty
// headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip.
//
@@ -2327,7 +2462,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// without the new block. By resetting the BestHeaderSent, we ensure we
// will re-announce the new block via headers (or compact blocks again)
// in the SendMessages logic.
- nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip();
+ nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip();
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
return true;
}
@@ -2335,14 +2470,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (strCommand == NetMsgType::TX) {
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
- if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
+ if (!g_relay_txes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)))
{
LogPrint(BCLog::NET, "transaction sent in violation of protocol peer=%d\n", pfrom->GetId());
return true;
}
- std::deque<COutPoint> vWorkQueue;
- std::vector<uint256> vEraseQueue;
CTransactionRef ptx;
vRecv >> ptx;
const CTransaction& tx = *ptx;
@@ -2367,7 +2500,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
mempool.check(pcoinsTip.get());
RelayTransaction(tx, connman);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
- vWorkQueue.emplace_back(inv.hash, i);
+ auto it_by_prev = mapOrphanTransactionsByPrev.find(COutPoint(inv.hash, i));
+ if (it_by_prev != mapOrphanTransactionsByPrev.end()) {
+ for (const auto& elem : it_by_prev->second) {
+ pfrom->orphan_work_set.insert(elem->first);
+ }
+ }
}
pfrom->nLastTXTime = GetTime();
@@ -2378,65 +2516,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
mempool.size(), mempool.DynamicMemoryUsage() / 1000);
// Recursively process any orphan transactions that depended on this one
- std::set<NodeId> setMisbehaving;
- while (!vWorkQueue.empty()) {
- auto itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue.front());
- vWorkQueue.pop_front();
- if (itByPrev == mapOrphanTransactionsByPrev.end())
- continue;
- for (auto mi = itByPrev->second.begin();
- mi != itByPrev->second.end();
- ++mi)
- {
- const CTransactionRef& porphanTx = (*mi)->second.tx;
- const CTransaction& orphanTx = *porphanTx;
- const uint256& orphanHash = orphanTx.GetHash();
- NodeId fromPeer = (*mi)->second.fromPeer;
- bool fMissingInputs2 = false;
- // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan
- // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get
- // anyone relaying LegitTxX banned)
- CValidationState stateDummy;
-
-
- if (setMisbehaving.count(fromPeer))
- continue;
- if (AcceptToMemoryPool(mempool, stateDummy, porphanTx, &fMissingInputs2, &lRemovedTxn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
- LogPrint(BCLog::MEMPOOL, " accepted orphan tx %s\n", orphanHash.ToString());
- RelayTransaction(orphanTx, connman);
- for (unsigned int i = 0; i < orphanTx.vout.size(); i++) {
- vWorkQueue.emplace_back(orphanHash, i);
- }
- vEraseQueue.push_back(orphanHash);
- }
- else if (!fMissingInputs2)
- {
- int nDos = 0;
- if (stateDummy.IsInvalid(nDos) && nDos > 0)
- {
- // Punish peer that gave us an invalid orphan tx
- Misbehaving(fromPeer, nDos);
- setMisbehaving.insert(fromPeer);
- LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
- }
- // Has inputs but not accepted to mempool
- // Probably non-standard or insufficient fee
- LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
- vEraseQueue.push_back(orphanHash);
- if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
- // Do not use rejection cache for witness transactions or
- // witness-stripped transactions, as they can have been malleated.
- // See https://github.com/bitcoin/bitcoin/issues/8279 for details.
- assert(recentRejects);
- recentRejects->insert(orphanHash);
- }
- }
- mempool.check(pcoinsTip.get());
- }
- }
-
- for (const uint256& hash : vEraseQueue)
- EraseOrphanTx(hash);
+ ProcessOrphanTx(connman, pfrom->orphan_work_set, lRemovedTxn);
}
else if (fMissingInputs)
{
@@ -2471,7 +2551,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
recentRejects->insert(tx.GetHash());
}
} else {
- if (!tx.HasWitness() && !state.CorruptionPossible()) {
+ assert(IsTransactionReason(state.GetReason()));
+ if (!tx.HasWitness() && state.GetReason() != ValidationInvalidReason::TX_WITNESS_MUTATED) {
// Do not use rejection cache for witness transactions or
// witness-stripped transactions, as they can have been malleated.
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
@@ -2490,15 +2571,13 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// to policy, allowing the node to function as a gateway for
// nodes hidden behind it.
//
- // Never relay transactions that we would assign a non-zero DoS
- // score for, as we expect peers to do the same with us in that
- // case.
- int nDoS = 0;
- if (!state.IsInvalid(nDoS) || nDoS == 0) {
+ // Never relay transactions that might result in being
+ // disconnected (or banned).
+ if (state.IsInvalid() && TxRelayMayResultInDisconnect(state)) {
+ LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state));
+ } else {
LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->GetId());
RelayTransaction(tx, connman);
- } else {
- LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state));
}
}
}
@@ -2523,8 +2602,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// peer simply for relaying a tx that our recentRejects has caught,
// regardless of false positives.
- int nDoS = 0;
- if (state.IsInvalid(nDoS))
+ if (state.IsInvalid())
{
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
pfrom->GetId(),
@@ -2533,15 +2611,19 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash));
}
- if (nDoS > 0) {
- Misbehaving(pfrom->GetId(), nDoS);
- }
+ MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ false);
}
return true;
}
- if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::CMPCTBLOCK)
{
+ // Ignore cmpctblock received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected cmpctblock message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
CBlockHeaderAndShortTxIDs cmpctblock;
vRecv >> cmpctblock;
@@ -2552,8 +2634,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
- if (!IsInitialBlockDownload())
- connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
+ if (!::ChainstateActive().IsInitialBlockDownload())
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
return true;
}
@@ -2565,14 +2647,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
const CBlockIndex *pindex = nullptr;
CValidationState state;
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
- int nDoS;
- if (state.IsInvalid(nDoS)) {
- if (nDoS > 0) {
- LOCK(cs_main);
- Misbehaving(pfrom->GetId(), nDoS, strprintf("Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId()));
- } else {
- LogPrint(BCLog::NET, "Peer %d sent us invalid header via cmpctblock\n", pfrom->GetId());
- }
+ if (state.IsInvalid()) {
+ MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
return true;
}
}
@@ -2603,7 +2679,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// If this was a new header with more work than our tip, update the
// peer's last block announcement time
- if (received_new_header && pindex->nChainWork > chainActive.Tip()->nChainWork) {
+ if (received_new_header && pindex->nChainWork > ::ChainActive().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime();
}
@@ -2613,7 +2689,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
return true;
- if (pindex->nChainWork <= chainActive.Tip()->nChainWork || // We know something better
+ if (pindex->nChainWork <= ::ChainActive().Tip()->nChainWork || // We know something better
pindex->nTx != 0) { // We had this block at some point, but pruned it
if (fAlreadyInFlight) {
// We requested this block for some reason, but our mempool will probably be useless
@@ -2637,7 +2713,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// We want to be a bit conservative just to be extra careful about DoS
// possibilities in compact block processing...
- if (pindex->nHeight <= chainActive.Height() + 2) {
+ if (pindex->nHeight <= ::ChainActive().Height() + 2) {
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
(fAlreadyInFlight && blockInFlightIt->second.first == pfrom->GetId())) {
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
@@ -2722,7 +2798,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
// the peer if the header turns out to be for an invalid block.
// Note that if a peer tries to build on an invalid chain, that
// will be detected and the peer will be banned.
- return ProcessHeadersMessage(pfrom, connman, {cmpctblock.header}, chainparams, /*punish_duplicate_invalid=*/false);
+ return ProcessHeadersMessage(pfrom, connman, {cmpctblock.header}, chainparams, /*via_compact_block=*/true);
}
if (fBlockReconstructed) {
@@ -2761,8 +2837,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCKTXN)
{
+ // Ignore blocktxn received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected blocktxn message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
BlockTransactions resp;
vRecv >> resp;
@@ -2836,8 +2918,14 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
return true;
}
- if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing
+ if (strCommand == NetMsgType::HEADERS)
{
+ // Ignore headers received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected headers message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
std::vector<CBlockHeader> headers;
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
@@ -2853,16 +2941,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
}
- // Headers received via a HEADERS message should be valid, and reflect
- // the chain the peer is on. If we receive a known-invalid header,
- // disconnect the peer if it is using one of our outbound connection
- // slots.
- bool should_punish = !pfrom->fInbound && !pfrom->m_manual_connection;
- return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish);
+ return ProcessHeadersMessage(pfrom, connman, headers, chainparams, /*via_compact_block=*/false);
}
- if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing
+ if (strCommand == NetMsgType::BLOCK)
{
+ // Ignore block received while importing
+ if (fImporting || fReindex) {
+ LogPrint(BCLog::NET, "Unexpected block message received from peer %d\n", pfrom->GetId());
+ return true;
+ }
+
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
vRecv >> *pblock;
@@ -2912,8 +3001,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
pfrom->vAddrToSend.clear();
std::vector<CAddress> vAddr = connman->GetAddresses();
FastRandomContext insecure_rand;
- for (const CAddress &addr : vAddr)
- pfrom->PushAddress(addr, insecure_rand);
+ for (const CAddress &addr : vAddr) {
+ if (!g_banman->IsBanned(addr)) {
+ pfrom->PushAddress(addr, insecure_rand);
+ }
+ }
return true;
}
@@ -3081,8 +3173,27 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
}
if (strCommand == NetMsgType::NOTFOUND) {
- // We do not care about the NOTFOUND message, but logging an Unknown Command
- // message would be undesirable as we transmit it ourselves.
+ // Remove the NOTFOUND transactions from the peer
+ LOCK(cs_main);
+ CNodeState *state = State(pfrom->GetId());
+ std::vector<CInv> vInv;
+ vRecv >> vInv;
+ if (vInv.size() <= MAX_PEER_TX_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ for (CInv &inv : vInv) {
+ if (inv.type == MSG_TX || inv.type == MSG_WITNESS_TX) {
+ // If we receive a NOTFOUND message for a txid we requested, erase
+ // it from our data structures for this peer.
+ auto in_flight_it = state->m_tx_download.m_tx_in_flight.find(inv.hash);
+ if (in_flight_it == state->m_tx_download.m_tx_in_flight.end()) {
+ // Skip any further work if this is a spurious NOTFOUND
+ // message.
+ continue;
+ }
+ state->m_tx_download.m_tx_in_flight.erase(in_flight_it);
+ state->m_tx_download.m_tx_announced.erase(inv.hash);
+ }
+ }
+ }
return true;
}
@@ -3141,11 +3252,22 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
if (!pfrom->vRecvGetData.empty())
ProcessGetData(pfrom, chainparams, connman, interruptMsgProc);
+ if (!pfrom->orphan_work_set.empty()) {
+ std::list<CTransactionRef> removed_txn;
+ LOCK2(cs_main, g_cs_orphans);
+ ProcessOrphanTx(connman, pfrom->orphan_work_set, removed_txn);
+ for (const CTransactionRef& removedTx : removed_txn) {
+ AddToCompactExtraTransactions(removedTx);
+ }
+ }
+
if (pfrom->fDisconnect)
return false;
// this maintains the order of responses
+ // and prevents vRecvGetData to grow unbounded
if (!pfrom->vRecvGetData.empty()) return true;
+ if (!pfrom->orphan_work_set.empty()) return true;
// Don't bother if send buffer is too full to respond anyway
if (pfrom->fPauseSend)
@@ -3211,23 +3333,22 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
if (m_enable_bip61) {
connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message")));
}
- if (strstr(e.what(), "end of data"))
- {
+ if (strstr(e.what(), "end of data")) {
// Allow exceptions from under-length message on vRecv
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "size too large"))
- {
+ } else if (strstr(e.what(), "size too large")) {
// Allow exceptions from over-long size
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else if (strstr(e.what(), "non-canonical ReadCompactSize()"))
- {
+ } else if (strstr(e.what(), "non-canonical ReadCompactSize()")) {
// Allow exceptions from non-canonical encoding
LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
- }
- else
- {
+ } else if (strstr(e.what(), "Superfluous witness record")) {
+ // Allow exceptions from illegal witness encoding
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ } else if (strstr(e.what(), "Unknown transaction optional data")) {
+ // Allow exceptions from unknown witness encoding
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what());
+ } else {
PrintExceptionContinue(&e, "ProcessMessages()");
}
}
@@ -3261,7 +3382,7 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds)
// their chain has more work than ours, we should sync to it,
// unless it's invalid, in which case we should find that out and
// disconnect from them elsewhere).
- if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= chainActive.Tip()->nChainWork) {
+ if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork) {
if (state.m_chain_sync.m_timeout != 0) {
state.m_chain_sync.m_timeout = 0;
state.m_chain_sync.m_work_header = nullptr;
@@ -3273,7 +3394,7 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds)
// where we checked against our tip.
// Either way, set a new timeout based on current tip.
state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT;
- state.m_chain_sync.m_work_header = chainActive.Tip();
+ state.m_chain_sync.m_work_header = ::ChainActive().Tip();
state.m_chain_sync.m_sent_getheaders = false;
} else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) {
// No evidence yet that our peer has synced to a chain with work equal to that
@@ -3286,7 +3407,7 @@ void PeerLogicValidation::ConsiderEviction(CNode *pto, int64_t time_in_seconds)
} else {
assert(state.m_chain_sync.m_work_header);
LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto->GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
state.m_chain_sync.m_sent_getheaders = true;
constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes
// Bump the timeout to allow a response, which could clear the timeout
@@ -3448,7 +3569,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Address refresh broadcast
int64_t nNow = GetTimeMicros();
- if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ if (!::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
AdvertiseLocal(pto);
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
@@ -3484,7 +3605,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Start block sync
if (pindexBestHeader == nullptr)
- pindexBestHeader = chainActive.Tip();
+ pindexBestHeader = ::ChainActive().Tip();
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
@@ -3503,18 +3624,10 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
if (pindexStart->pprev)
pindexStart = pindexStart->pprev;
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), pto->nStartingHeight);
- connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
+ connman->PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256()));
}
}
- // Resend wallet transactions that haven't gotten in a block yet
- // Except during reindex, importing and IBD, when old wallet
- // transactions become unconfirmed and spams other nodes.
- if (!fReindex && !fImporting && !IsInitialBlockDownload())
- {
- GetMainSignals().Broadcast(nTimeBestReceived, connman);
- }
-
//
// Try sending block announcements via headers
//
@@ -3538,11 +3651,11 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
bool fFoundStartingHeader = false;
// 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.
+ // headers that aren't on ::ChainActive(), give up.
for (const uint256 &hash : pto->vBlockHashesToAnnounce) {
const CBlockIndex* pindex = LookupBlockIndex(hash);
assert(pindex);
- if (chainActive[pindex->nHeight] != pindex) {
+ if (::ChainActive()[pindex->nHeight] != pindex) {
// Bail out if we reorged away from this block
fRevertToInv = true;
break;
@@ -3638,9 +3751,9 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Warn if we're announcing a block that is not on the main chain.
// This should be very rare and could be optimized out.
// Just log for now.
- if (chainActive[pindex->nHeight] != pindex) {
+ if (::ChainActive()[pindex->nHeight] != pindex) {
LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n",
- hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString());
+ hashToAnnounce.ToString(), ::ChainActive().Tip()->GetBlockHash().ToString());
}
// If the peer's chain has this block, don't inv it back.
@@ -3857,7 +3970,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Message: getdata (blocks)
//
std::vector<CInv> vGetData;
- if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !::ChainstateActive().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
@@ -3879,9 +3992,33 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
//
// Message: getdata (non-blocks)
//
+
+ // For robustness, expire old requests after a long timeout, so that
+ // we can resume downloading transactions from a peer even if they
+ // were unresponsive in the past.
+ // Eventually we should consider disconnecting peers, but this is
+ // conservative.
+ if (state.m_tx_download.m_check_expiry_timer <= nNow) {
+ for (auto it=state.m_tx_download.m_tx_in_flight.begin(); it != state.m_tx_download.m_tx_in_flight.end();) {
+ if (it->second <= nNow - TX_EXPIRY_INTERVAL) {
+ LogPrint(BCLog::NET, "timeout of inflight tx %s from peer=%d\n", it->first.ToString(), pto->GetId());
+ state.m_tx_download.m_tx_announced.erase(it->first);
+ state.m_tx_download.m_tx_in_flight.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+ // On average, we do this check every TX_EXPIRY_INTERVAL. Randomize
+ // so that we're not doing this for all peers at the same time.
+ state.m_tx_download.m_check_expiry_timer = nNow + TX_EXPIRY_INTERVAL/2 + GetRand(TX_EXPIRY_INTERVAL);
+ }
+
auto& tx_process_time = state.m_tx_download.m_tx_process_time;
while (!tx_process_time.empty() && tx_process_time.begin()->first <= nNow && state.m_tx_download.m_tx_in_flight.size() < MAX_PEER_TX_IN_FLIGHT) {
- const uint256& txid = tx_process_time.begin()->second;
+ const uint256 txid = tx_process_time.begin()->second;
+ // Erase this entry from tx_process_time (it may be added back for
+ // processing at a later time, see below)
+ tx_process_time.erase(tx_process_time.begin());
CInv inv(MSG_TX | GetFetchFlags(pto), txid);
if (!AlreadyHave(inv)) {
// If this transaction was last requested more than 1 minute ago,
@@ -3895,20 +4032,20 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
vGetData.clear();
}
UpdateTxRequestTime(inv.hash, nNow);
- state.m_tx_download.m_tx_in_flight.insert(inv.hash);
+ state.m_tx_download.m_tx_in_flight.emplace(inv.hash, nNow);
} else {
// This transaction is in flight from someone else; queue
// up processing to happen after the download times out
// (with a slight delay for inbound peers, to prefer
// requests to outbound peers).
- RequestTx(&state, txid, nNow);
+ int64_t next_process_time = CalculateTxGetDataTime(txid, nNow, !state.fPreferredDownload);
+ tx_process_time.emplace(next_process_time, txid);
}
} else {
// We have already seen this transaction, no need to download.
state.m_tx_download.m_tx_announced.erase(inv.hash);
state.m_tx_download.m_tx_in_flight.erase(inv.hash);
}
- tx_process_time.erase(tx_process_time.begin());
}
@@ -3955,4 +4092,5 @@ public:
mapOrphanTransactions.clear();
mapOrphanTransactionsByPrev.clear();
}
-} instance_of_cnetprocessingcleanup;
+};
+static CNetProcessingCleanup instance_of_cnetprocessingcleanup;
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 58e45c2c02..4fbfa2b5c8 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -14,6 +14,11 @@ static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
// 0xFD + sha256("bitcoin")[0:5]
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
+/**
+ * Construct an unspecified IPv6 network address (::/128).
+ *
+ * @note This address is considered invalid by CNetAddr::IsValid()
+ */
CNetAddr::CNetAddr()
{
memset(ip, 0, sizeof(ip));
@@ -40,6 +45,20 @@ void CNetAddr::SetRaw(Network network, const uint8_t *ip_in)
}
}
+/**
+ * Try to make this a dummy address that maps the specified name into IPv6 like
+ * so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy
+ * addresses have a prefix of fd6b:88c0:8724::/48 and are guaranteed to not be
+ * publicly routable as it falls under RFC4193's fc00::/7 subnet allocated to
+ * unique-local addresses.
+ *
+ * CAddrMan uses these fake addresses to keep track of which DNS seeds were
+ * used.
+ *
+ * @returns Whether or not the operation was successful.
+ *
+ * @see CNetAddr::IsInternal(), CNetAddr::IsRFC4193()
+ */
bool CNetAddr::SetInternal(const std::string &name)
{
if (name.empty()) {
@@ -52,6 +71,16 @@ bool CNetAddr::SetInternal(const std::string &name)
return true;
}
+/**
+ * Try to make this a dummy address that maps the specified onion address into
+ * IPv6 using OnionCat's range and encoding. Such dummy addresses have a prefix
+ * of fd87:d87e:eb43::/48 and are guaranteed to not be publicly routable as they
+ * fall under RFC4193's fc00::/7 subnet allocated to unique-local addresses.
+ *
+ * @returns Whether or not the operation was successful.
+ *
+ * @see CNetAddr::IsTor(), CNetAddr::IsRFC4193()
+ */
bool CNetAddr::SetSpecial(const std::string &strName)
{
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
@@ -175,6 +204,17 @@ bool CNetAddr::IsRFC4843() const
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
}
+bool CNetAddr::IsRFC7343() const
+{
+ return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x20);
+}
+
+/**
+ * @returns Whether or not this is a dummy address that maps an onion address
+ * into IPv6.
+ *
+ * @see CNetAddr::SetSpecial(const std::string &)
+ */
bool CNetAddr::IsTor() const
{
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
@@ -194,6 +234,16 @@ bool CNetAddr::IsLocal() const
return false;
}
+/**
+ * @returns Whether or not this network address is a valid address that @a could
+ * be used to refer to an actual host.
+ *
+ * @note A valid address may or may not be publicly routable on the global
+ * internet. As in, the set of valid addresses is a superset of the set of
+ * publicly routable addresses.
+ *
+ * @see CNetAddr::IsRoutable()
+ */
bool CNetAddr::IsValid() const
{
// Cleanup 3-byte shifted addresses caused by garbage in size field
@@ -233,11 +283,25 @@ bool CNetAddr::IsValid() const
return true;
}
+/**
+ * @returns Whether or not this network address is publicly routable on the
+ * global internet.
+ *
+ * @note A routable address is always valid. As in, the set of routable addresses
+ * is a subset of the set of valid addresses.
+ *
+ * @see CNetAddr::IsValid()
+ */
bool CNetAddr::IsRoutable() const
{
- return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsLocal() || IsInternal());
+ return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) || IsRFC4843() || IsRFC7343() || IsLocal() || IsInternal());
}
+/**
+ * @returns Whether or not this is a dummy address that maps a name into IPv6.
+ *
+ * @see CNetAddr::SetInternal(const std::string &)
+ */
bool CNetAddr::IsInternal() const
{
return memcmp(ip, g_internal_prefix, sizeof(g_internal_prefix)) == 0;
@@ -299,6 +363,16 @@ bool operator<(const CNetAddr& a, const CNetAddr& b)
return (memcmp(a.ip, b.ip, 16) < 0);
}
+/**
+ * Try to get our IPv4 address.
+ *
+ * @param[out] pipv4Addr The in_addr struct to which to copy.
+ *
+ * @returns Whether or not the operation was successful, in particular, whether
+ * or not our address was an IPv4 address.
+ *
+ * @see CNetAddr::IsIPv4()
+ */
bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
{
if (!IsIPv4())
@@ -307,6 +381,16 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
return true;
}
+/**
+ * Try to get our IPv6 address.
+ *
+ * @param[out] pipv6Addr The in6_addr struct to which to copy.
+ *
+ * @returns Whether or not the operation was successful, in particular, whether
+ * or not our address was an IPv6 address.
+ *
+ * @see CNetAddr::IsIPv6()
+ */
bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
{
if (!IsIPv6()) {
@@ -316,8 +400,16 @@ bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
return true;
}
-// get canonical identifier of an address' group
-// no two connections will be attempted to addresses with the same group
+/**
+ * Get the canonical identifier of our network group
+ *
+ * The groups are assigned in a way where it should be costly for an attacker to
+ * obtain addresses with many different group identifiers, even if it is cheap
+ * to obtain addresses with the same identifier.
+ *
+ * @note No two connections will be attempted to addresses with the same network
+ * group.
+ */
std::vector<unsigned char> CNetAddr::GetGroup() const
{
std::vector<unsigned char> vchRet;
@@ -379,12 +471,15 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nBits = 32;
vchRet.push_back(nClass);
+
+ // push our ip onto vchRet byte by byte...
while (nBits >= 8)
{
vchRet.push_back(GetByte(15 - nStartByte));
nStartByte++;
nBits -= 8;
}
+ // ...for the last byte, push nBits and for the rest of the byte push 1's
if (nBits > 0)
vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
@@ -526,6 +621,18 @@ bool operator<(const CService& a, const CService& b)
return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) || (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) && a.port < b.port);
}
+/**
+ * Obtain the IPv4/6 socket address this represents.
+ *
+ * @param[out] paddr The obtained socket address.
+ * @param[in,out] addrlen The size, in bytes, of the address structure pointed
+ * to by paddr. The value that's pointed to by this
+ * parameter might change after calling this function if
+ * the size of the corresponding address structure
+ * changed.
+ *
+ * @returns Whether or not the operation was successful.
+ */
bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
{
if (IsIPv4()) {
@@ -556,13 +663,16 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
return false;
}
+/**
+ * @returns An identifier unique to this service's address and port number.
+ */
std::vector<unsigned char> CService::GetKey() const
{
std::vector<unsigned char> vKey;
vKey.resize(18);
memcpy(vKey.data(), ip, 16);
- vKey[16] = port / 0x100;
- vKey[17] = port & 0x0FF;
+ vKey[16] = port / 0x100; // most significant byte of our port
+ vKey[17] = port & 0x0FF; // least significant byte of our port
return vKey;
}
@@ -641,6 +751,10 @@ CSubNet::CSubNet(const CNetAddr &addr):
network = addr;
}
+/**
+ * @returns True if this subnet is valid, the specified address is valid, and
+ * the specified address belongs in this subnet.
+ */
bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid())
@@ -651,6 +765,10 @@ bool CSubNet::Match(const CNetAddr &addr) const
return true;
}
+/**
+ * @returns The number of 1-bits in the prefix of the specified subnet mask. If
+ * the specified subnet mask is not a valid one, -1.
+ */
static inline int NetmaskBits(uint8_t x)
{
switch(x) {
diff --git a/src/netaddress.h b/src/netaddress.h
index ca435d17dc..673eaf8d7b 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -48,10 +48,6 @@ class CNetAddr
void SetRaw(Network network, const uint8_t *data);
public:
- /**
- * Transform an arbitrary string into a non-routable ipv6 address.
- * Useful for mapping resolved addresses back to their source.
- */
bool SetInternal(const std::string& name);
bool SetSpecial(const std::string &strName); // for Tor addresses
@@ -67,10 +63,11 @@ class CNetAddr
bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
bool IsRFC4193() const; // IPv6 unique local (FC00::/7)
bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
- bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
+ bool IsRFC4843() const; // IPv6 ORCHID (deprecated) (2001:10::/28)
+ bool IsRFC7343() const; // IPv6 ORCHIDv2 (2001:20::/28)
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
- bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
- bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
+ bool IsRFC6052() const; // IPv6 well-known prefix for IPv4-embedded address (64:FF9B::/96)
+ bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) (actually defined in RFC2765)
bool IsTor() const;
bool IsLocal() const;
bool IsRoutable() const;
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 6c386a9ade..78b3b6ae3a 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -5,10 +5,7 @@
#include <netbase.h>
-#include <hash.h>
#include <sync.h>
-#include <uint256.h>
-#include <random.h>
#include <tinyformat.h>
#include <util/system.h>
#include <util/strencodings.h>
diff --git a/src/node/README.md b/src/node/README.md
new file mode 100644
index 0000000000..e99a717534
--- /dev/null
+++ b/src/node/README.md
@@ -0,0 +1,22 @@
+# src/node/
+
+The [`src/node/`](./) directory contains code that needs to access node state
+(state in `CChain`, `CBlockIndex`, `CCoinsView`, `CTxMemPool`, and similar
+classes).
+
+Code in [`src/node/`](./) is meant to be segregated from code in
+[`src/wallet/`](../wallet/) and [`src/qt/`](../qt/), to ensure wallet and GUI
+code changes don't interfere with node operation, to allow wallet and GUI code
+to run in separate processes, and to perhaps eventually allow wallet and GUI
+code to be maintained in separate source repositories.
+
+As a rule of thumb, code in one of the [`src/node/`](./),
+[`src/wallet/`](../wallet/), or [`src/qt/`](../qt/) directories should avoid
+calling code in the other directories directly, and only invoke it indirectly
+through the more limited [`src/interfaces/`](../interfaces/) classes.
+
+The [`src/node/`](./) directory is a new directory introduced in
+[#14978](https://github.com/bitcoin/bitcoin/pull/14978) and at the moment is
+sparsely populated. Eventually more substantial files like
+[`src/validation.cpp`](../validation.cpp) and
+[`src/txmempool.cpp`](../txmempool.cpp) might be moved there.
diff --git a/src/node/coin.cpp b/src/node/coin.cpp
new file mode 100644
index 0000000000..bb98e63f3a
--- /dev/null
+++ b/src/node/coin.cpp
@@ -0,0 +1,22 @@
+// 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 <node/coin.h>
+
+#include <txmempool.h>
+#include <validation.h>
+
+void FindCoins(std::map<COutPoint, Coin>& coins)
+{
+ LOCK2(cs_main, ::mempool.cs);
+ assert(pcoinsTip);
+ CCoinsViewCache& chain_view = *::pcoinsTip;
+ CCoinsViewMemPool mempool_view(&chain_view, ::mempool);
+ for (auto& coin : coins) {
+ if (!mempool_view.GetCoin(coin.first, coin.second)) {
+ // Either the coin is not in the CCoinsViewCache or is spent. Clear it.
+ coin.second.Clear();
+ }
+ }
+}
diff --git a/src/node/coin.h b/src/node/coin.h
new file mode 100644
index 0000000000..eb95b75cfb
--- /dev/null
+++ b/src/node/coin.h
@@ -0,0 +1,22 @@
+// 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_NODE_COIN_H
+#define BITCOIN_NODE_COIN_H
+
+#include <map>
+
+class COutPoint;
+class Coin;
+
+/**
+ * Look up unspent output information. Returns coins in the mempool and in the
+ * current chain UTXO set. Iterates through all the keys in the map and
+ * populates the values.
+ *
+ * @param[in,out] coins map to fill
+ */
+void FindCoins(std::map<COutPoint, Coin>& coins);
+
+#endif // BITCOIN_NODE_COIN_H
diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp
new file mode 100644
index 0000000000..12559c5a5f
--- /dev/null
+++ b/src/node/psbt.cpp
@@ -0,0 +1,134 @@
+// Copyright (c) 2009-2018 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 <coins.h>
+#include <consensus/tx_verify.h>
+#include <node/psbt.h>
+#include <policy/policy.h>
+#include <policy/settings.h>
+
+#include <numeric>
+
+PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
+{
+ // Go through each input and build status
+ PSBTAnalysis result;
+
+ bool calc_fee = true;
+ bool all_final = true;
+ bool only_missing_sigs = true;
+ bool only_missing_final = false;
+ CAmount in_amt = 0;
+
+ result.inputs.resize(psbtx.tx->vin.size());
+
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& input = psbtx.inputs[i];
+ PSBTInputAnalysis& input_analysis = result.inputs[i];
+
+ // Check for a UTXO
+ CTxOut utxo;
+ if (psbtx.GetInputUTXO(utxo, i)) {
+ in_amt += utxo.nValue;
+ input_analysis.has_utxo = true;
+ } else {
+ input_analysis.has_utxo = false;
+ input_analysis.is_final = false;
+ input_analysis.next = PSBTRole::UPDATER;
+ calc_fee = false;
+ }
+
+ // Check if it is final
+ if (!utxo.IsNull() && !PSBTInputSigned(input)) {
+ input_analysis.is_final = false;
+ all_final = false;
+
+ // Figure out what is missing
+ SignatureData outdata;
+ bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata);
+
+ // Things are missing
+ if (!complete) {
+ input_analysis.missing_pubkeys = outdata.missing_pubkeys;
+ input_analysis.missing_redeem_script = outdata.missing_redeem_script;
+ input_analysis.missing_witness_script = outdata.missing_witness_script;
+ input_analysis.missing_sigs = outdata.missing_sigs;
+
+ // If we are only missing signatures and nothing else, then next is signer
+ if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
+ input_analysis.next = PSBTRole::SIGNER;
+ } else {
+ only_missing_sigs = false;
+ input_analysis.next = PSBTRole::UPDATER;
+ }
+ } else {
+ only_missing_final = true;
+ input_analysis.next = PSBTRole::FINALIZER;
+ }
+ } else if (!utxo.IsNull()){
+ input_analysis.is_final = true;
+ }
+ }
+
+ if (all_final) {
+ only_missing_sigs = false;
+ result.next = PSBTRole::EXTRACTOR;
+ }
+ if (calc_fee) {
+ // Get the output amount
+ CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), CAmount(0),
+ [](CAmount a, const CTxOut& b) {
+ return a += b.nValue;
+ }
+ );
+
+ // Get the fee
+ CAmount fee = in_amt - out_amt;
+ result.fee = fee;
+
+ // Estimate the size
+ CMutableTransaction mtx(*psbtx.tx);
+ CCoinsView view_dummy;
+ CCoinsViewCache view(&view_dummy);
+ bool success = true;
+
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& input = psbtx.inputs[i];
+ Coin newcoin;
+
+ if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !psbtx.GetInputUTXO(newcoin.out, i)) {
+ success = false;
+ break;
+ } else {
+ mtx.vin[i].scriptSig = input.final_script_sig;
+ mtx.vin[i].scriptWitness = input.final_script_witness;
+ newcoin.nHeight = 1;
+ view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
+ }
+ }
+
+ if (success) {
+ CTransaction ctx = CTransaction(mtx);
+ size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
+ result.estimated_vsize = size;
+ // Estimate fee rate
+ CFeeRate feerate(fee, size);
+ result.estimated_feerate = feerate;
+ }
+
+ if (only_missing_sigs) {
+ result.next = PSBTRole::SIGNER;
+ } else if (only_missing_final) {
+ result.next = PSBTRole::FINALIZER;
+ } else if (all_final) {
+ result.next = PSBTRole::EXTRACTOR;
+ } else {
+ result.next = PSBTRole::UPDATER;
+ }
+ } else {
+ result.next = PSBTRole::UPDATER;
+ }
+
+ return result;
+}
diff --git a/src/node/psbt.h b/src/node/psbt.h
new file mode 100644
index 0000000000..e04366a20f
--- /dev/null
+++ b/src/node/psbt.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009-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_NODE_PSBT_H
+#define BITCOIN_NODE_PSBT_H
+
+#include <psbt.h>
+
+/**
+ * Holds an analysis of one input from a PSBT
+ */
+struct PSBTInputAnalysis {
+ bool has_utxo; //!< Whether we have UTXO information for this input
+ bool is_final; //!< Whether the input has all required information including signatures
+ PSBTRole next; //!< Which of the BIP 174 roles needs to handle this input next
+
+ std::vector<CKeyID> missing_pubkeys; //!< Pubkeys whose BIP32 derivation path is missing
+ std::vector<CKeyID> missing_sigs; //!< Pubkeys whose signatures are missing
+ uint160 missing_redeem_script; //!< Hash160 of redeem script, if missing
+ uint256 missing_witness_script; //!< SHA256 of witness script, if missing
+};
+
+/**
+ * Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
+ */
+struct PSBTAnalysis {
+ Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
+ Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
+ Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
+ std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
+ PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
+};
+
+/**
+ * Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
+ *
+ * @param[in] psbtx the PSBT to analyze
+ * @return A PSBTAnalysis with information about the provided PSBT.
+ */
+PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx);
+
+#endif // BITCOIN_NODE_PSBT_H
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 7b9b4310e7..5ffb15ed3c 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -6,38 +6,13 @@
#include <consensus/validation.h>
#include <net.h>
#include <txmempool.h>
+#include <util/validation.h>
#include <validation.h>
#include <validationinterface.h>
#include <node/transaction.h>
#include <future>
-std::string TransactionErrorString(const TransactionError err)
-{
- switch (err) {
- case TransactionError::OK:
- return "No error";
- case TransactionError::MISSING_INPUTS:
- return "Missing inputs";
- case TransactionError::ALREADY_IN_CHAIN:
- return "Transaction already in block chain";
- case TransactionError::P2P_DISABLED:
- return "Peer-to-peer functionality missing or disabled";
- case TransactionError::MEMPOOL_REJECTED:
- return "Transaction rejected by AcceptToMemoryPool";
- case TransactionError::MEMPOOL_ERROR:
- return "AcceptToMemoryPool failed";
- case TransactionError::INVALID_PSBT:
- return "PSBT is not sane";
- case TransactionError::PSBT_MISMATCH:
- return "PSBTs not compatible (different transactions)";
- case TransactionError::SIGHASH_MISMATCH:
- return "Specified sighash value does not match existing value";
- // no default case, so the compiler can warn about missing cases
- }
- assert(false);
-}
-
TransactionError BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, std::string& err_string, const CAmount& highfee)
{
std::promise<void> promise;
diff --git a/src/node/transaction.h b/src/node/transaction.h
index 3457ececa4..51033f94e5 100644
--- a/src/node/transaction.h
+++ b/src/node/transaction.h
@@ -8,20 +8,7 @@
#include <attributes.h>
#include <primitives/transaction.h>
#include <uint256.h>
-
-enum class TransactionError {
- OK, //!< No error
- MISSING_INPUTS,
- ALREADY_IN_CHAIN,
- P2P_DISABLED,
- MEMPOOL_REJECTED,
- MEMPOOL_ERROR,
- INVALID_PSBT,
- PSBT_MISMATCH,
- SIGHASH_MISMATCH,
-};
-
-std::string TransactionErrorString(const TransactionError error);
+#include <util/error.h>
/**
* Broadcast a transaction
diff --git a/src/noui.cpp b/src/noui.cpp
index c7d8fee0ba..caab9f326e 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -18,26 +18,30 @@ bool noui_ThreadSafeMessageBox(const std::string& message, const std::string& ca
{
bool fSecure = style & CClientUIInterface::SECURE;
style &= ~CClientUIInterface::SECURE;
+ bool prefix = !(style & CClientUIInterface::MSG_NOPREFIX);
+ style &= ~CClientUIInterface::MSG_NOPREFIX;
std::string strCaption;
- // Check for usage of predefined caption
- switch (style) {
- case CClientUIInterface::MSG_ERROR:
- strCaption += _("Error");
- break;
- case CClientUIInterface::MSG_WARNING:
- strCaption += _("Warning");
- break;
- case CClientUIInterface::MSG_INFORMATION:
- strCaption += _("Information");
- break;
- default:
- strCaption += caption; // Use supplied caption (can be empty)
+ if (prefix) {
+ switch (style) {
+ case CClientUIInterface::MSG_ERROR:
+ strCaption = "Error: ";
+ break;
+ case CClientUIInterface::MSG_WARNING:
+ strCaption = "Warning: ";
+ break;
+ case CClientUIInterface::MSG_INFORMATION:
+ strCaption = "Information: ";
+ break;
+ default:
+ strCaption = caption + ": "; // Use supplied caption (can be empty)
+ }
}
- if (!fSecure)
- LogPrintf("%s: %s\n", strCaption, message);
- fprintf(stderr, "%s: %s\n", strCaption.c_str(), message.c_str());
+ if (!fSecure) {
+ LogPrintf("%s%s\n", strCaption, message);
+ }
+ tfm::format(std::cerr, "%s%s\n", strCaption.c_str(), message.c_str());
return false;
}
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index 7e5690dfc5..73ffb801f2 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -45,14 +45,14 @@ const std::string& FormatOutputType(OutputType type)
CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
{
switch (type) {
- case OutputType::LEGACY: return key.GetID();
+ case OutputType::LEGACY: return PKHash(key);
case OutputType::P2SH_SEGWIT:
case OutputType::BECH32: {
- if (!key.IsCompressed()) return key.GetID();
- CTxDestination witdest = WitnessV0KeyHash(key.GetID());
+ if (!key.IsCompressed()) return PKHash(key);
+ CTxDestination witdest = WitnessV0KeyHash(PKHash(key));
CScript witprog = GetScriptForDestination(witdest);
if (type == OutputType::P2SH_SEGWIT) {
- return CScriptID(witprog);
+ return ScriptHash(witprog);
} else {
return witdest;
}
@@ -63,10 +63,10 @@ CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
{
- CKeyID keyid = key.GetID();
+ PKHash keyid(key);
if (key.IsCompressed()) {
CTxDestination segwit = WitnessV0KeyHash(keyid);
- CTxDestination p2sh = CScriptID(GetScriptForDestination(segwit));
+ CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
return std::vector<CTxDestination>{std::move(keyid), std::move(p2sh), std::move(segwit)};
} else {
return std::vector<CTxDestination>{std::move(keyid)};
@@ -80,19 +80,19 @@ CTxDestination AddAndGetDestinationForScript(CKeyStore& keystore, const CScript&
// Note that scripts over 520 bytes are not yet supported.
switch (type) {
case OutputType::LEGACY:
- return CScriptID(script);
+ return ScriptHash(script);
case OutputType::P2SH_SEGWIT:
case OutputType::BECH32: {
CTxDestination witdest = WitnessV0ScriptHash(script);
CScript witprog = GetScriptForDestination(witdest);
// Check if the resulting program is solvable (i.e. doesn't use an uncompressed key)
- if (!IsSolvable(keystore, witprog)) return CScriptID(script);
+ if (!IsSolvable(keystore, witprog)) return ScriptHash(script);
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
keystore.AddCScript(witprog);
if (type == OutputType::BECH32) {
return witdest;
} else {
- return CScriptID(witprog);
+ return ScriptHash(witprog);
}
}
default: assert(false);
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index c49b9fa36b..5d538606c2 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -4,7 +4,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/fees.h>
-#include <policy/policy.h>
#include <clientversion.h>
#include <primitives/transaction.h>
@@ -27,40 +26,6 @@ std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
return horizon_string->second;
}
-std::string StringForFeeReason(FeeReason reason) {
- static const std::map<FeeReason, std::string> fee_reason_strings = {
- {FeeReason::NONE, "None"},
- {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
- {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"},
- {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"},
- {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"},
- {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"},
- {FeeReason::PAYTXFEE, "PayTxFee set"},
- {FeeReason::FALLBACK, "Fallback fee"},
- {FeeReason::REQUIRED, "Minimum Required Fee"},
- {FeeReason::MAXTXFEE, "MaxTxFee limit"}
- };
- auto reason_string = fee_reason_strings.find(reason);
-
- if (reason_string == fee_reason_strings.end()) return "Unknown";
-
- return reason_string->second;
-}
-
-bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
- static const std::map<std::string, FeeEstimateMode> fee_modes = {
- {"UNSET", FeeEstimateMode::UNSET},
- {"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
- {"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
- };
- auto mode = fee_modes.find(mode_string);
-
- if (mode == fee_modes.end()) return false;
-
- fee_estimate_mode = mode->second;
- return true;
-}
-
/**
* We will instantiate an instance of this class to track transactions that were
* included in a block. We will lump transactions into a bucket according to their
@@ -82,7 +47,7 @@ private:
std::vector<double> txCtAvg;
// Count the total # of txs confirmed within Y blocks in each bucket
- // Track the historical moving average of theses totals over blocks
+ // Track the historical moving average of these totals over blocks
std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
// Track moving avg of txs which have been evicted from the mempool
@@ -560,7 +525,7 @@ void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, boo
if (txHeight != nBestSeenHeight) {
// Ignore side chains and re-orgs; assuming they are random they don't
// affect the estimate. We'll potentially double count transactions in 1-block reorgs.
- // Ignore txs if BlockPolicyEstimator is not in sync with chainActive.Tip().
+ // Ignore txs if BlockPolicyEstimator is not in sync with ::ChainActive().Tip().
// It will be synced next time a block is processed.
return;
}
diff --git a/src/policy/fees.h b/src/policy/fees.h
index c8472a12f5..16683bf5ad 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -43,11 +43,8 @@ enum class FeeReason {
PAYTXFEE,
FALLBACK,
REQUIRED,
- MAXTXFEE,
};
-std::string StringForFeeReason(FeeReason reason);
-
/* Used to determine type of fee estimation requested */
enum class FeeEstimateMode {
UNSET, //!< Use default settings based on other criteria
@@ -55,8 +52,6 @@ enum class FeeEstimateMode {
CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
};
-bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
-
/* Used to return detailed information about a feerate bucket */
struct EstimatorBucket
{
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index d4cc538492..51de5841ec 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -8,11 +8,7 @@
#include <policy/policy.h>
#include <consensus/validation.h>
-#include <validation.h>
#include <coins.h>
-#include <tinyformat.h>
-#include <util/system.h>
-#include <util/strencodings.h>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
@@ -59,7 +55,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
std::vector<std::vector<unsigned char> > vSolutions;
whichType = Solver(scriptPubKey, vSolutions);
- if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) {
+ if (whichType == TX_NONSTANDARD) {
return false;
} else if (whichType == TX_MULTISIG) {
unsigned char m = vSolutions.front()[0];
@@ -77,7 +73,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
return true;
}
-bool IsStandardTx(const CTransaction& tx, std::string& reason)
+bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
{
if (tx.nVersion > CTransaction::MAX_STANDARD_VERSION || tx.nVersion < 1) {
reason = "version";
@@ -123,10 +119,10 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason)
if (whichType == TX_NULL_DATA)
nDataOut++;
- else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
+ else if ((whichType == TX_MULTISIG) && (!permit_bare_multisig)) {
reason = "bare-multisig";
return false;
- } else if (IsDust(txout, ::dustRelayFee)) {
+ } else if (IsDust(txout, dust_relay_fee)) {
reason = "dust";
return false;
}
@@ -239,21 +235,17 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
return true;
}
-CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
-CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
-unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
-
-int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
+int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
- return (std::max(nWeight, nSigOpCost * nBytesPerSigOp) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
+ return (std::max(nWeight, nSigOpCost * bytes_per_sigop) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}
-int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost)
+int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
- return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost);
+ return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost, bytes_per_sigop);
}
-int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost)
+int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
- return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost);
+ return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost, bytes_per_sigop);
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 3d47ac1267..ebe040f0ea 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -34,6 +34,8 @@ static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
/** Default for -bytespersigop */
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
+/** Default for -permitbaremultisig */
+static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
/** The maximum number of witness stack items in a standard P2WSH script */
static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
/** The maximum size of each witness stack item in a standard P2WSH script */
@@ -84,7 +86,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
* Check for standard transaction types
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
-bool IsStandardTx(const CTransaction& tx, std::string& reason);
+bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
@@ -98,13 +100,19 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
*/
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-extern CFeeRate incrementalRelayFee;
-extern CFeeRate dustRelayFee;
-extern unsigned int nBytesPerSigOp;
-
/** Compute the virtual transaction size (weight reinterpreted as bytes). */
-int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost);
-int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost = 0);
-int64_t GetVirtualTransactionInputSize(const CTxIn& tx, int64_t nSigOpCost = 0);
+int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop);
+int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost, unsigned int bytes_per_sigop);
+int64_t GetVirtualTransactionInputSize(const CTxIn& tx, int64_t nSigOpCost, unsigned int bytes_per_sigop);
+
+static inline int64_t GetVirtualTransactionSize(const CTransaction& tx)
+{
+ return GetVirtualTransactionSize(tx, 0, 0);
+}
+
+static inline int64_t GetVirtualTransactionInputSize(const CTxIn& tx)
+{
+ return GetVirtualTransactionInputSize(tx, 0, 0);
+}
#endif // BITCOIN_POLICY_POLICY_H
diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp
index 0dc130d104..b4b8341d77 100644
--- a/src/policy/rbf.cpp
+++ b/src/policy/rbf.cpp
@@ -3,18 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <policy/rbf.h>
+#include <util/rbf.h>
-bool SignalsOptInRBF(const CTransaction &tx)
-{
- for (const CTxIn &txin : tx.vin) {
- if (txin.nSequence <= MAX_BIP125_RBF_SEQUENCE) {
- return true;
- }
- }
- return false;
-}
-
-RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool)
+RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
{
AssertLockHeld(pool.cs);
diff --git a/src/policy/rbf.h b/src/policy/rbf.h
index 581f489e12..0707b0044f 100644
--- a/src/policy/rbf.h
+++ b/src/policy/rbf.h
@@ -7,22 +7,16 @@
#include <txmempool.h>
-static const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd;
-
enum class RBFTransactionState {
UNKNOWN,
REPLACEABLE_BIP125,
FINAL
};
-// Check whether the sequence numbers on this transaction are signaling
-// opt-in to replace-by-fee, according to BIP 125
-bool SignalsOptInRBF(const CTransaction &tx);
-
// Determine whether an in-mempool transaction is signaling opt-in to RBF
// according to BIP 125
// This involves checking sequence numbers of the transaction, as well
// as the sequence numbers of all in-mempool ancestors.
-RBFTransactionState IsRBFOptIn(const CTransaction &tx, CTxMemPool &pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
+RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
#endif // BITCOIN_POLICY_RBF_H
diff --git a/src/policy/settings.cpp b/src/policy/settings.cpp
new file mode 100644
index 0000000000..e8e1559407
--- /dev/null
+++ b/src/policy/settings.cpp
@@ -0,0 +1,14 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 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 <policy/settings.h>
+
+#include <policy/feerate.h>
+#include <policy/policy.h>
+
+bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
+CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
+CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
+unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
diff --git a/src/policy/settings.h b/src/policy/settings.h
new file mode 100644
index 0000000000..30a7189c93
--- /dev/null
+++ b/src/policy/settings.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 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_POLICY_SETTINGS_H
+#define BITCOIN_POLICY_SETTINGS_H
+
+#include <policy/policy.h>
+
+class CFeeRate;
+class CTransaction;
+
+// Policy settings which are configurable at runtime.
+extern CFeeRate incrementalRelayFee;
+extern CFeeRate dustRelayFee;
+extern unsigned int nBytesPerSigOp;
+extern bool fIsBareMultisigStd;
+
+static inline bool IsStandardTx(const CTransaction& tx, std::string& reason)
+{
+ return IsStandardTx(tx, ::fIsBareMultisigStd, ::dustRelayFee, reason);
+}
+
+static inline int64_t GetVirtualTransactionSize(int64_t weight, int64_t sigop_cost)
+{
+ return GetVirtualTransactionSize(weight, sigop_cost, ::nBytesPerSigOp);
+}
+
+static inline int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t sigop_cost)
+{
+ return GetVirtualTransactionSize(tx, sigop_cost, ::nBytesPerSigOp);
+}
+
+#endif // BITCOIN_POLICY_SETTINGS_H
diff --git a/src/prevector.h b/src/prevector.h
index 99e5751634..9d576321b6 100644
--- a/src/prevector.h
+++ b/src/prevector.h
@@ -147,14 +147,14 @@ public:
};
private:
- size_type _size;
+ size_type _size = 0;
union direct_or_indirect {
char direct[sizeof(T) * N];
struct {
size_type capacity;
char* indirect;
};
- } _union;
+ } _union = {};
T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }
const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }
@@ -230,34 +230,34 @@ public:
fill(item_ptr(0), first, last);
}
- prevector() : _size(0), _union{{}} {}
+ prevector() {}
- explicit prevector(size_type n) : prevector() {
+ explicit prevector(size_type n) {
resize(n);
}
- explicit prevector(size_type n, const T& val) : prevector() {
+ explicit prevector(size_type n, const T& val) {
change_capacity(n);
_size += n;
fill(item_ptr(0), n, val);
}
template<typename InputIterator>
- prevector(InputIterator first, InputIterator last) : prevector() {
+ prevector(InputIterator first, InputIterator last) {
size_type n = last - first;
change_capacity(n);
_size += n;
fill(item_ptr(0), first, last);
}
- prevector(const prevector<N, T, Size, Diff>& other) : prevector() {
+ prevector(const prevector<N, T, Size, Diff>& other) {
size_type n = other.size();
change_capacity(n);
_size += n;
fill(item_ptr(0), other.begin(), other.end());
}
- prevector(prevector<N, T, Size, Diff>&& other) : prevector() {
+ prevector(prevector<N, T, Size, Diff>&& other) {
swap(other);
}
@@ -378,6 +378,21 @@ public:
fill(ptr, first, last);
}
+ inline void resize_uninitialized(size_type new_size) {
+ // resize_uninitialized changes the size of the prevector but does not initialize it.
+ // If size < new_size, the added elements must be initialized explicitly.
+ if (capacity() < new_size) {
+ change_capacity(new_size);
+ _size += new_size - size();
+ return;
+ }
+ if (new_size < size()) {
+ erase(item_ptr(new_size), end());
+ } else {
+ _size += new_size - size();
+ }
+ }
+
iterator erase(iterator pos) {
return erase(pos, pos + 1);
}
diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp
index a0c2e3f125..60c7c2d160 100644
--- a/src/primitives/block.cpp
+++ b/src/primitives/block.cpp
@@ -7,7 +7,6 @@
#include <hash.h>
#include <tinyformat.h>
-#include <util/strencodings.h>
#include <crypto/common.h>
uint256 CBlockHeader::GetHash() const
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index f6f8e31363..aad991e2f1 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -222,6 +222,10 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
for (size_t i = 0; i < tx.vin.size(); i++) {
s >> tx.vin[i].scriptWitness.stack;
}
+ if (!tx.HasWitness()) {
+ /* It's illegal to encode witnesses when all witness stacks are empty. */
+ throw std::ios_base::failure("Superfluous witness record");
+ }
}
if (flags) {
/* Unknown flag in the serialization */
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 0fb7d49d7d..d765133190 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -5,6 +5,8 @@
#include <psbt.h>
#include <util/strencodings.h>
+#include <numeric>
+
PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
{
inputs.resize(tx.vin.size());
@@ -205,7 +207,7 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
}
-bool PSBTInputSigned(PSBTInput& input)
+bool PSBTInputSigned(const PSBTInput& input)
{
return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
}
@@ -325,3 +327,41 @@ TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector
return TransactionError::OK;
}
+
+std::string PSBTRoleName(PSBTRole role) {
+ switch (role) {
+ case PSBTRole::UPDATER: return "updater";
+ case PSBTRole::SIGNER: return "signer";
+ case PSBTRole::FINALIZER: return "finalizer";
+ case PSBTRole::EXTRACTOR: return "extractor";
+ // no default case, so the compiler can warn about missing cases
+ }
+ assert(false);
+}
+
+bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
+{
+ bool invalid;
+ std::string tx_data = DecodeBase64(base64_tx, &invalid);
+ if (invalid) {
+ error = "invalid base64";
+ return false;
+ }
+ return DecodeRawPSBT(psbt, tx_data, error);
+}
+
+bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
+{
+ CDataStream ss_data(tx_data.data(), tx_data.data() + tx_data.size(), SER_NETWORK, PROTOCOL_VERSION);
+ try {
+ ss_data >> psbt;
+ if (!ss_data.empty()) {
+ error = "extra data after PSBT";
+ return false;
+ }
+ } catch (const std::exception& e) {
+ error = e.what();
+ return false;
+ }
+ return true;
+}
diff --git a/src/psbt.h b/src/psbt.h
index c889dad361..1bc1e91a84 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -7,6 +7,8 @@
#include <attributes.h>
#include <node/transaction.h>
+#include <optional.h>
+#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <pubkey.h>
#include <script/sign.h>
@@ -548,8 +550,17 @@ struct PartiallySignedTransaction
}
};
+enum class PSBTRole {
+ UPDATER,
+ SIGNER,
+ FINALIZER,
+ EXTRACTOR
+};
+
+std::string PSBTRoleName(PSBTRole role);
+
/** Checks whether a PSBTInput is already signed. */
-bool PSBTInputSigned(PSBTInput& input);
+bool PSBTInputSigned(const PSBTInput& input);
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool use_dummy = false);
@@ -580,4 +591,9 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
*/
NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
+//! Decode a base64ed PSBT into a PartiallySignedTransaction
+NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
+//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
+NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
+
#endif // BITCOIN_PSBT_H
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 726dafccb0..d8c39e8862 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -10,7 +10,6 @@
#include <qt/forms/ui_addressbookpage.h>
#include <qt/addresstablemodel.h>
-#include <qt/bitcoingui.h>
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/guiutil.h>
@@ -107,7 +106,7 @@ AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode _mode,
ui->newAddress->setVisible(true);
break;
case ReceivingTab:
- ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction."));
+ ui->labelExplanation->setText(tr("These are your Bitcoin addresses for receiving payments. Use the 'Create new receiving address' button in the receive tab to create new addresses."));
ui->deleteAddress->setVisible(false);
ui->newAddress->setVisible(false);
break;
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index c3143e948a..fa6c9c9f7a 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -7,7 +7,6 @@
#include <qt/guiutil.h>
#include <qt/walletmodel.h>
-#include <interfaces/node.h>
#include <key_io.h>
#include <wallet/wallet.h>
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
index 00c446cc63..8a6b205cd8 100644
--- a/src/qt/bantablemodel.cpp
+++ b/src/qt/bantablemodel.cpp
@@ -5,8 +5,6 @@
#include <qt/bantablemodel.h>
#include <qt/clientmodel.h>
-#include <qt/guiconstants.h>
-#include <qt/guiutil.h>
#include <interfaces/node.h>
#include <sync.h>
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 1b063771ef..2fdbcca043 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -30,13 +30,10 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <noui.h>
-#include <rpc/server.h>
+#include <util/threadnames.h>
#include <ui_interface.h>
#include <uint256.h>
#include <util/system.h>
-#include <warnings.h>
-
-#include <walletinitinterface.h>
#include <memory>
#include <stdint.h>
@@ -149,6 +146,7 @@ void BitcoinCore::initialize()
try
{
qDebug() << __func__ << ": Running initialization in thread";
+ util::ThreadRename("qt-init");
bool rv = m_node.appInitMain();
Q_EMIT initializeResult(rv);
} catch (const std::exception& e) {
@@ -332,7 +330,7 @@ void BitcoinApplication::initializeResult(bool success)
if(success)
{
// Log this only after AppInitMain finishes, as then logging setup is guaranteed complete
- qWarning() << "Platform customization:" << platformStyle->getName();
+ qInfo() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this);
#ifdef ENABLE_BIP70
@@ -423,6 +421,7 @@ int GuiMain(int argc, char* argv[])
std::tie(argc, argv) = winArgs.get();
#endif
SetupEnvironment();
+ util::ThreadRename("main");
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
@@ -437,16 +436,17 @@ int GuiMain(int argc, char* argv[])
Q_INIT_RESOURCE(bitcoin);
Q_INIT_RESOURCE(bitcoin_locale);
- BitcoinApplication app(*node, argc, argv);
// Generate high-dpi pixmaps
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if QT_VERSION >= 0x050600
- QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
#ifdef Q_OS_MAC
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
+ BitcoinApplication app(*node, argc, argv);
+
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
// Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index abf9136eee..babb2ce518 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -335,8 +335,9 @@ void BitcoinGUI::createActions()
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
m_open_wallet_action = new QAction(tr("Open Wallet"), this);
- m_open_wallet_action->setMenu(new QMenu(this));
+ m_open_wallet_action->setEnabled(false);
m_open_wallet_action->setStatusTip(tr("Open a wallet"));
+ m_open_wallet_menu = new QMenu(this);
m_close_wallet_action = new QAction(tr("Close Wallet..."), this);
m_close_wallet_action->setStatusTip(tr("Close wallet"));
@@ -368,11 +369,20 @@ void BitcoinGUI::createActions()
connect(usedSendingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedSendingAddresses);
connect(usedReceivingAddressesAction, &QAction::triggered, walletFrame, &WalletFrame::usedReceivingAddresses);
connect(openAction, &QAction::triggered, this, &BitcoinGUI::openClicked);
- connect(m_open_wallet_action->menu(), &QMenu::aboutToShow, [this] {
- m_open_wallet_action->menu()->clear();
- for (std::string path : m_wallet_controller->getWalletsAvailableToOpen()) {
+ connect(m_open_wallet_menu, &QMenu::aboutToShow, [this] {
+ m_open_wallet_menu->clear();
+ std::vector<std::string> available_wallets = m_wallet_controller->getWalletsAvailableToOpen();
+ std::vector<std::string> wallets = m_node.listWalletDir();
+ for (const auto& path : wallets) {
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
- QAction* action = m_open_wallet_action->menu()->addAction(name);
+ QAction* action = m_open_wallet_menu->addAction(name);
+
+ if (std::find(available_wallets.begin(), available_wallets.end(), path) == available_wallets.end()) {
+ // This wallet is already loaded
+ action->setEnabled(false);
+ continue;
+ }
+
connect(action, &QAction::triggered, [this, name, path] {
OpenWalletActivity* activity = m_wallet_controller->openWallet(path);
@@ -400,6 +410,10 @@ void BitcoinGUI::createActions()
assert(invoked);
});
}
+ if (wallets.empty()) {
+ QAction* action = m_open_wallet_menu->addAction(tr("No wallets available"));
+ action->setEnabled(false);
+ }
});
connect(m_close_wallet_action, &QAction::triggered, [this] {
m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this);
@@ -620,6 +634,9 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
m_wallet_controller = wallet_controller;
+ m_open_wallet_action->setEnabled(true);
+ m_open_wallet_action->setMenu(m_open_wallet_menu);
+
connect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);
@@ -1022,49 +1039,51 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
progressBar->setToolTip(tooltip);
}
-void BitcoinGUI::message(const QString &title, const QString &message, unsigned int style, bool *ret)
+void BitcoinGUI::message(const QString& title, QString message, unsigned int style, bool* ret)
{
- QString strTitle = tr("Bitcoin"); // default title
+ // Default title. On macOS, the window title is ignored (as required by the macOS Guidelines).
+ QString strTitle{PACKAGE_NAME};
// Default to information icon
int nMBoxIcon = QMessageBox::Information;
int nNotifyIcon = Notificator::Information;
- QString msgType;
+ bool prefix = !(style & CClientUIInterface::MSG_NOPREFIX);
+ style &= ~CClientUIInterface::MSG_NOPREFIX;
- // Prefer supplied title over style based title
+ QString msgType;
if (!title.isEmpty()) {
msgType = title;
- }
- else {
+ } else {
switch (style) {
case CClientUIInterface::MSG_ERROR:
msgType = tr("Error");
+ if (prefix) message = tr("Error: %1").arg(message);
break;
case CClientUIInterface::MSG_WARNING:
msgType = tr("Warning");
+ if (prefix) message = tr("Warning: %1").arg(message);
break;
case CClientUIInterface::MSG_INFORMATION:
msgType = tr("Information");
+ // No need to prepend the prefix here.
break;
default:
break;
}
}
- // Append title to "Bitcoin - "
- if (!msgType.isEmpty())
+
+ if (!msgType.isEmpty()) {
strTitle += " - " + msgType;
+ }
- // Check for error/warning icon
if (style & CClientUIInterface::ICON_ERROR) {
nMBoxIcon = QMessageBox::Critical;
nNotifyIcon = Notificator::Critical;
- }
- else if (style & CClientUIInterface::ICON_WARNING) {
+ } else if (style & CClientUIInterface::ICON_WARNING) {
nMBoxIcon = QMessageBox::Warning;
nNotifyIcon = Notificator::Warning;
}
- // Display message
if (style & CClientUIInterface::MODAL) {
// Check for buttons, use OK as default, if none was supplied
QMessageBox::StandardButton buttons;
@@ -1077,9 +1096,9 @@ void BitcoinGUI::message(const QString &title, const QString &message, unsigned
int r = mBox.exec();
if (ret != nullptr)
*ret = r == QMessageBox::Ok;
- }
- else
+ } else {
notificator->notify(static_cast<Notificator::Class>(nNotifyIcon), strTitle, message);
+ }
}
void BitcoinGUI::changeEvent(QEvent *e)
@@ -1328,6 +1347,7 @@ void BitcoinGUI::showProgress(const QString &title, int nProgress)
if (progressDialog) {
progressDialog->close();
progressDialog->deleteLater();
+ progressDialog = nullptr;
}
} else if (progressDialog) {
progressDialog->setValue(nProgress);
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index b58ccbb455..46ced79007 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -148,6 +148,7 @@ private:
QAction* openAction = nullptr;
QAction* showHelpMessageAction = nullptr;
QAction* m_open_wallet_action{nullptr};
+ QMenu* m_open_wallet_menu{nullptr};
QAction* m_close_wallet_action{nullptr};
QAction* m_wallet_selector_label_action = nullptr;
QAction* m_wallet_selector_action = nullptr;
@@ -219,7 +220,7 @@ public Q_SLOTS:
@see CClientUIInterface::MessageBoxFlags
@param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only)
*/
- void message(const QString &title, const QString &message, unsigned int style, bool *ret = nullptr);
+ void message(const QString& title, QString message, unsigned int style, bool* ret = nullptr);
#ifdef ENABLE_WALLET
void setCurrentWallet(WalletModel* wallet_model);
diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp
index 8aa1fdba4d..b27f8a744f 100644
--- a/src/qt/bitcoinunits.cpp
+++ b/src/qt/bitcoinunits.cpp
@@ -4,8 +4,6 @@
#include <qt/bitcoinunits.h>
-#include <primitives/transaction.h>
-
#include <QStringList>
BitcoinUnits::BitcoinUnits(QObject *parent):
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 27b4c182f9..ce950150df 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -9,19 +9,12 @@
#include <qt/guiutil.h>
#include <qt/peertablemodel.h>
-#include <chain.h>
-#include <chainparams.h>
-#include <checkpoints.h>
#include <clientversion.h>
#include <interfaces/handler.h>
#include <interfaces/node.h>
-#include <validation.h>
#include <net.h>
#include <netbase.h>
-#include <txmempool.h>
-#include <ui_interface.h>
#include <util/system.h>
-#include <warnings.h>
#include <stdint.h>
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 0d9f1adcd2..6b9f79aaf8 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -10,12 +10,10 @@
#include <qt/forms/ui_coincontroldialog.h>
#include <qt/addresstablemodel.h>
-#include <base58.h>
#include <qt/bitcoinunits.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
-#include <txmempool.h>
#include <qt/walletmodel.h>
#include <wallet/coincontrol.h>
@@ -23,8 +21,6 @@
#include <key_io.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <validation.h> // For mempool
-#include <wallet/fees.h>
#include <wallet/wallet.h>
#include <QApplication>
@@ -471,8 +467,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
else if(ExtractDestination(out.txout.scriptPubKey, address))
{
CPubKey pubkey;
- CKeyID *keyid = boost::get<CKeyID>(&address);
- if (keyid && model->wallet().getPubKey(*keyid, pubkey))
+ PKHash *pkhash = boost::get<PKHash>(&address);
+ if (pkhash && model->wallet().getPubKey(CKeyID(*pkhash), pubkey))
{
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
}
diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui
index bd7f3c5f56..5ce469ee96 100644
--- a/src/qt/forms/coincontroldialog.ui
+++ b/src/qt/forms/coincontroldialog.ui
@@ -467,12 +467,6 @@
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index f0b976001e..6e52c5e477 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -636,6 +636,9 @@
<property name="placeholderText">
<string/>
</property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
</widget>
</item>
</layout>
@@ -1480,6 +1483,19 @@
</property>
</widget>
</item>
+ <item row="18" column="0">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</widget>
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui
index 2f916d0b44..0d280f2993 100644
--- a/src/qt/forms/receivecoinsdialog.ui
+++ b/src/qt/forms/receivecoinsdialog.ui
@@ -108,7 +108,7 @@
</size>
</property>
<property name="text">
- <string>&amp;Request payment</string>
+ <string>&amp;Create new receiving address</string>
</property>
<property name="icon">
<iconset resource="../bitcoin.qrc">
@@ -189,7 +189,7 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="useBech32">
+ <widget class="QCheckBox" name="useLegacyAddress">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -206,10 +206,10 @@
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
- <string>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</string>
+ <string>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When checked, an address compatible with older wallets will be created instead.</string>
</property>
<property name="text">
- <string>Generate native segwit (Bech32) address</string>
+ <string>Generate legacy address</string>
</property>
</widget>
</item>
@@ -360,7 +360,7 @@
<tabstops>
<tabstop>reqLabel</tabstop>
<tabstop>reqAmount</tabstop>
- <tabstop>useBech32</tabstop>
+ <tabstop>useLegacyAddress</tabstop>
<tabstop>reqMessage</tabstop>
<tabstop>receiveButton</tabstop>
<tabstop>clearButton</tabstop>
diff --git a/src/qt/forms/receiverequestdialog.ui b/src/qt/forms/receiverequestdialog.ui
index dbe966b241..9f896ee3b1 100644
--- a/src/qt/forms/receiverequestdialog.ui
+++ b/src/qt/forms/receiverequestdialog.ui
@@ -127,7 +127,7 @@
<customwidget>
<class>QRImageWidget</class>
<extends>QLabel</extends>
- <header>qt/receiverequestdialog.h</header>
+ <header>qt/qrimagewidget.h</header>
</customwidget>
</customwidgets>
<resources/>
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index 736ff13a4a..d8f5594983 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -37,12 +37,6 @@ static const bool DEFAULT_SPLASHSCREEN = true;
*/
static const int TOOLTIP_WRAP_THRESHOLD = 80;
-/* Maximum allowed URI length */
-static const int MAX_URI_LENGTH = 255;
-
-/* QRCodeDialog -- size of exported QR Code image */
-#define QR_IMAGE_SIZE 300
-
/* Number of frames in spinner animation */
#define SPINNER_FRAMES 36
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index ba0a5abdf3..70e52c9f1d 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -60,6 +60,7 @@
#include <objc/objc-runtime.h>
#include <CoreServices/CoreServices.h>
+#include <QProcess>
#endif
namespace GUIUtil {
@@ -175,7 +176,9 @@ bool parseBitcoinURI(QString uri, SendCoinsRecipient *out)
QString formatBitcoinURI(const SendCoinsRecipient &info)
{
- QString ret = QString("bitcoin:%1").arg(info.address);
+ bool bech_32 = info.address.startsWith(QString::fromStdString(Params().Bech32HRP() + "1"));
+
+ QString ret = QString("bitcoin:%1").arg(bech_32 ? info.address.toUpper() : info.address);
int paramCount = 0;
if (info.amount)
@@ -244,6 +247,11 @@ QList<QModelIndex> getEntryData(QAbstractItemView *view, int column)
return view->selectionModel()->selectedRows(column);
}
+QString getDefaultDataDirectory()
+{
+ return boostPathToQString(GetDefaultDataDir());
+}
+
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
@@ -392,7 +400,15 @@ bool openBitcoinConf()
configFile.close();
/* Open bitcoin.conf with the associated application */
- return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
+ bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig)));
+#ifdef Q_OS_MAC
+ // Workaround for macOS-specific behavior; see #15409.
+ if (!res) {
+ res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", boostPathToQString(pathConfig)});
+ }
+#endif
+
+ return res;
}
ToolTipToRichTextFilter::ToolTipToRichTextFilter(int _size_threshold, QObject *parent) :
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index cbec73a882..bea4a83494 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -79,6 +79,11 @@ namespace GUIUtil
void setClipboard(const QString& str);
+ /**
+ * Determine default data directory for operating system.
+ */
+ QString getDefaultDataDirectory();
+
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
when no suffix is provided by the user.
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 499af9fa07..c595361934 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -168,7 +168,7 @@ QString Intro::getDataDirectory()
void Intro::setDataDirectory(const QString &dataDir)
{
ui->dataDirectory->setText(dataDir);
- if(dataDir == getDefaultDataDirectory())
+ if(dataDir == GUIUtil::getDefaultDataDirectory())
{
ui->dataDirDefault->setChecked(true);
ui->dataDirectory->setEnabled(false);
@@ -180,11 +180,6 @@ void Intro::setDataDirectory(const QString &dataDir)
}
}
-QString Intro::getDefaultDataDirectory()
-{
- return GUIUtil::boostPathToQString(GetDefaultDataDir());
-}
-
bool Intro::pickDataDirectory(interfaces::Node& node)
{
QSettings settings;
@@ -193,7 +188,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
if(!gArgs.GetArg("-datadir", "").empty())
return true;
/* 1) Default data directory for operating system */
- QString dataDir = getDefaultDataDirectory();
+ QString dataDir = GUIUtil::getDefaultDataDirectory();
/* 2) Allow QSettings to override default dir */
dataDir = settings.value("strDataDir", dataDir).toString();
@@ -239,7 +234,7 @@ bool Intro::pickDataDirectory(interfaces::Node& node)
* override -datadir in the bitcoin.conf file in the default data directory
* (to be consistent with bitcoind behavior)
*/
- if(dataDir != getDefaultDataDirectory()) {
+ if(dataDir != GUIUtil::getDefaultDataDirectory()) {
node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting
}
return true;
@@ -293,7 +288,7 @@ void Intro::on_ellipsisButton_clicked()
void Intro::on_dataDirDefault_clicked()
{
- setDataDirectory(getDefaultDataDirectory());
+ setDataDirectory(GUIUtil::getDefaultDataDirectory());
}
void Intro::on_dataDirCustom_clicked()
diff --git a/src/qt/intro.h b/src/qt/intro.h
index b537c94f7d..c3b26808d4 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -48,11 +48,6 @@ public:
*/
static bool pickDataDirectory(interfaces::Node& node);
- /**
- * Determine default data directory for operating system.
- */
- static QString getDefaultDataDirectory();
-
Q_SIGNALS:
void requestCheck();
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 9094aeff56..40dc7bf400 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -154,6 +154,10 @@ void OptionsDialog::setModel(OptionsModel *_model)
if (_model->isRestartRequired())
showRestartWarning(true);
+ // Prune values are in GB to be consistent with intro.cpp
+ static constexpr uint64_t nMinDiskSpace = (MIN_DISK_SPACE_FOR_BLOCK_FILES / GB_BYTES) + (MIN_DISK_SPACE_FOR_BLOCK_FILES % GB_BYTES) ? 1 : 0;
+ ui->pruneSize->setRange(nMinDiskSpace, std::numeric_limits<int>::max());
+
QString strLabel = _model->getOverriddenByCommandLine();
if (strLabel.isEmpty())
strLabel = tr("none");
@@ -164,10 +168,6 @@ void OptionsDialog::setModel(OptionsModel *_model)
mapper->toFirst();
updateDefaultProxyNets();
-
- // Prune values are in GB to be consistent with intro.cpp
- static constexpr uint64_t nMinDiskSpace = (MIN_DISK_SPACE_FOR_BLOCK_FILES / GB_BYTES) + (MIN_DISK_SPACE_FOR_BLOCK_FILES % GB_BYTES) ? 1 : 0;
- ui->pruneSize->setRange(nMinDiskSpace, _model->node().getAssumedBlockchainSize());
}
/* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 62496a57f4..f3974b1c85 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -17,7 +17,6 @@
#include <net.h>
#include <netbase.h>
#include <txdb.h> // for -dbcache defaults
-#include <qt/intro.h>
#include <QNetworkProxy>
#include <QSettings>
@@ -110,7 +109,7 @@ void OptionsModel::Init(bool resetSettings)
addOverriddenOption("-par");
if (!settings.contains("strDataDir"))
- settings.setValue("strDataDir", Intro::getDefaultDataDirectory());
+ settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory());
// Wallet
#ifdef ENABLE_WALLET
@@ -173,7 +172,7 @@ static void CopySettings(QSettings& dst, const QSettings& src)
/** Back up a QSettings to an ini-formatted file. */
static void BackupSettings(const fs::path& filename, const QSettings& src)
{
- qWarning() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
+ qInfo() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
dst.clear();
CopySettings(dst, src);
@@ -187,7 +186,7 @@ void OptionsModel::Reset()
BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
// Save the strDataDir setting
- QString dataDir = Intro::getDefaultDataDirectory();
+ QString dataDir = GUIUtil::getDefaultDataDirectory();
dataDir = settings.value("strDataDir", dataDir).toString();
// Remove all entries from our QSettings object
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 43dccec4ea..c99515fe1c 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -488,7 +488,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
continue;
}
}
- qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
+ qInfo() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
// Project for another day:
// Fetch certificate revocation lists, and add them to certStore.
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 496aeebf7d..85b691c470 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -9,7 +9,6 @@
#include <qt/guiutil.h>
#include <interfaces/node.h>
-#include <validation.h> // for cs_main
#include <sync.h>
#include <QDebug>
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
index d537d759de..fca2a4e8c5 100644
--- a/src/qt/platformstyle.cpp
+++ b/src/qt/platformstyle.cpp
@@ -4,8 +4,6 @@
#include <qt/platformstyle.h>
-#include <qt/guiconstants.h>
-
#include <QApplication>
#include <QColor>
#include <QImage>
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
new file mode 100644
index 0000000000..bf1baf5470
--- /dev/null
+++ b/src/qt/qrimagewidget.cpp
@@ -0,0 +1,141 @@
+// Copyright (c) 2011-2018 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 <qt/qrimagewidget.h>
+
+#include <qt/guiutil.h>
+
+#include <QApplication>
+#include <QClipboard>
+#include <QDrag>
+#include <QMenu>
+#include <QMimeData>
+#include <QMouseEvent>
+#include <QPainter>
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h> /* for USE_QRCODE */
+#endif
+
+#ifdef USE_QRCODE
+#include <qrencode.h>
+#endif
+
+QRImageWidget::QRImageWidget(QWidget *parent):
+ QLabel(parent), contextMenu(nullptr)
+{
+ contextMenu = new QMenu(this);
+ QAction *saveImageAction = new QAction(tr("&Save Image..."), this);
+ connect(saveImageAction, &QAction::triggered, this, &QRImageWidget::saveImage);
+ contextMenu->addAction(saveImageAction);
+ QAction *copyImageAction = new QAction(tr("&Copy Image"), this);
+ connect(copyImageAction, &QAction::triggered, this, &QRImageWidget::copyImage);
+ contextMenu->addAction(copyImageAction);
+}
+
+bool QRImageWidget::setQR(const QString& data, const QString& text)
+{
+#ifdef USE_QRCODE
+ setText("");
+ if (data.isEmpty()) return false;
+
+ // limit length
+ if (data.length() > MAX_URI_LENGTH) {
+ setText(tr("Resulting URI too long, try to reduce the text for label / message."));
+ return false;
+ }
+
+ QRcode *code = QRcode_encodeString(data.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
+
+ if (!code) {
+ setText(tr("Error encoding URI into QR Code."));
+ return false;
+ }
+
+ QImage qrImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
+ qrImage.fill(0xffffff);
+ unsigned char *p = code->data;
+ for (int y = 0; y < code->width; ++y) {
+ for (int x = 0; x < code->width; ++x) {
+ qrImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
+ ++p;
+ }
+ }
+ QRcode_free(code);
+
+ QImage qrAddrImage = QImage(QR_IMAGE_SIZE, QR_IMAGE_SIZE + (text.isEmpty() ? 0 : 20), QImage::Format_RGB32);
+ qrAddrImage.fill(0xffffff);
+ QPainter painter(&qrAddrImage);
+ painter.drawImage(0, 0, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE));
+
+ if (!text.isEmpty()) {
+ QFont font = GUIUtil::fixedPitchFont();
+ QRect paddedRect = qrAddrImage.rect();
+
+ // calculate ideal font size
+ qreal font_size = GUIUtil::calculateIdealFontSize(paddedRect.width() - 20, text, font);
+ font.setPointSizeF(font_size);
+
+ painter.setFont(font);
+ paddedRect.setHeight(QR_IMAGE_SIZE+12);
+ painter.drawText(paddedRect, Qt::AlignBottom|Qt::AlignCenter, text);
+ }
+
+ painter.end();
+ setPixmap(QPixmap::fromImage(qrAddrImage));
+
+ return true;
+#else
+ setText(tr("QR code support not available."));
+ return false;
+#endif
+}
+
+QImage QRImageWidget::exportImage()
+{
+ if(!pixmap())
+ return QImage();
+ return pixmap()->toImage();
+}
+
+void QRImageWidget::mousePressEvent(QMouseEvent *event)
+{
+ if(event->button() == Qt::LeftButton && pixmap())
+ {
+ event->accept();
+ QMimeData *mimeData = new QMimeData;
+ mimeData->setImageData(exportImage());
+
+ QDrag *drag = new QDrag(this);
+ drag->setMimeData(mimeData);
+ drag->exec();
+ } else {
+ QLabel::mousePressEvent(event);
+ }
+}
+
+void QRImageWidget::saveImage()
+{
+ if(!pixmap())
+ return;
+ QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr);
+ if (!fn.isEmpty())
+ {
+ exportImage().save(fn);
+ }
+}
+
+void QRImageWidget::copyImage()
+{
+ if(!pixmap())
+ return;
+ QApplication::clipboard()->setImage(exportImage());
+}
+
+void QRImageWidget::contextMenuEvent(QContextMenuEvent *event)
+{
+ if(!pixmap())
+ return;
+ contextMenu->exec(event->globalPos());
+}
diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h
new file mode 100644
index 0000000000..2a219ac101
--- /dev/null
+++ b/src/qt/qrimagewidget.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011-2018 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_QRIMAGEWIDGET_H
+#define BITCOIN_QT_QRIMAGEWIDGET_H
+
+#include <QImage>
+#include <QLabel>
+
+/* Maximum allowed URI length */
+static const int MAX_URI_LENGTH = 255;
+
+/* Size of exported QR Code image */
+static const int QR_IMAGE_SIZE = 300;
+
+QT_BEGIN_NAMESPACE
+class QMenu;
+QT_END_NAMESPACE
+
+/* Label widget for QR code. This image can be dragged, dropped, copied and saved
+ * to disk.
+ */
+class QRImageWidget : public QLabel
+{
+ Q_OBJECT
+
+public:
+ explicit QRImageWidget(QWidget *parent = nullptr);
+ bool setQR(const QString& data, const QString& text = "");
+ QImage exportImage();
+
+public Q_SLOTS:
+ void saveImage();
+ void copyImage();
+
+protected:
+ virtual void mousePressEvent(QMouseEvent *event);
+ virtual void contextMenuEvent(QContextMenuEvent *event);
+
+private:
+ QMenu *contextMenu;
+};
+
+#endif // BITCOIN_QT_QRIMAGEWIDGET_H
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 22a79a12bb..c58717e21e 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -7,9 +7,7 @@
#include <qt/receivecoinsdialog.h>
#include <qt/forms/ui_receivecoinsdialog.h>
-#include <qt/addressbookpage.h>
#include <qt/addresstablemodel.h>
-#include <qt/bitcoinunits.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
#include <qt/receiverequestdialog.h>
@@ -95,9 +93,9 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model)
columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(tableView, AMOUNT_MINIMUM_COLUMN_WIDTH, DATE_COLUMN_WIDTH, this);
if (model->wallet().getDefaultAddressType() == OutputType::BECH32) {
- ui->useBech32->setCheckState(Qt::Checked);
+ ui->useLegacyAddress->setCheckState(Qt::Unchecked);
} else {
- ui->useBech32->setCheckState(Qt::Unchecked);
+ ui->useLegacyAddress->setCheckState(Qt::Checked);
}
// Set the button to be enabled or disabled based on whether the wallet can give out new addresses.
@@ -150,7 +148,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
QString label = ui->reqLabel->text();
/* Generate new receiving address */
OutputType address_type;
- if (ui->useBech32->isChecked()) {
+ if (!ui->useLegacyAddress->isChecked()) {
address_type = OutputType::BECH32;
} else {
address_type = model->wallet().getDefaultAddressType();
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index f5b30cf6d2..e492502002 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -6,85 +6,16 @@
#include <qt/forms/ui_receiverequestdialog.h>
#include <qt/bitcoinunits.h>
-#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <QClipboard>
-#include <QDrag>
-#include <QMenu>
-#include <QMimeData>
-#include <QMouseEvent>
#include <QPixmap>
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h> /* for USE_QRCODE */
#endif
-#ifdef USE_QRCODE
-#include <qrencode.h>
-#endif
-
-QRImageWidget::QRImageWidget(QWidget *parent):
- QLabel(parent), contextMenu(nullptr)
-{
- contextMenu = new QMenu(this);
- QAction *saveImageAction = new QAction(tr("&Save Image..."), this);
- connect(saveImageAction, &QAction::triggered, this, &QRImageWidget::saveImage);
- contextMenu->addAction(saveImageAction);
- QAction *copyImageAction = new QAction(tr("&Copy Image"), this);
- connect(copyImageAction, &QAction::triggered, this, &QRImageWidget::copyImage);
- contextMenu->addAction(copyImageAction);
-}
-
-QImage QRImageWidget::exportImage()
-{
- if(!pixmap())
- return QImage();
- return pixmap()->toImage();
-}
-
-void QRImageWidget::mousePressEvent(QMouseEvent *event)
-{
- if(event->button() == Qt::LeftButton && pixmap())
- {
- event->accept();
- QMimeData *mimeData = new QMimeData;
- mimeData->setImageData(exportImage());
-
- QDrag *drag = new QDrag(this);
- drag->setMimeData(mimeData);
- drag->exec();
- } else {
- QLabel::mousePressEvent(event);
- }
-}
-
-void QRImageWidget::saveImage()
-{
- if(!pixmap())
- return;
- QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), nullptr);
- if (!fn.isEmpty())
- {
- exportImage().save(fn);
- }
-}
-
-void QRImageWidget::copyImage()
-{
- if(!pixmap())
- return;
- QApplication::clipboard()->setImage(exportImage());
-}
-
-void QRImageWidget::contextMenuEvent(QContextMenuEvent *event)
-{
- if(!pixmap())
- return;
- contextMenu->exec(event->globalPos());
-}
-
ReceiveRequestDialog::ReceiveRequestDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ReceiveRequestDialog),
@@ -150,55 +81,9 @@ void ReceiveRequestDialog::update()
}
ui->outUri->setText(html);
-#ifdef USE_QRCODE
- ui->lblQRCode->setText("");
- if(!uri.isEmpty())
- {
- // limit URI length
- if (uri.length() > MAX_URI_LENGTH)
- {
- ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message."));
- } else {
- QRcode *code = QRcode_encodeString(uri.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
- if (!code)
- {
- ui->lblQRCode->setText(tr("Error encoding URI into QR Code."));
- return;
- }
- QImage qrImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
- qrImage.fill(0xffffff);
- unsigned char *p = code->data;
- for (int y = 0; y < code->width; y++)
- {
- for (int x = 0; x < code->width; x++)
- {
- qrImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
- p++;
- }
- }
- QRcode_free(code);
-
- QImage qrAddrImage = QImage(QR_IMAGE_SIZE, QR_IMAGE_SIZE+20, QImage::Format_RGB32);
- qrAddrImage.fill(0xffffff);
- QPainter painter(&qrAddrImage);
- painter.drawImage(0, 0, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE));
- QFont font = GUIUtil::fixedPitchFont();
- QRect paddedRect = qrAddrImage.rect();
-
- // calculate ideal font size
- qreal font_size = GUIUtil::calculateIdealFontSize(paddedRect.width() - 20, info.address, font);
- font.setPointSizeF(font_size);
-
- painter.setFont(font);
- paddedRect.setHeight(QR_IMAGE_SIZE+12);
- painter.drawText(paddedRect, Qt::AlignBottom|Qt::AlignCenter, info.address);
- painter.end();
-
- ui->lblQRCode->setPixmap(QPixmap::fromImage(qrAddrImage));
- ui->btnSaveAs->setEnabled(true);
- }
+ if (ui->lblQRCode->setQR(uri, info.address)) {
+ ui->btnSaveAs->setEnabled(true);
}
-#endif
}
void ReceiveRequestDialog::on_btnCopyURI_clicked()
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index dd28fd73c8..a6e1a2af16 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -8,41 +8,11 @@
#include <qt/walletmodel.h>
#include <QDialog>
-#include <QImage>
-#include <QLabel>
-#include <QPainter>
namespace Ui {
class ReceiveRequestDialog;
}
-QT_BEGIN_NAMESPACE
-class QMenu;
-QT_END_NAMESPACE
-
-/* Label widget for QR code. This image can be dragged, dropped, copied and saved
- * to disk.
- */
-class QRImageWidget : public QLabel
-{
- Q_OBJECT
-
-public:
- explicit QRImageWidget(QWidget *parent = nullptr);
- QImage exportImage();
-
-public Q_SLOTS:
- void saveImage();
- void copyImage();
-
-protected:
- virtual void mousePressEvent(QMouseEvent *event);
- virtual void contextMenuEvent(QContextMenuEvent *event);
-
-private:
- QMenu *contextMenu;
-};
-
class ReceiveRequestDialog : public QDialog
{
Q_OBJECT
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index fc1e14b031..071a197c3c 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -21,8 +21,6 @@
#include <util/strencodings.h>
#include <util/system.h>
-#include <openssl/crypto.h>
-
#include <univalue.h>
#ifdef ENABLE_WALLET
@@ -69,7 +67,6 @@ const QStringList historyFilter = QStringList()
<< "importmulti"
<< "sethdseed"
<< "signmessagewithprivkey"
- << "signrawtransaction"
<< "signrawtransactionwithkey"
<< "walletpassphrase"
<< "walletpassphrasechange"
@@ -680,6 +677,9 @@ void RPCConsole::setClientModel(ClientModel *model)
wordList.sort();
autoCompleter = new QCompleter(wordList, this);
autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
+ // ui->lineEdit is initially disabled because running commands is only
+ // possible from now on.
+ ui->lineEdit->setEnabled(true);
ui->lineEdit->setCompleter(autoCompleter);
autoCompleter->popup()->installEventFilter(this);
// Start thread to execute RPC commands.
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 6e00ab755c..cb9efe9319 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -279,18 +279,16 @@ void SendCoinsDialog::on_sendButton_clicked()
QStringList formatted;
for (const SendCoinsRecipient &rcp : currentTransaction.getRecipients())
{
- // generate bold amount string with wallet name in case of multiwallet
- QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
+ // generate amount string with wallet name in case of multiwallet
+ QString amount = BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
if (model->isMultiwallet()) {
- amount.append(" <u>"+tr("from wallet %1").arg(GUIUtil::HtmlEscape(model->getWalletName()))+"</u> ");
+ amount.append(tr(" from wallet '%1'").arg(model->getWalletName()));
}
- amount.append("</b>");
- // generate monospace address string
- QString address = "<span style='font-family: monospace;'>" + rcp.address;
- address.append("</span>");
+
+ // generate address string
+ QString address = rcp.address;
QString recipientElement;
- recipientElement = "<br />";
#ifdef ENABLE_BIP70
if (!rcp.paymentRequest.IsInitialized()) // normal payment
@@ -298,7 +296,7 @@ void SendCoinsDialog::on_sendButton_clicked()
{
if(rcp.label.length() > 0) // label with address
{
- recipientElement.append(tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.label)));
+ recipientElement.append(tr("%1 to '%2'").arg(amount, rcp.label));
recipientElement.append(QString(" (%1)").arg(address));
}
else // just address
@@ -309,7 +307,7 @@ void SendCoinsDialog::on_sendButton_clicked()
#ifdef ENABLE_BIP70
else if(!rcp.authenticatedMerchant.isEmpty()) // authenticated payment request
{
- recipientElement.append(tr("%1 to %2").arg(amount, GUIUtil::HtmlEscape(rcp.authenticatedMerchant)));
+ recipientElement.append(tr("%1 to '%2'").arg(amount, rcp.authenticatedMerchant));
}
else // unauthenticated payment request
{
@@ -323,7 +321,7 @@ void SendCoinsDialog::on_sendButton_clicked()
QString questionString = tr("Are you sure you want to send?");
questionString.append("<br /><span style='font-size:10pt;'>");
questionString.append(tr("Please, review your transaction."));
- questionString.append("</span><br />%1");
+ questionString.append("</span>%1");
if(txFee > 0)
{
@@ -364,8 +362,17 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append(QString("<br /><span style='font-size:10pt; font-weight:normal;'>(=%1)</span>")
.arg(alternativeUnits.join(" " + tr("or") + " ")));
- SendConfirmationDialog confirmationDialog(tr("Confirm send coins"),
- questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this);
+ QString informative_text;
+ QString detailed_text;
+ if (formatted.size() > 1) {
+ questionString = questionString.arg("");
+ informative_text = tr("To review recipient list click \"Show Details...\"");
+ detailed_text = formatted.join("\n\n");
+ } else {
+ questionString = questionString.arg("<br /><br />" + formatted.at(0));
+ }
+
+ SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), questionString, informative_text, detailed_text, SEND_CONFIRM_DELAY, this);
confirmationDialog.exec();
QMessageBox::StandardButton retval = static_cast<QMessageBox::StandardButton>(confirmationDialog.result());
@@ -578,7 +585,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
msgParams.second = CClientUIInterface::MSG_ERROR;
break;
case WalletModel::AbsurdFee:
- msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->node().getMaxTxFee()));
+ msgParams.first = tr("A fee higher than %1 is considered an absurdly high fee.").arg(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->wallet().getDefaultMaxTxFee()));
break;
case WalletModel::PaymentRequestExpired:
msgParams.first = tr("Payment request expired.");
@@ -881,10 +888,15 @@ void SendCoinsDialog::coinControlUpdateLabels()
}
}
-SendConfirmationDialog::SendConfirmationDialog(const QString &title, const QString &text, int _secDelay,
- QWidget *parent) :
- QMessageBox(QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::Cancel, parent), secDelay(_secDelay)
+SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, QWidget* parent)
+ : QMessageBox(parent), secDelay(_secDelay)
{
+ setIcon(QMessageBox::Question);
+ setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines).
+ setText(text);
+ setInformativeText(informative_text);
+ setDetailedText(detailed_text);
+ setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
setDefaultButton(QMessageBox::Cancel);
yesButton = button(QMessageBox::Yes);
updateYesButton();
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 337a72b878..c6c1816877 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -108,7 +108,7 @@ class SendConfirmationDialog : public QMessageBox
Q_OBJECT
public:
- SendConfirmationDialog(const QString &title, const QString &text, int secDelay = SEND_CONFIRM_DELAY, QWidget *parent = nullptr);
+ SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, QWidget* parent = nullptr);
int exec();
private Q_SLOTS:
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index d37a78fa8c..71f5f2ae75 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -11,7 +11,7 @@
#include <qt/walletmodel.h>
#include <key_io.h>
-#include <validation.h> // For strMessageMagic
+#include <util/validation.h> // For strMessageMagic
#include <wallet/wallet.h>
#include <string>
@@ -120,8 +120,8 @@ 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 CKeyID* keyID = boost::get<CKeyID>(&destination);
- if (!keyID) {
+ const PKHash* pkhash = boost::get<PKHash>(&destination);
+ if (!pkhash) {
ui->addressIn_SM->setValid(false);
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -137,7 +137,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
- if (!model->wallet().getPrivKey(*keyID, key))
+ if (!model->wallet().getPrivKey(CKeyID(*pkhash), key))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
@@ -198,7 +198,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again."));
return;
}
- if (!boost::get<CKeyID>(&destination)) {
+ if (!boost::get<PKHash>(&destination)) {
ui->addressIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again."));
@@ -229,7 +229,7 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- if (!(CTxDestination(pubkey.GetID()) == destination)) {
+ if (!(CTxDestination(PKHash(pubkey)) == destination)) {
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>"));
return;
diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp
index 7f5e92ea9f..11a518ebd2 100644
--- a/src/qt/test/addressbooktests.cpp
+++ b/src/qt/test/addressbooktests.cpp
@@ -1,11 +1,9 @@
#include <qt/test/addressbooktests.h>
#include <qt/test/util.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <interfaces/chain.h>
#include <interfaces/node.h>
-#include <qt/addressbookpage.h>
-#include <qt/addresstablemodel.h>
#include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
@@ -14,7 +12,6 @@
#include <key.h>
#include <key_io.h>
-#include <pubkey.h>
#include <wallet/wallet.h>
#include <QApplication>
@@ -58,7 +55,7 @@ void TestAddAddressesToSendBook()
{
TestChain100Setup test;
auto chain = interfaces::MakeChain();
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateMock());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp
index da25d83175..a900ec0198 100644
--- a/src/qt/test/apptests.cpp
+++ b/src/qt/test/apptests.cpp
@@ -5,7 +5,7 @@
#include <qt/test/apptests.h>
#include <chainparams.h>
-#include <init.h>
+#include <key.h>
#include <qt/bitcoin.h>
#include <qt/bitcoingui.h>
#include <qt/networkstyle.h>
@@ -16,9 +16,6 @@
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
-#ifdef ENABLE_WALLET
-#include <wallet/db.h>
-#endif
#include <QAction>
#include <QEventLoop>
@@ -29,7 +26,6 @@
#include <QtGlobal>
#include <QtTest/QtTestWidgets>
#include <QtTest/QtTestGui>
-#include <new>
#include <string>
#include <univalue.h>
@@ -66,6 +62,9 @@ void AppTests::appTests()
}
#endif
+ ECC_Stop(); // Already started by the common test setup, so stop it to avoid interference
+ LogInstance().DisconnectTestLogger();
+
m_app.parameterSetup();
m_app.createOptionsModel(true /* reset settings */);
QScopedPointer<const NetworkStyle> style(
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index f8a9c25303..3735f41f9d 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -4,15 +4,10 @@
#include <qt/test/rpcnestedtests.h>
-#include <chainparams.h>
-#include <consensus/validation.h>
-#include <fs.h>
#include <interfaces/node.h>
-#include <validation.h>
-#include <rpc/register.h>
#include <rpc/server.h>
#include <qt/rpcconsole.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <univalue.h>
#include <util/system.h>
@@ -39,6 +34,9 @@ void RPCNestedTests::rpcNestedTests()
tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
//mempool.setSanityCheck(1.0);
+ ECC_Stop(); // Already started by the common test setup, so stop it to avoid interference
+ LogInstance().DisconnectTestLogger();
+
TestingSetup test;
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
diff --git a/src/qt/test/rpcnestedtests.h b/src/qt/test/rpcnestedtests.h
index e33f4e3da1..97143ff78a 100644
--- a/src/qt/test/rpcnestedtests.h
+++ b/src/qt/test/rpcnestedtests.h
@@ -8,9 +8,6 @@
#include <QObject>
#include <QTest>
-#include <txdb.h>
-#include <txmempool.h>
-
class RPCNestedTests : public QObject
{
Q_OBJECT
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index a2bf53973b..79d88ab742 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -6,14 +6,13 @@
#include <config/bitcoin-config.h>
#endif
-#include <chainparams.h>
#include <interfaces/node.h>
#include <qt/bitcoin.h>
#include <qt/test/apptests.h>
#include <qt/test/rpcnestedtests.h>
-#include <util/system.h>
#include <qt/test/uritests.h>
#include <qt/test/compattests.h>
+#include <test/setup_common.h>
#ifdef ENABLE_WALLET
#include <qt/test/addressbooktests.h>
@@ -48,14 +47,8 @@ extern void noui_connect();
// This is all you need to run all the tests
int main(int argc, char *argv[])
{
- SetupEnvironment();
- SetupNetworking();
- SelectParams(CBaseChainParams::REGTEST);
- noui_connect();
- ClearDatadirCache();
- fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000));
- fs::create_directories(pathTemp);
- gArgs.ForceSetArg("-datadir", pathTemp.string());
+ BasicTestingSetup test{CBaseChainParams::REGTEST};
+
auto node = interfaces::MakeNode();
bool fInvalid = false;
@@ -109,7 +102,5 @@ int main(int argc, char *argv[])
}
#endif
- fs::remove_all(pathTemp);
-
return fInvalid;
}
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index 2b50a2ba81..e54915ec75 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -1,10 +1,8 @@
#include <qt/test/wallettests.h>
#include <qt/test/util.h>
-#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/node.h>
-#include <base58.h>
#include <qt/bitcoinamountfield.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
@@ -15,7 +13,7 @@
#include <qt/transactionview.h>
#include <qt/walletmodel.h>
#include <key_io.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <validation.h>
#include <wallet/wallet.h>
#include <qt/overviewpage.h>
@@ -135,7 +133,7 @@ void TestGUI()
test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
}
auto chain = interfaces::MakeChain();
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateMock());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
{
@@ -145,11 +143,13 @@ void TestGUI()
}
{
auto locked_chain = wallet->chain().lock();
+ LockAssertion lock(::cs_main);
+
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
CWallet::ScanResult result = wallet->ScanForWalletTransactions(locked_chain->getBlockHash(0), {} /* stop_block */, reserver, true /* fUpdate */);
QCOMPARE(result.status, CWallet::ScanResult::SUCCESS);
- QCOMPARE(result.last_scanned_block, chainActive.Tip()->GetBlockHash());
+ QCOMPARE(result.last_scanned_block, ::ChainActive().Tip()->GetBlockHash());
QVERIFY(result.last_failed_block.IsNull());
}
wallet->SetBroadcastTransactions(true);
@@ -169,8 +169,8 @@ void TestGUI()
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
QCOMPARE(transactionTableModel->rowCount({}), 105);
- uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
- uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
+ uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, false /* rbf */);
+ uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, true /* rbf */);
QCOMPARE(transactionTableModel->rowCount({}), 107);
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 0d070d9e87..ebe7925368 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -20,9 +20,8 @@
#include <script/script.h>
#include <timedata.h>
#include <util/system.h>
-#include <wallet/db.h>
-#include <wallet/wallet.h>
#include <policy/policy.h>
+#include <wallet/ismine.h>
#include <stdint.h>
#include <string>
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index aa785553c8..9de90759fa 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -5,11 +5,9 @@
#include <qt/transactionrecord.h>
#include <chain.h>
-#include <consensus/consensus.h>
#include <interfaces/wallet.h>
#include <key_io.h>
-#include <timedata.h>
-#include <validation.h>
+#include <wallet/ismine.h>
#include <stdint.h>
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 631a9b891d..6fe35b13cf 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -15,11 +15,7 @@
#include <core_io.h>
#include <interfaces/handler.h>
-#include <interfaces/node.h>
-#include <sync.h>
#include <uint256.h>
-#include <util/system.h>
-#include <validation.h>
#include <QColor>
#include <QDateTime>
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 762ec434a1..17e174e57a 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -10,7 +10,6 @@
#include <qt/editaddressdialog.h>
#include <qt/optionsmodel.h>
#include <qt/platformstyle.h>
-#include <qt/sendcoinsdialog.h>
#include <qt/transactiondescdialog.h>
#include <qt/transactionfilterproxy.h>
#include <qt/transactionrecord.h>
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index b051dd159b..aa810690c9 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -11,17 +11,12 @@
#include <qt/forms/ui_helpmessagedialog.h>
#include <qt/bitcoingui.h>
-#include <qt/clientmodel.h>
-#include <qt/guiconstants.h>
-#include <qt/intro.h>
#ifdef ENABLE_BIP70
#include <qt/paymentrequestplus.h>
#endif
-#include <qt/guiutil.h>
#include <clientversion.h>
#include <init.h>
-#include <interfaces/node.h>
#include <util/system.h>
#include <util/strencodings.h>
@@ -129,7 +124,7 @@ HelpMessageDialog::~HelpMessageDialog()
void HelpMessageDialog::printToConsole()
{
// On other operating systems, the expected action is to print the message to the console.
- fprintf(stdout, "%s\n", qPrintable(text));
+ tfm::format(std::cout, "%s\n", qPrintable(text));
}
void HelpMessageDialog::showOrPrint()
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index fab86a7912..019bd65823 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -9,9 +9,11 @@
#include <algorithm>
+#include <QApplication>
#include <QMessageBox>
#include <QMutexLocker>
#include <QThread>
+#include <QWindow>
WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent)
: QObject(parent)
@@ -97,7 +99,17 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
m_wallets.push_back(wallet_model);
connect(wallet_model, &WalletModel::unload, [this, wallet_model] {
- removeAndDeleteWallet(wallet_model);
+ // Defer removeAndDeleteWallet when no modal widget is active.
+ // TODO: remove this workaround by removing usage of QDiallog::exec.
+ if (QApplication::activeModalWidget()) {
+ connect(qApp, &QApplication::focusWindowChanged, wallet_model, [this, wallet_model]() {
+ if (!QApplication::activeModalWidget()) {
+ removeAndDeleteWallet(wallet_model);
+ }
+ }, Qt::QueuedConnection);
+ } else {
+ removeAndDeleteWallet(wallet_model);
+ }
});
// Re-emit coinsSent signal from wallet model.
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 466f2278eb..94413547d4 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -40,15 +40,11 @@ void WalletFrame::setClientModel(ClientModel *_clientModel)
this->clientModel = _clientModel;
}
-bool WalletFrame::addWallet(WalletModel *walletModel)
+void WalletFrame::addWallet(WalletModel *walletModel)
{
- if (!gui || !clientModel || !walletModel) {
- return false;
- }
+ if (!gui || !clientModel || !walletModel) return;
- if (mapWalletViews.count(walletModel) > 0) {
- return false;
- }
+ if (mapWalletViews.count(walletModel) > 0) return;
WalletView *walletView = new WalletView(platformStyle, this);
walletView->setBitcoinGUI(gui);
@@ -72,31 +68,25 @@ bool WalletFrame::addWallet(WalletModel *walletModel)
});
connect(walletView, &WalletView::outOfSyncWarningClicked, this, &WalletFrame::outOfSyncWarningClicked);
-
- return true;
}
-bool WalletFrame::setCurrentWallet(WalletModel* wallet_model)
+void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
- if (mapWalletViews.count(wallet_model) == 0)
- return false;
+ if (mapWalletViews.count(wallet_model) == 0) return;
WalletView *walletView = mapWalletViews.value(wallet_model);
walletStack->setCurrentWidget(walletView);
assert(walletView);
walletView->updateEncryptionStatus();
- return true;
}
-bool WalletFrame::removeWallet(WalletModel* wallet_model)
+void WalletFrame::removeWallet(WalletModel* wallet_model)
{
- if (mapWalletViews.count(wallet_model) == 0)
- return false;
+ if (mapWalletViews.count(wallet_model) == 0) return;
WalletView *walletView = mapWalletViews.take(wallet_model);
walletStack->removeWidget(walletView);
delete walletView;
- return true;
}
void WalletFrame::removeAllWallets()
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index 6a74fde9fd..156653f47d 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -36,9 +36,9 @@ public:
void setClientModel(ClientModel *clientModel);
- bool addWallet(WalletModel *walletModel);
- bool setCurrentWallet(WalletModel* wallet_model);
- bool removeWallet(WalletModel* wallet_model);
+ void addWallet(WalletModel *walletModel);
+ void setCurrentWallet(WalletModel* wallet_model);
+ void removeWallet(WalletModel* wallet_model);
void removeAllWallets();
bool handlePaymentRequest(const SendCoinsRecipient& recipient);
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index f4f3be8f43..c1eba61749 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -221,10 +221,8 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return TransactionCreationFailed;
}
- // reject absurdly high fee. (This can never happen because the
- // wallet caps the fee at maxTxFee. This merely serves as a
- // belt-and-suspenders check)
- if (nFeeRequired > m_node.getMaxTxFee())
+ // Reject absurdly high fee
+ if (nFeeRequired > m_wallet->getDefaultMaxTxFee())
return AbsurdFee;
}
@@ -482,7 +480,7 @@ WalletModel::UnlockContext::~UnlockContext()
}
}
-void WalletModel::UnlockContext::CopyFrom(const UnlockContext& rhs)
+void WalletModel::UnlockContext::CopyFrom(UnlockContext&& rhs)
{
// Transfer context; old object no longer relocks wallet
*this = rhs;
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index b123befbb4..54428aec08 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -194,15 +194,18 @@ public:
bool isValid() const { return valid; }
- // Copy operator and constructor transfer the context
- UnlockContext(const UnlockContext& obj) { CopyFrom(obj); }
- UnlockContext& operator=(const UnlockContext& rhs) { CopyFrom(rhs); return *this; }
+ // Copy constructor is disabled.
+ UnlockContext(const UnlockContext&) = delete;
+ // Move operator and constructor transfer the context
+ UnlockContext(UnlockContext&& obj) { CopyFrom(std::move(obj)); }
+ UnlockContext& operator=(UnlockContext&& rhs) { CopyFrom(std::move(rhs)); return *this; }
private:
WalletModel *wallet;
bool valid;
mutable bool relock; // mutable, as it can be set to false by copying
- void CopyFrom(const UnlockContext& rhs);
+ UnlockContext& operator=(const UnlockContext&) = default;
+ void CopyFrom(UnlockContext&& rhs);
};
UnlockContext requestUnlock();
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index eb3b0baf08..8c0dc276b0 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -8,7 +8,6 @@
#include <qt/walletmodeltransaction.h>
-#include <interfaces/node.h>
#include <policy/policy.h>
WalletModelTransaction::WalletModelTransaction(const QList<SendCoinsRecipient> &_recipients) :
@@ -29,7 +28,7 @@ std::unique_ptr<interfaces::PendingWalletTx>& WalletModelTransaction::getWtx()
unsigned int WalletModelTransaction::getTransactionSize()
{
- return wtx ? wtx->getVirtualSize() : 0;
+ return wtx ? GetVirtualTransactionSize(wtx->get()) : 0;
}
CAmount WalletModelTransaction::getTransactionFee() const
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 5f6f93d948..be47f67f95 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -316,6 +316,7 @@ void WalletView::showProgress(const QString &title, int nProgress)
if (progressDialog) {
progressDialog->close();
progressDialog->deleteLater();
+ progressDialog = nullptr;
}
} else if (progressDialog) {
if (progressDialog->wasCanceled()) {
diff --git a/src/qt/winshutdownmonitor.cpp b/src/qt/winshutdownmonitor.cpp
index 08cae76add..b177b22b3f 100644
--- a/src/qt/winshutdownmonitor.cpp
+++ b/src/qt/winshutdownmonitor.cpp
@@ -63,7 +63,7 @@ void WinShutdownMonitor::registerShutdownBlockReason(const QString& strReason, c
}
if (shutdownBRCreate(mainWinId, strReason.toStdWString().c_str()))
- qWarning() << "registerShutdownBlockReason: Successfully registered: " + strReason;
+ qInfo() << "registerShutdownBlockReason: Successfully registered: " + strReason;
else
qWarning() << "registerShutdownBlockReason: Failed to register: " + strReason;
}
diff --git a/src/random.cpp b/src/random.cpp
index 1aa78a9034..de26e6de1a 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -237,6 +237,34 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
#endif
}
+/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
+static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept
+{
+ CSHA512 inner_hasher;
+ inner_hasher.Write(seed, sizeof(seed));
+
+ // Hash loop
+ unsigned char buffer[64];
+ int64_t stop = GetTimeMicros() + microseconds;
+ do {
+ for (int i = 0; i < 1000; ++i) {
+ inner_hasher.Finalize(buffer);
+ inner_hasher.Reset();
+ inner_hasher.Write(buffer, sizeof(buffer));
+ }
+ // Benchmark operation and feed it into outer hasher.
+ int64_t perf = GetPerformanceCounter();
+ hasher.Write((const unsigned char*)&perf, sizeof(perf));
+ } while (GetTimeMicros() < stop);
+
+ // Produce output from inner state and feed it to outer hasher.
+ inner_hasher.Finalize(buffer);
+ hasher.Write(buffer, sizeof(buffer));
+ // Try to clean up.
+ inner_hasher.Reset();
+ memory_cleanse(buffer, sizeof(buffer));
+}
+
static void RandAddSeedPerfmon(CSHA512& hasher)
{
#ifdef WIN32
@@ -529,7 +557,23 @@ static void SeedSlow(CSHA512& hasher) noexcept
SeedTimestamp(hasher);
}
-static void SeedSleep(CSHA512& hasher)
+/** Extract entropy from rng, strengthen it, and feed it into hasher. */
+static void SeedStrengthen(CSHA512& hasher, RNGState& rng) noexcept
+{
+ static std::atomic<int64_t> last_strengthen{0};
+ int64_t last_time = last_strengthen.load();
+ int64_t current_time = GetTimeMicros();
+ if (current_time > last_time + 60000000) { // Only run once a minute
+ // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
+ unsigned char strengthen_seed[32];
+ rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false);
+ // Strengthen it for 10ms (100ms on first run), and feed it into hasher.
+ Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher);
+ last_strengthen = current_time;
+ }
+}
+
+static void SeedSleep(CSHA512& hasher, RNGState& rng)
{
// Everything that the 'fast' seeder includes
SeedFast(hasher);
@@ -545,9 +589,12 @@ static void SeedSleep(CSHA512& hasher)
// Windows performance monitor data (once every 10 minutes)
RandAddSeedPerfmon(hasher);
+
+ // Strengthen every minute
+ SeedStrengthen(hasher, rng);
}
-static void SeedStartup(CSHA512& hasher) noexcept
+static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
{
#ifdef WIN32
RAND_screen();
@@ -561,6 +608,9 @@ static void SeedStartup(CSHA512& hasher) noexcept
// Windows performance monitor data.
RandAddSeedPerfmon(hasher);
+
+ // Strengthen
+ SeedStrengthen(hasher, rng);
}
enum class RNGLevel {
@@ -585,7 +635,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
SeedSlow(hasher);
break;
case RNGLevel::SLEEP:
- SeedSleep(hasher);
+ SeedSleep(hasher, rng);
break;
}
@@ -593,7 +643,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
if (!rng.MixExtract(out, num, std::move(hasher), false)) {
// On the first invocation, also seed with SeedStartup().
CSHA512 startup_hasher;
- SeedStartup(startup_hasher);
+ SeedStartup(startup_hasher, rng);
rng.MixExtract(out, num, std::move(startup_hasher), true);
}
@@ -652,7 +702,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
if (requires_seed) RandomSeed();
std::vector<unsigned char> ret(len);
if (len > 0) {
- rng.Output(&ret[0], len);
+ rng.Keystream(&ret[0], len);
}
return ret;
}
diff --git a/src/random.h b/src/random.h
index 1c035f87ba..75d037738d 100644
--- a/src/random.h
+++ b/src/random.h
@@ -43,6 +43,7 @@
* - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally:
* - A high-precision timestamp before and after sleeping 1ms.
* - (On Windows) Once every 10 minutes, performance monitoring data from the OS.
+ - - Once every minute, strengthen the entropy for 10 ms using repeated SHA512.
* These just exploit the fact the system is idle to improve the quality of the RNG
* slightly.
*
@@ -51,6 +52,7 @@
* - 256 bits from the hardware RNG (rdseed or rdrand) when available.
* - (On Windows) Performance monitoring data from the OS.
* - (On Windows) Through OpenSSL, the screen contents.
+ * - Strengthen the entropy for 100 ms using repeated SHA512.
*
* When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
* (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
@@ -111,7 +113,7 @@ private:
if (requires_seed) {
RandomSeed();
}
- rng.Output(bytebuf, sizeof(bytebuf));
+ rng.Keystream(bytebuf, sizeof(bytebuf));
bytebuf_size = sizeof(bytebuf);
}
diff --git a/src/rest.cpp b/src/rest.cpp
index 326f7ae1d2..ab409947d3 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -141,13 +141,13 @@ static bool rest_headers(HTTPRequest* req,
headers.reserve(count);
{
LOCK(cs_main);
- tip = chainActive.Tip();
+ tip = ::ChainActive().Tip();
const CBlockIndex* pindex = LookupBlockIndex(hash);
- while (pindex != nullptr && chainActive.Contains(pindex)) {
+ while (pindex != nullptr && ::ChainActive().Contains(pindex)) {
headers.push_back(pindex);
if (headers.size() == (unsigned long)count)
break;
- pindex = chainActive.Next(pindex);
+ pindex = ::ChainActive().Next(pindex);
}
}
@@ -209,7 +209,7 @@ static bool rest_block(HTTPRequest* req,
CBlockIndex* tip = nullptr;
{
LOCK(cs_main);
- tip = chainActive.Tip();
+ tip = ::ChainActive().Tip();
pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
@@ -300,7 +300,7 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
switch (rf) {
case RetFormat::JSON: {
- UniValue mempoolInfoObject = mempoolInfoToJSON();
+ UniValue mempoolInfoObject = MempoolInfoToJSON(::mempool);
std::string strJSON = mempoolInfoObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -322,7 +322,7 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar
switch (rf) {
case RetFormat::JSON: {
- UniValue mempoolObject = mempoolToJSON(true);
+ UniValue mempoolObject = MempoolToJSON(::mempool, true);
std::string strJSON = mempoolObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
@@ -522,7 +522,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// serialize data
// use exact same output as mentioned in Bip64
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
- ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
+ ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
req->WriteHeader("Content-Type", "application/octet-stream");
@@ -532,7 +532,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
case RetFormat::HEX: {
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
- ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
+ ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
req->WriteHeader("Content-Type", "text/plain");
@@ -545,8 +545,8 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
// pack in some essentials
// use more or less the same output as mentioned in Bip64
- objGetUTXOResponse.pushKV("chainHeight", chainActive.Height());
- objGetUTXOResponse.pushKV("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex());
+ objGetUTXOResponse.pushKV("chainHeight", ::ChainActive().Height());
+ objGetUTXOResponse.pushKV("chaintipHash", ::ChainActive().Tip()->GetBlockHash().GetHex());
objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation);
UniValue utxos(UniValue::VARR);
@@ -590,10 +590,10 @@ static bool rest_blockhash_by_height(HTTPRequest* req,
CBlockIndex* pblockindex = nullptr;
{
LOCK(cs_main);
- if (blockheight > chainActive.Height()) {
+ if (blockheight > ::ChainActive().Height()) {
return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range");
}
- pblockindex = chainActive[blockheight];
+ pblockindex = ::ChainActive()[blockheight];
}
switch (rf) {
case RetFormat::BINARY: {
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 7e8e5e07d0..50c4589d9f 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -6,15 +6,14 @@
#include <rpc/blockchain.h>
#include <amount.h>
-#include <base58.h>
+#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
-#include <checkpoints.h>
#include <coins.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <hash.h>
-#include <index/txindex.h>
+#include <index/blockfilterindex.h>
#include <key_io.h>
#include <policy/feerate.h>
#include <policy/policy.h>
@@ -27,8 +26,10 @@
#include <sync.h>
#include <txdb.h>
#include <txmempool.h>
+#include <undo.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/validation.h>
#include <validation.h>
#include <validationinterface.h>
#include <versionbitsinfo.h>
@@ -91,6 +92,9 @@ static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* b
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
{
+ // Serialize passed information without accessing chain state of the active chain!
+ AssertLockNotHeld(cs_main); // For performance reasons
+
UniValue result(UniValue::VOBJ);
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
const CBlockIndex* pnext;
@@ -117,6 +121,9 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails)
{
+ // Serialize passed information without accessing chain state of the active chain!
+ AssertLockNotHeld(cs_main); // For performance reasons
+
UniValue result(UniValue::VOBJ);
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
const CBlockIndex* pnext;
@@ -174,7 +181,7 @@ static UniValue getblockcount(const JSONRPCRequest& request)
}.ToString());
LOCK(cs_main);
- return chainActive.Height();
+ return ::ChainActive().Height();
}
static UniValue getbestblockhash(const JSONRPCRequest& request)
@@ -194,7 +201,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
}.ToString());
LOCK(cs_main);
- return chainActive.Tip()->GetBlockHash().GetHex();
+ return ::ChainActive().Tip()->GetBlockHash().GetHex();
}
void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
@@ -373,12 +380,14 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
}.ToString());
LOCK(cs_main);
- return GetDifficulty(chainActive.Tip());
+ return GetDifficulty(::ChainActive().Tip());
}
static std::string EntryDescriptionString()
{
- return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
+ return " \"vsize\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n"
+ " \"size\" : n, (numeric) (DEPRECATED) same as vsize. Only returned if bitcoind is started with -deprecatedrpc=size\n"
+ " size will be completely removed in v0.20.\n"
" \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + " (DEPRECATED)\n"
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority (DEPRECATED)\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
@@ -405,9 +414,9 @@ static std::string EntryDescriptionString()
" \"bip125-replaceable\" : true|false, (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee)\n";
}
-static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCKS_REQUIRED(::mempool.cs)
+static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
{
- AssertLockHeld(mempool.cs);
+ AssertLockHeld(pool.cs);
UniValue fees(UniValue::VOBJ);
fees.pushKV("base", ValueFromAmount(e.GetFee()));
@@ -416,7 +425,8 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
info.pushKV("fees", fees);
- info.pushKV("size", (int)e.GetTxSize());
+ info.pushKV("vsize", (int)e.GetTxSize());
+ if (IsDeprecatedRPCEnabled("size")) info.pushKV("size", (int)e.GetTxSize());
info.pushKV("fee", ValueFromAmount(e.GetFee()));
info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
info.pushKV("time", e.GetTime());
@@ -427,12 +437,12 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
info.pushKV("ancestorcount", e.GetCountWithAncestors());
info.pushKV("ancestorsize", e.GetSizeWithAncestors());
info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
- info.pushKV("wtxid", mempool.vTxHashes[e.vTxHashesIdx].first.ToString());
+ info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
const CTransaction& tx = e.GetTx();
std::set<std::string> setDepends;
for (const CTxIn& txin : tx.vin)
{
- if (mempool.exists(txin.prevout.hash))
+ if (pool.exists(txin.prevout.hash))
setDepends.insert(txin.prevout.hash.ToString());
}
@@ -445,8 +455,8 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
info.pushKV("depends", depends);
UniValue spent(UniValue::VARR);
- const CTxMemPool::txiter &it = mempool.mapTx.find(tx.GetHash());
- const CTxMemPool::setEntries &setChildren = mempool.GetMemPoolChildren(it);
+ const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
+ const CTxMemPool::setEntries& setChildren = pool.GetMemPoolChildren(it);
for (CTxMemPool::txiter childiter : setChildren) {
spent.push_back(childiter->GetTx().GetHash().ToString());
}
@@ -455,7 +465,7 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
// Add opt-in RBF status
bool rbfStatus = false;
- RBFTransactionState rbfState = IsRBFOptIn(tx, mempool);
+ RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
if (rbfState == RBFTransactionState::UNKNOWN) {
throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
} else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
@@ -465,25 +475,24 @@ static void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) EXCLUSIVE_LOCK
info.pushKV("bip125-replaceable", rbfStatus);
}
-UniValue mempoolToJSON(bool fVerbose)
+UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose)
{
- if (fVerbose)
- {
- LOCK(mempool.cs);
+ if (verbose) {
+ LOCK(pool.cs);
UniValue o(UniValue::VOBJ);
- for (const CTxMemPoolEntry& e : mempool.mapTx)
- {
+ for (const CTxMemPoolEntry& e : pool.mapTx) {
const uint256& hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
- o.pushKV(hash.ToString(), info);
+ entryToJSON(pool, info, e);
+ // Mempool has unique entries so there is no advantage in using
+ // UniValue::pushKV, which checks if the key already exists in O(N).
+ // UniValue::__pushKV is used instead which currently is O(1).
+ o.__pushKV(hash.ToString(), info);
}
return o;
- }
- else
- {
+ } else {
std::vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
+ pool.queryHashes(vtxid);
UniValue a(UniValue::VARR);
for (const uint256& hash : vtxid)
@@ -525,7 +534,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request)
if (!request.params[0].isNull())
fVerbose = request.params[0].get_bool();
- return mempoolToJSON(fVerbose);
+ return MempoolToJSON(::mempool, fVerbose);
}
static UniValue getmempoolancestors(const JSONRPCRequest& request)
@@ -591,7 +600,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *ancestorIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(::mempool, info, e);
o.pushKV(_hash.ToString(), info);
}
return o;
@@ -661,7 +670,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *descendantIt;
const uint256& _hash = e.GetTx().GetHash();
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(::mempool, info, e);
o.pushKV(_hash.ToString(), info);
}
return o;
@@ -700,7 +709,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request)
const CTxMemPoolEntry &e = *it;
UniValue info(UniValue::VOBJ);
- entryToJSON(info, e);
+ entryToJSON(::mempool, info, e);
return info;
}
@@ -725,10 +734,10 @@ static UniValue getblockhash(const JSONRPCRequest& request)
LOCK(cs_main);
int nHeight = request.params[0].get_int();
- if (nHeight < 0 || nHeight > chainActive.Height())
+ if (nHeight < 0 || nHeight > ::ChainActive().Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
- CBlockIndex* pblockindex = chainActive[nHeight];
+ CBlockIndex* pblockindex = ::ChainActive()[nHeight];
return pblockindex->GetBlockHash().GetHex();
}
@@ -784,7 +793,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
{
LOCK(cs_main);
pblockindex = LookupBlockIndex(hash);
- tip = chainActive.Tip();
+ tip = ::ChainActive().Tip();
}
if (!pblockindex) {
@@ -821,11 +830,23 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
return block;
}
+static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex)
+{
+ CBlockUndo blockUndo;
+ if (IsBlockPruned(pblockindex)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
+ }
+
+ if (!UndoReadFromDisk(blockUndo, pblockindex)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
+ }
+
+ return blockUndo;
+}
+
static UniValue getblock(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
- RPCHelpMan{"getblock",
+ const RPCHelpMan help{"getblock",
"\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
"If verbosity is 1, returns an Object with information about block <hash>.\n"
"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
@@ -877,9 +898,11 @@ static UniValue getblock(const JSONRPCRequest& request)
HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
},
- }.ToString());
+ };
- LOCK(cs_main);
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
uint256 hash(ParseHashV(request.params[0], "blockhash"));
@@ -891,12 +914,20 @@ static UniValue getblock(const JSONRPCRequest& request)
verbosity = request.params[1].get_bool() ? 1 : 0;
}
- const CBlockIndex* pblockindex = LookupBlockIndex(hash);
- if (!pblockindex) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
- }
+ CBlock block;
+ const CBlockIndex* pblockindex;
+ const CBlockIndex* tip;
+ {
+ LOCK(cs_main);
+ pblockindex = LookupBlockIndex(hash);
+ tip = ::ChainActive().Tip();
+
+ if (!pblockindex) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
- const CBlock block = GetBlockChecked(pblockindex);
+ block = GetBlockChecked(pblockindex);
+ }
if (verbosity <= 0)
{
@@ -906,7 +937,7 @@ static UniValue getblock(const JSONRPCRequest& request)
return strHex;
}
- return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2);
+ return blockToJSON(block, tip, pblockindex, verbosity >= 2);
}
struct CCoinsStats
@@ -1011,7 +1042,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
// too low to be a block time (corresponds to timestamp from Sep 2001).
if (heightParam > 1000000000) {
// Add a 2 hour buffer to include blocks which might have had old timestamps
- CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW);
+ CBlockIndex* pindex = ::ChainActive().FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
}
@@ -1019,7 +1050,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
}
unsigned int height = (unsigned int) heightParam;
- unsigned int chainHeight = (unsigned int) chainActive.Height();
+ unsigned int chainHeight = (unsigned int) ::ChainActive().Height();
if (chainHeight < Params().PruneAfterHeight())
throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
else if (height > chainHeight)
@@ -1030,7 +1061,12 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
}
PruneBlockFilesManual(height);
- return uint64_t(height);
+ const CBlockIndex* block = ::ChainActive().Tip();
+ assert(block);
+ while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
+ block = block->pprev;
+ }
+ return uint64_t(block->nHeight);
}
static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
@@ -1062,7 +1098,7 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
CCoinsStats stats;
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
if (GetUTXOStats(pcoinsdbview.get(), stats)) {
ret.pushKV("height", (int64_t)stats.nHeight);
ret.pushKV("bestblock", stats.hashBlock.GetHex());
@@ -1318,16 +1354,16 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
LOCK(cs_main);
- const CBlockIndex* tip = chainActive.Tip();
+ const CBlockIndex* tip = ::ChainActive().Tip();
UniValue obj(UniValue::VOBJ);
obj.pushKV("chain", Params().NetworkIDString());
- obj.pushKV("blocks", (int)chainActive.Height());
+ obj.pushKV("blocks", (int)::ChainActive().Height());
obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
obj.pushKV("difficulty", (double)GetDifficulty(tip));
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
- obj.pushKV("initialblockdownload", IsInitialBlockDownload());
+ obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload());
obj.pushKV("chainwork", tip->nChainWork.GetHex());
obj.pushKV("size_on_disk", CalculateCurrentUsage());
obj.pushKV("pruned", fPruneMode);
@@ -1418,11 +1454,11 @@ static UniValue getchaintips(const JSONRPCRequest& request)
LOCK(cs_main);
/*
- * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them.
+ * Idea: the set of chain tips is ::ChainActive().tip, plus orphan blocks which do not have another orphan building off of them.
* Algorithm:
* - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
* - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
- * - add chainActive.Tip()
+ * - add ::ChainActive().Tip()
*/
std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
std::set<const CBlockIndex*> setOrphans;
@@ -1430,7 +1466,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
{
- if (!chainActive.Contains(item.second)) {
+ if (!::ChainActive().Contains(item.second)) {
setOrphans.insert(item.second);
setPrevs.insert(item.second->pprev);
}
@@ -1444,7 +1480,7 @@ static UniValue getchaintips(const JSONRPCRequest& request)
}
// Always report the currently active tip.
- setTips.insert(chainActive.Tip());
+ setTips.insert(::ChainActive().Tip());
/* Construct the output array. */
UniValue res(UniValue::VARR);
@@ -1454,11 +1490,11 @@ static UniValue getchaintips(const JSONRPCRequest& request)
obj.pushKV("height", block->nHeight);
obj.pushKV("hash", block->phashBlock->GetHex());
- const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
+ const int branchLen = block->nHeight - ::ChainActive().FindFork(block)->nHeight;
obj.pushKV("branchlen", branchLen);
std::string status;
- if (chainActive.Contains(block)) {
+ if (::ChainActive().Contains(block)) {
// This block is part of the currently active chain.
status = "active";
} else if (block->nStatus & BLOCK_FAILED_MASK) {
@@ -1485,15 +1521,18 @@ static UniValue getchaintips(const JSONRPCRequest& request)
return res;
}
-UniValue mempoolInfoToJSON()
+UniValue MempoolInfoToJSON(const CTxMemPool& pool)
{
+ // Make sure this call is atomic in the pool.
+ LOCK(pool.cs);
UniValue ret(UniValue::VOBJ);
- ret.pushKV("size", (int64_t) mempool.size());
- ret.pushKV("bytes", (int64_t) mempool.GetTotalTxSize());
- ret.pushKV("usage", (int64_t) mempool.DynamicMemoryUsage());
+ ret.pushKV("loaded", pool.IsLoaded());
+ ret.pushKV("size", (int64_t)pool.size());
+ ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
+ ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
size_t maxmempool = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
ret.pushKV("maxmempool", (int64_t) maxmempool);
- ret.pushKV("mempoolminfee", ValueFromAmount(std::max(mempool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
+ ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
return ret;
@@ -1508,6 +1547,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
+ " \"loaded\": true|false (boolean) True if the mempool is fully loaded\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
" \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
@@ -1522,7 +1562,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
},
}.ToString());
- return mempoolInfoToJSON();
+ return MempoolInfoToJSON(::mempool);
}
static UniValue preciousblock(const JSONRPCRequest& request)
@@ -1583,15 +1623,15 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
uint256 hash(ParseHashV(request.params[0], "blockhash"));
CValidationState state;
+ CBlockIndex* pblockindex;
{
LOCK(cs_main);
- CBlockIndex* pblockindex = LookupBlockIndex(hash);
+ pblockindex = LookupBlockIndex(hash);
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
-
- InvalidateBlock(state, Params(), pblockindex);
}
+ InvalidateBlock(state, Params(), pblockindex);
if (state.IsValid()) {
ActivateBestChain(state, Params());
@@ -1675,7 +1715,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
if (request.params[1].isNull()) {
LOCK(cs_main);
- pindex = chainActive.Tip();
+ pindex = ::ChainActive().Tip();
} else {
uint256 hash(ParseHashV(request.params[1], "blockhash"));
LOCK(cs_main);
@@ -1683,7 +1723,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- if (!chainActive.Contains(pindex)) {
+ if (!::ChainActive().Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
}
}
@@ -1780,8 +1820,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
{
const RPCHelpMan help{"getblockstats",
"\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
- "It won't work for some heights with pruning.\n"
- "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n",
+ "It won't work for some heights with pruning.\n",
{
{"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block", "", {"", "string or numeric"}},
{"stats", RPCArg::Type::ARR, /* default */ "all values", "Values to plot (see result below)",
@@ -1844,7 +1883,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
CBlockIndex* pindex;
if (request.params[0].isNum()) {
const int height = request.params[0].get_int();
- const int current_tip = chainActive.Height();
+ const int current_tip = ::ChainActive().Height();
if (height < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
}
@@ -1852,14 +1891,14 @@ static UniValue getblockstats(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
}
- pindex = chainActive[height];
+ pindex = ::ChainActive()[height];
} else {
const uint256 hash(ParseHashV(request.params[0], "hash_or_height"));
pindex = LookupBlockIndex(hash);
if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- if (!chainActive.Contains(pindex)) {
+ if (!::ChainActive().Contains(pindex)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Block is not in chain %s", Params().NetworkIDString()));
}
}
@@ -1876,6 +1915,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
}
const CBlock block = GetBlockChecked(pindex);
+ const CBlockUndo blockUndo = GetUndoChecked(pindex);
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
@@ -1889,10 +1929,6 @@ static UniValue getblockstats(const JSONRPCRequest& request)
const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
- if (loop_inputs && !g_txindex) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled");
- }
-
CAmount maxfee = 0;
CAmount maxfeerate = 0;
CAmount minfee = MAX_MONEY;
@@ -1913,7 +1949,8 @@ static UniValue getblockstats(const JSONRPCRequest& request)
std::vector<std::pair<CAmount, int64_t>> feerate_array;
std::vector<int64_t> txsize_array;
- for (const auto& tx : block.vtx) {
+ for (size_t i = 0; i < block.vtx.size(); ++i) {
+ const auto& tx = block.vtx.at(i);
outputs += tx->vout.size();
CAmount tx_total_out = 0;
@@ -1957,14 +1994,9 @@ static UniValue getblockstats(const JSONRPCRequest& request)
if (loop_inputs) {
CAmount tx_total_in = 0;
- for (const CTxIn& in : tx->vin) {
- CTransactionRef tx_in;
- uint256 hashBlock;
- if (!GetTransaction(in.prevout.hash, tx_in, Params().GetConsensus(), hashBlock)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, std::string("Unexpected internal error (tx index seems corrupt)"));
- }
-
- CTxOut prevoutput = tx_in->vout[in.prevout.n];
+ const auto& txundo = blockUndo.vtxundo.at(i - 1);
+ for (const Coin& coin: txundo.vprevout) {
+ const CTxOut& prevoutput = coin.out;
tx_total_in += prevoutput.nValue;
utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD;
@@ -2058,11 +2090,11 @@ static UniValue savemempool(const JSONRPCRequest& request)
}.ToString());
}
- if (!g_is_mempool_loaded) {
+ if (!::mempool.IsLoaded()) {
throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
}
- if (!DumpMempool()) {
+ if (!DumpMempool(::mempool)) {
throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
}
@@ -2225,8 +2257,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
desc_str = desc_uni.get_str();
UniValue range_uni = find_value(scanobject, "range");
if (!range_uni.isNull()) {
- range = ParseRange(range_uni);
- if (range.first < 0 || (range.second >> 31) != 0 || range.second >= range.first + 1000000) throw JSONRPCError(RPC_INVALID_PARAMETER, "range out of range");
+ range = ParseDescriptorRange(range_uni);
}
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan object needs to be either a string or an object");
@@ -2264,7 +2295,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
std::unique_ptr<CCoinsViewCursor> pcursor;
{
LOCK(cs_main);
- FlushStateToDisk();
+ ::ChainstateActive().ForceFlushStateToDisk();
pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
assert(pcursor);
}
@@ -2297,6 +2328,85 @@ UniValue scantxoutset(const JSONRPCRequest& request)
return result;
}
+static UniValue getblockfilter(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw std::runtime_error(
+ RPCHelpMan{"getblockfilter",
+ "\nRetrieve a BIP 157 content filter for a particular block.\n",
+ {
+ {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
+ {"filtertype", RPCArg::Type::STR, /*default*/ "basic", "The type name of the filter"},
+ },
+ RPCResult{
+ "{\n"
+ " \"filter\" : (string) the hex-encoded filter data\n"
+ " \"header\" : (string) the hex-encoded filter header\n"
+ "}\n"
+ },
+ RPCExamples{
+ HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"")
+ }
+ }.ToString()
+ );
+ }
+
+ uint256 block_hash = ParseHashV(request.params[0], "blockhash");
+ std::string filtertype_name = "basic";
+ if (!request.params[1].isNull()) {
+ filtertype_name = request.params[1].get_str();
+ }
+
+ BlockFilterType filtertype;
+ if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
+ }
+
+ BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
+ if (!index) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
+ }
+
+ const CBlockIndex* block_index;
+ bool block_was_connected;
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(block_hash);
+ if (!block_index) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+ }
+ block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
+ }
+
+ bool index_ready = index->BlockUntilSyncedToCurrentChain();
+
+ BlockFilter filter;
+ uint256 filter_header;
+ if (!index->LookupFilter(block_index, filter) ||
+ !index->LookupFilterHeader(block_index, filter_header)) {
+ int err_code;
+ std::string errmsg = "Filter not found.";
+
+ if (!block_was_connected) {
+ err_code = RPC_INVALID_ADDRESS_OR_KEY;
+ errmsg += " Block was not connected to active chain.";
+ } else if (!index_ready) {
+ err_code = RPC_MISC_ERROR;
+ errmsg += " Block filters are still in the process of being indexed.";
+ } else {
+ err_code = RPC_INTERNAL_ERROR;
+ errmsg += " This error is unexpected and indicates index corruption.";
+ }
+
+ throw JSONRPCError(err_code, errmsg);
+ }
+
+ UniValue ret(UniValue::VOBJ);
+ ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
+ ret.pushKV("header", filter_header.GetHex());
+ return ret;
+}
+
// clang-format off
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
@@ -2324,6 +2434,7 @@ static const CRPCCommand commands[] =
{ "blockchain", "preciousblock", &preciousblock, {"blockhash"} },
{ "blockchain", "scantxoutset", &scantxoutset, {"action", "scanobjects"} },
+ { "blockchain", "getblockfilter", &getblockfilter, {"blockhash", "filtertype"} },
/* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, {"blockhash"} },
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 529132d033..ff461fbcbc 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -5,12 +5,17 @@
#ifndef BITCOIN_RPC_BLOCKCHAIN_H
#define BITCOIN_RPC_BLOCKCHAIN_H
-#include <vector>
-#include <stdint.h>
#include <amount.h>
+#include <sync.h>
+
+#include <stdint.h>
+#include <vector>
+
+extern RecursiveMutex cs_main;
class CBlock;
class CBlockIndex;
+class CTxMemPool;
class UniValue;
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
@@ -27,16 +32,16 @@ double GetDifficulty(const CBlockIndex* blockindex);
void RPCNotifyBlockChange(bool ibd, const CBlockIndex *);
/** Block description to JSON */
-UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false);
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false) LOCKS_EXCLUDED(cs_main);
/** Mempool information to JSON */
-UniValue mempoolInfoToJSON();
+UniValue MempoolInfoToJSON(const CTxMemPool& pool);
/** Mempool to JSON */
-UniValue mempoolToJSON(bool fVerbose = false);
+UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false);
/** Block header to JSON */
-UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex);
+UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main);
/** Used by getblockstats to get feerates at different percentiles by weight */
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index a266580b3d..8f6bdc21aa 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -36,6 +36,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendtoaddress", 4, "subtractfeefromamount" },
{ "sendtoaddress", 5 , "replaceable" },
{ "sendtoaddress", 6 , "conf_target" },
+ { "sendtoaddress", 8, "avoid_reuse" },
{ "settxfee", 0, "amount" },
{ "sethdseed", 0, "newkeypool" },
{ "getreceivedbyaddress", 1, "minconf" },
@@ -48,6 +49,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listreceivedbylabel", 2, "include_watchonly" },
{ "getbalance", 1, "minconf" },
{ "getbalance", 2, "include_watchonly" },
+ { "getbalance", 3, "avoid_reuse" },
{ "getblockhash", 0, "height" },
{ "waitforblockheight", 0, "height" },
{ "waitforblockheight", 1, "timeout" },
@@ -92,8 +94,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransactionwithkey", 2, "prevtxs" },
{ "signrawtransactionwithwallet", 1, "prevtxs" },
{ "sendrawtransaction", 1, "allowhighfees" },
+ { "sendrawtransaction", 1, "maxfeerate" },
{ "testmempoolaccept", 0, "rawtxs" },
{ "testmempoolaccept", 1, "allowhighfees" },
+ { "testmempoolaccept", 1, "maxfeerate" },
{ "combinerawtransaction", 0, "txs" },
{ "fundrawtransaction", 1, "options" },
{ "fundrawtransaction", 2, "iswitness" },
@@ -139,6 +143,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "setban", 2, "bantime" },
{ "setban", 3, "absolute" },
{ "setnetworkactive", 0, "state" },
+ { "setwalletflag", 1, "value" },
{ "getmempoolancestors", 1, "verbose" },
{ "getmempooldescendants", 1, "verbose" },
{ "bumpfee", 1, "options" },
@@ -160,6 +165,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "rescanblockchain", 1, "stop_height"},
{ "createwallet", 1, "disable_private_keys"},
{ "createwallet", 2, "blank"},
+ { "createwallet", 4, "avoid_reuse"},
{ "getnodeaddresses", 0, "count"},
{ "stop", 0, "wait" },
};
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index f2acb8fbf5..477f05f46c 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -16,13 +16,16 @@
#include <policy/fees.h>
#include <pow.h>
#include <rpc/blockchain.h>
-#include <rpc/mining.h>
#include <rpc/server.h>
#include <rpc/util.h>
+#include <script/script.h>
#include <shutdown.h>
#include <txmempool.h>
+#include <univalue.h>
+#include <util/fees.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/validation.h>
#include <validation.h>
#include <validationinterface.h>
#include <versionbitsinfo.h>
@@ -37,10 +40,10 @@
* If 'height' is nonnegative, compute the estimate at the time when a given block was found.
*/
static UniValue GetNetworkHashPS(int lookup, int height) {
- CBlockIndex *pb = chainActive.Tip();
+ CBlockIndex *pb = ::ChainActive().Tip();
- if (height >= 0 && height < chainActive.Height())
- pb = chainActive[height];
+ if (height >= 0 && height < ::ChainActive().Height())
+ pb = ::ChainActive()[height];
if (pb == nullptr || !pb->nHeight)
return 0;
@@ -98,7 +101,7 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1);
}
-UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
+static UniValue generateBlocks(const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
{
static const int nInnerLoopCount = 0x10000;
int nHeightEnd = 0;
@@ -106,20 +109,20 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen
{ // Don't keep cs_main locked
LOCK(cs_main);
- nHeight = chainActive.Height();
+ nHeight = ::ChainActive().Height();
nHeightEnd = nHeight+nGenerate;
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd && !ShutdownRequested())
{
- std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript));
+ std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbase_script));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
- IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
+ IncrementExtraNonce(pblock, ::ChainActive().Tip(), nExtraNonce);
}
while (nMaxTries > 0 && pblock->nNonce < nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
++pblock->nNonce;
@@ -136,12 +139,6 @@ UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGen
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
-
- //mark script as important because it was used at least for one coinbase output if the script came from the wallet
- if (keepScript)
- {
- coinbaseScript->KeepScript();
- }
}
return blockHashes;
}
@@ -179,10 +176,9 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
}
- std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
- coinbaseScript->reserveScript = GetScriptForDestination(destination);
+ CScript coinbase_script = GetScriptForDestination(destination);
- return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
+ return generateBlocks(coinbase_script, nGenerate, nMaxTries);
}
static UniValue getmininginfo(const JSONRPCRequest& request)
@@ -214,10 +210,10 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
- obj.pushKV("blocks", (int)chainActive.Height());
+ obj.pushKV("blocks", (int)::ChainActive().Height());
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
- obj.pushKV("difficulty", (double)GetDifficulty(chainActive.Tip()));
+ obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
obj.pushKV("networkhashps", getnetworkhashps(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", Params().NetworkIDString());
@@ -413,7 +409,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
return "duplicate-inconclusive";
}
- CBlockIndex* const pindexPrev = chainActive.Tip();
+ CBlockIndex* const pindexPrev = ::ChainActive().Tip();
// TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
return "inconclusive-not-best-prevblk";
@@ -444,10 +440,10 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
- throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!");
+ throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
- if (IsInitialBlockDownload())
- throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading 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;
@@ -469,7 +465,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
else
{
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
- hashWatchedChain = chainActive.Tip()->GetBlockHash();
+ hashWatchedChain = ::ChainActive().Tip()->GetBlockHash();
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
@@ -507,7 +503,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
static CBlockIndex* pindexPrev;
static int64_t nStart;
static std::unique_ptr<CBlockTemplate> pblocktemplate;
- if (pindexPrev != chainActive.Tip() ||
+ if (pindexPrev != ::ChainActive().Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
@@ -515,7 +511,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
- CBlockIndex* pindexPrevNew = chainActive.Tip();
+ CBlockIndex* pindexPrevNew = ::ChainActive().Tip();
nStart = GetTime();
// Create new block
@@ -650,7 +646,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
result.pushKV("transactions", transactions);
result.pushKV("coinbaseaux", aux);
result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue);
- result.pushKV("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast));
+ result.pushKV("longpollid", ::ChainActive().Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast));
result.pushKV("target", hashTarget.GetHex());
result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
result.pushKV("mutable", aMutable);
diff --git a/src/rpc/mining.h b/src/rpc/mining.h
deleted file mode 100644
index be9a973315..0000000000
--- a/src/rpc/mining.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2017 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_RPC_MINING_H
-#define BITCOIN_RPC_MINING_H
-
-#include <script/script.h>
-
-#include <univalue.h>
-
-/** Generate blocks (mine) */
-UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript);
-
-#endif
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index 822a0beef9..7a1bdec7b9 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -3,26 +3,20 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <chain.h>
-#include <clientversion.h>
-#include <core_io.h>
#include <crypto/ripemd160.h>
#include <key_io.h>
-#include <validation.h>
#include <httpserver.h>
-#include <net.h>
-#include <netbase.h>
#include <outputtype.h>
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
-#include <timedata.h>
#include <util/system.h>
#include <util/strencodings.h>
-#include <warnings.h>
+#include <util/validation.h>
#include <stdint.h>
+#include <tuple>
#ifdef HAVE_MALLOC_INFO
#include <malloc.h>
#endif
@@ -34,11 +28,7 @@ static UniValue validateaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"validateaddress",
- "\nReturn information about the given bitcoin address.\n"
- "DEPRECATION WARNING: Parts of this command have been deprecated and moved to getaddressinfo. Clients must\n"
- "transition to using getaddressinfo to access this information before upgrading to v0.18. The following deprecated\n"
- "fields have moved to getaddressinfo and will only be shown here with -deprecatedrpc=validateaddress: ismine, iswatchonly,\n"
- "script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n",
+ "\nReturn information about the given bitcoin address.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},
},
@@ -132,9 +122,9 @@ static UniValue createmultisig(const JSONRPCRequest& request)
}
// Construct using pay-to-script-hash:
- const CScript inner = CreateMultisigRedeemscript(required, pubkeys);
CBasicKeyStore keystore;
- const CTxDestination dest = AddAndGetDestinationForScript(keystore, inner, output_type);
+ CScript inner;
+ const CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, keystore, inner);
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(dest));
@@ -206,7 +196,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
},
RPCExamples{
"First three native segwit receive addresses\n" +
- HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" \"[0,2]\"")
+ HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"")
}}.ToString()
);
}
@@ -218,22 +208,11 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
int64_t range_end = 0;
if (request.params.size() >= 2 && !request.params[1].isNull()) {
- auto range = ParseRange(request.params[1]);
- if (range.first < 0) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
- }
- if ((range.second >> 31) != 0) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high");
- }
- if (range.second >= range.first + 1000000) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large");
- }
- range_begin = range.first;
- range_end = range.second;
+ std::tie(range_begin, range_end) = ParseDescriptorRange(request.params[1]);
}
- FlatSigningProvider provider;
- auto desc = Parse(desc_str, provider, /* require_checksum = */ true);
+ FlatSigningProvider key_provider;
+ auto desc = Parse(desc_str, key_provider, /* require_checksum = */ true);
if (!desc) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor"));
}
@@ -249,8 +228,9 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
UniValue addresses(UniValue::VARR);
for (int i = range_begin; i <= range_end; ++i) {
+ FlatSigningProvider provider;
std::vector<CScript> scripts;
- if (!desc->Expand(i, provider, scripts, provider)) {
+ if (!desc->Expand(i, key_provider, scripts, provider)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Cannot derive script without private keys"));
}
@@ -309,8 +289,8 @@ static UniValue verifymessage(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
- const CKeyID *keyID = boost::get<CKeyID>(&destination);
- if (!keyID) {
+ const PKHash *pkhash = boost::get<PKHash>(&destination);
+ if (!pkhash) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
@@ -328,7 +308,7 @@ static UniValue verifymessage(const JSONRPCRequest& request)
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
- return (pubkey.GetID() == *keyID);
+ return (pubkey.GetID() == *pkhash);
}
static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index c7b3478f44..d993a88458 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -5,18 +5,17 @@
#include <rpc/server.h>
#include <banman.h>
-#include <chainparams.h>
#include <clientversion.h>
#include <core_io.h>
#include <net.h>
#include <net_processing.h>
#include <netbase.h>
#include <policy/policy.h>
+#include <policy/settings.h>
#include <rpc/protocol.h>
#include <rpc/util.h>
#include <sync.h>
#include <timedata.h>
-#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <validation.h>
@@ -495,7 +494,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
obj.pushKV("protocolversion",PROTOCOL_VERSION);
if(g_connman)
obj.pushKV("localservices", strprintf("%016x", g_connman->GetLocalServices()));
- obj.pushKV("localrelay", fRelayTxes);
+ obj.pushKV("localrelay", g_relay_txes);
obj.pushKV("timeoffset", GetTimeOffset());
if (g_connman) {
obj.pushKV("networkactive", g_connman->GetNetworkActive());
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index 23999b305a..33b0130a94 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -10,7 +10,6 @@
#include <util/system.h>
#include <util/strencodings.h>
#include <util/time.h>
-#include <version.h>
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index d19afaa8a1..9da24afe79 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -6,20 +6,19 @@
#include <chain.h>
#include <coins.h>
#include <compat/byteswap.h>
-#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <index/txindex.h>
-#include <init.h>
#include <key_io.h>
#include <keystore.h>
#include <merkleblock.h>
+#include <node/coin.h>
+#include <node/psbt.h>
#include <node/transaction.h>
-#include <policy/policy.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <psbt.h>
-#include <rpc/rawtransaction.h>
+#include <rpc/rawtransaction_util.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/script.h>
@@ -27,7 +26,7 @@
#include <script/sign.h>
#include <script/standard.h>
#include <uint256.h>
-#include <util/bip32.h>
+#include <util/moneystr.h>
#include <util/strencodings.h>
#include <validation.h>
#include <validationinterface.h>
@@ -38,6 +37,11 @@
#include <univalue.h>
+/** High fee for sendrawtransaction and testmempoolaccept.
+ * By default, transaction with a fee higher than this will be rejected by the
+ * RPCs. This can be overridden with the maxfeerate argument.
+ */
+constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE{COIN / 10};
static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
@@ -54,8 +58,8 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
entry.pushKV("blockhash", hashBlock.GetHex());
CBlockIndex* pindex = LookupBlockIndex(hashBlock);
if (pindex) {
- if (chainActive.Contains(pindex)) {
- entry.pushKV("confirmations", 1 + chainActive.Height() - pindex->nHeight);
+ if (::ChainActive().Contains(pindex)) {
+ entry.pushKV("confirmations", 1 + ::ChainActive().Height() - pindex->nHeight);
entry.pushKV("time", pindex->GetBlockTime());
entry.pushKV("blocktime", pindex->GetBlockTime());
}
@@ -174,7 +178,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
if (!blockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
}
- in_active_chain = chainActive.Contains(blockindex);
+ in_active_chain = ::ChainActive().Contains(blockindex);
}
bool f_txindex_ready = false;
@@ -192,7 +196,7 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
}
errmsg = "No such transaction found in the provided block";
} else if (!g_txindex) {
- errmsg = "No such mempool transaction. Use -txindex to enable blockchain transaction queries";
+ errmsg = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries";
} else if (!f_txindex_ready) {
errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed";
} else {
@@ -264,7 +268,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
for (const auto& tx : setTxids) {
const Coin& coin = AccessByTxid(*pcoinsTip, tx);
if (!coin.IsSpent()) {
- pblockindex = chainActive[coin.nHeight];
+ pblockindex = ::ChainActive()[coin.nHeight];
break;
}
}
@@ -338,7 +342,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
LOCK(cs_main);
const CBlockIndex* pindex = LookupBlockIndex(merkleBlock.header.GetHash());
- if (!pindex || !chainActive.Contains(pindex) || pindex->nTx == 0) {
+ if (!pindex || !::ChainActive().Contains(pindex) || pindex->nTx == 0) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
}
@@ -352,119 +356,6 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
return res;
}
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf)
-{
- if (inputs_in.isNull() || outputs_in.isNull())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
-
- UniValue inputs = inputs_in.get_array();
- const bool outputs_is_obj = outputs_in.isObject();
- UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
-
- CMutableTransaction rawTx;
-
- if (!locktime.isNull()) {
- int64_t nLockTime = locktime.get_int64();
- if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
- rawTx.nLockTime = nLockTime;
- }
-
- bool rbfOptIn = rbf.isTrue();
-
- for (unsigned int idx = 0; idx < inputs.size(); idx++) {
- const UniValue& input = inputs[idx];
- const UniValue& o = input.get_obj();
-
- uint256 txid = ParseHashO(o, "txid");
-
- const UniValue& vout_v = find_value(o, "vout");
- if (!vout_v.isNum())
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
- int nOutput = vout_v.get_int();
- if (nOutput < 0)
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
-
- uint32_t nSequence;
- if (rbfOptIn) {
- nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
- } else if (rawTx.nLockTime) {
- nSequence = CTxIn::SEQUENCE_FINAL - 1;
- } else {
- nSequence = CTxIn::SEQUENCE_FINAL;
- }
-
- // set the sequence number if passed in the parameters object
- const UniValue& sequenceObj = find_value(o, "sequence");
- if (sequenceObj.isNum()) {
- int64_t seqNr64 = sequenceObj.get_int64();
- if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
- } else {
- nSequence = (uint32_t)seqNr64;
- }
- }
-
- CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
-
- rawTx.vin.push_back(in);
- }
-
- if (!outputs_is_obj) {
- // Translate array of key-value pairs into dict
- UniValue outputs_dict = UniValue(UniValue::VOBJ);
- for (size_t i = 0; i < outputs.size(); ++i) {
- const UniValue& output = outputs[i];
- if (!output.isObject()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
- }
- if (output.size() != 1) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
- }
- outputs_dict.pushKVs(output);
- }
- outputs = std::move(outputs_dict);
- }
-
- // Duplicate checking
- std::set<CTxDestination> destinations;
- bool has_data{false};
-
- for (const std::string& name_ : outputs.getKeys()) {
- if (name_ == "data") {
- if (has_data) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, duplicate key: data");
- }
- has_data = true;
- std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
-
- CTxOut out(0, CScript() << OP_RETURN << data);
- rawTx.vout.push_back(out);
- } else {
- CTxDestination destination = DecodeDestination(name_);
- if (!IsValidDestination(destination)) {
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
- }
-
- if (!destinations.insert(destination).second) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
- }
-
- CScript scriptPubKey = GetScriptForDestination(destination);
- CAmount nAmount = AmountFromValue(outputs[name_]);
-
- CTxOut out(nAmount, scriptPubKey);
- rawTx.vout.push_back(out);
- }
- }
-
- if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(CTransaction(rawTx))) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
- }
-
- return rawTx;
-}
-
static UniValue createrawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
@@ -535,14 +426,17 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
static UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
- RPCHelpMan{"decoderawtransaction",
+ const RPCHelpMan help{"decoderawtransaction",
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction\n"
- " If iswitness is not present, heuristic tests will be used in decoding"},
+ {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ "If iswitness is not present, heuristic tests will be used in decoding.\n"
+ "If true, only witness deserialization will be tried.\n"
+ "If false, only non-witness deserialization will be tried.\n"
+ "This boolean should reflect whether the transaction has inputs\n"
+ "(e.g. fully valid, or on-chain transactions), if known by the caller."
+ },
},
RPCResult{
"{\n"
@@ -589,7 +483,11 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
HelpExampleCli("decoderawtransaction", "\"hexstring\"")
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
@@ -608,33 +506,54 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
return result;
}
+static std::string GetAllOutputTypes()
+{
+ std::string ret;
+ for (int i = TX_NONSTANDARD; i <= TX_WITNESS_UNKNOWN; ++i) {
+ if (i != TX_NONSTANDARD) ret += ", ";
+ ret += GetTxnOutputType(static_cast<txnouttype>(i));
+ }
+ return ret;
+}
+
static UniValue decodescript(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() != 1)
- throw std::runtime_error(
- RPCHelpMan{"decodescript",
+ const RPCHelpMan help{"decodescript",
"\nDecode a hex-encoded script.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
},
RPCResult{
"{\n"
- " \"asm\":\"asm\", (string) Script public key\n"
- " \"hex\":\"hex\", (string) hex-encoded public key\n"
- " \"type\":\"type\", (string) The output type\n"
- " \"reqSigs\": n, (numeric) The required signatures\n"
- " \"addresses\": [ (json array of string)\n"
- " \"address\" (string) bitcoin address\n"
+ " \"asm\":\"asm\", (string) Script public key\n"
+ " \"type\":\"type\", (string) The output type (e.g. "+GetAllOutputTypes()+")\n"
+ " \"reqSigs\": n, (numeric) The required signatures\n"
+ " \"addresses\": [ (json array of string)\n"
+ " \"address\" (string) bitcoin address\n"
" ,...\n"
" ],\n"
- " \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n"
+ " \"p2sh\":\"str\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n"
+ " \"segwit\": { (json object) Result of a witness script public key wrapping this redeem script (not returned if the script is a P2SH or witness).\n"
+ " \"asm\":\"str\", (string) String representation of the script public key\n"
+ " \"hex\":\"hexstr\", (string) Hex string of the script public key\n"
+ " \"type\":\"str\", (string) The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash)\n"
+ " \"reqSigs\": n, (numeric) The required signatures (always 1)\n"
+ " \"addresses\": [ (json array of string) (always length 1)\n"
+ " \"address\" (string) segwit address\n"
+ " ,...\n"
+ " ],\n"
+ " \"p2sh-segwit\":\"str\" (string) address of the P2SH script wrapping this witness redeem script.\n"
"}\n"
},
RPCExamples{
HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR});
@@ -646,7 +565,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
} else {
// Empty scripts are valid
}
- ScriptPubKeyToUniv(script, r, false);
+ ScriptPubKeyToUniv(script, r, /* fIncludeHex */ false);
UniValue type;
type = find_value(r, "type");
@@ -654,7 +573,7 @@ static UniValue decodescript(const JSONRPCRequest& request)
if (type.isStr() && type.get_str() != "scripthash") {
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
// don't return the address for a P2SH of the P2SH.
- r.pushKV("p2sh", EncodeDestination(CScriptID(script)));
+ r.pushKV("p2sh", EncodeDestination(ScriptHash(script)));
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// is a witness program, don't return addresses for a segwit programs.
if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
@@ -680,8 +599,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
// Newer segwit program versions should be considered when then become available.
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script));
}
- ScriptPubKeyToUniv(segwitScr, sr, true);
- sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr)));
+ ScriptPubKeyToUniv(segwitScr, sr, /* fIncludeHex */ true);
+ sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(segwitScr)));
r.pushKV("segwit", sr);
}
}
@@ -689,23 +608,6 @@ static UniValue decodescript(const JSONRPCRequest& request)
return r;
}
-/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
-static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
-{
- UniValue entry(UniValue::VOBJ);
- entry.pushKV("txid", txin.prevout.hash.ToString());
- entry.pushKV("vout", (uint64_t)txin.prevout.n);
- UniValue witness(UniValue::VARR);
- for (unsigned int i = 0; i < txin.scriptWitness.stack.size(); i++) {
- witness.push_back(HexStr(txin.scriptWitness.stack[i].begin(), txin.scriptWitness.stack[i].end()));
- }
- entry.pushKV("witness", witness);
- entry.pushKV("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
- entry.pushKV("sequence", (uint64_t)txin.nSequence);
- entry.pushKV("error", strMessage);
- vErrorsRet.push_back(entry);
-}
-
static UniValue combinerawtransaction(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
@@ -790,155 +692,6 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
return EncodeHexTx(CTransaction(mergedTx));
}
-UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore *keystore, bool is_temp_keystore, const UniValue& hashType)
-{
- // Fetch previous transactions (inputs):
- CCoinsView viewDummy;
- CCoinsViewCache view(&viewDummy);
- {
- LOCK2(cs_main, mempool.cs);
- CCoinsViewCache &viewChain = *pcoinsTip;
- CCoinsViewMemPool viewMempool(&viewChain, mempool);
- view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
-
- for (const CTxIn& txin : mtx.vin) {
- view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
- }
-
- view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
- }
-
- // Add previous txouts given in the RPC call:
- if (!prevTxsUnival.isNull()) {
- UniValue prevTxs = prevTxsUnival.get_array();
- for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) {
- const UniValue& p = prevTxs[idx];
- if (!p.isObject()) {
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
- }
-
- UniValue prevOut = p.get_obj();
-
- RPCTypeCheckObj(prevOut,
- {
- {"txid", UniValueType(UniValue::VSTR)},
- {"vout", UniValueType(UniValue::VNUM)},
- {"scriptPubKey", UniValueType(UniValue::VSTR)},
- });
-
- uint256 txid = ParseHashO(prevOut, "txid");
-
- int nOut = find_value(prevOut, "vout").get_int();
- if (nOut < 0) {
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
- }
-
- COutPoint out(txid, nOut);
- std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
- CScript scriptPubKey(pkData.begin(), pkData.end());
-
- {
- const Coin& coin = view.AccessCoin(out);
- if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
- std::string err("Previous output scriptPubKey mismatch:\n");
- err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
- ScriptToAsmStr(scriptPubKey);
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
- }
- Coin newcoin;
- newcoin.out.scriptPubKey = scriptPubKey;
- newcoin.out.nValue = MAX_MONEY;
- if (prevOut.exists("amount")) {
- newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
- }
- newcoin.nHeight = 1;
- view.AddCoin(out, std::move(newcoin), true);
- }
-
- // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
- if (is_temp_keystore && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash())) {
- RPCTypeCheckObj(prevOut,
- {
- {"redeemScript", UniValueType(UniValue::VSTR)},
- {"witnessScript", UniValueType(UniValue::VSTR)},
- }, true);
- UniValue rs = find_value(prevOut, "redeemScript");
- if (!rs.isNull()) {
- std::vector<unsigned char> rsData(ParseHexV(rs, "redeemScript"));
- CScript redeemScript(rsData.begin(), rsData.end());
- keystore->AddCScript(redeemScript);
- // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
- // This is only for compatibility, it is encouraged to use the explicit witnessScript field instead.
- keystore->AddCScript(GetScriptForWitness(redeemScript));
- }
- UniValue ws = find_value(prevOut, "witnessScript");
- if (!ws.isNull()) {
- std::vector<unsigned char> wsData(ParseHexV(ws, "witnessScript"));
- CScript witnessScript(wsData.begin(), wsData.end());
- keystore->AddCScript(witnessScript);
- // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
- keystore->AddCScript(GetScriptForWitness(witnessScript));
- }
- }
- }
- }
-
- int nHashType = ParseSighashString(hashType);
-
- bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
-
- // Script verification errors
- UniValue vErrors(UniValue::VARR);
-
- // Use CTransaction for the constant parts of the
- // transaction to avoid rehashing.
- const CTransaction txConst(mtx);
- // Sign what we can:
- for (unsigned int i = 0; i < mtx.vin.size(); i++) {
- CTxIn& txin = mtx.vin[i];
- const Coin& coin = view.AccessCoin(txin.prevout);
- if (coin.IsSpent()) {
- TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
- continue;
- }
- const CScript& prevPubKey = coin.out.scriptPubKey;
- const CAmount& amount = coin.out.nValue;
-
- SignatureData sigdata = DataFromTransaction(mtx, i, coin.out);
- // Only sign SIGHASH_SINGLE if there's a corresponding output:
- if (!fHashSingle || (i < mtx.vout.size())) {
- ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
- }
-
- UpdateInput(txin, sigdata);
-
- // amount must be specified for valid segwit signature
- if (amount == MAX_MONEY && !txin.scriptWitness.IsNull()) {
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coin.out.ToString()));
- }
-
- ScriptError serror = SCRIPT_ERR_OK;
- if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
- if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
- // Unable to sign input and verification failed (possible attempt to partially sign).
- TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
- } else {
- TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
- }
- }
- }
- bool fComplete = vErrors.empty();
-
- UniValue result(UniValue::VOBJ);
- result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
- result.pushKV("complete", fComplete);
- if (!vErrors.empty()) {
- result.pushKV("errors", vErrors);
- }
-
- return result;
-}
-
static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4)
@@ -965,7 +718,7 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
{"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
{"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
{"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
- {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount spent"},
+ {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"},
},
},
},
@@ -996,8 +749,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
"}\n"
},
RPCExamples{
- HelpExampleCli("signrawtransactionwithkey", "\"myhex\"")
- + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\"")
+ HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"")
+ + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"")
},
}.ToString());
@@ -1019,27 +772,26 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
keystore.AddKey(key);
}
- return SignTransaction(*g_rpc_interfaces->chain, mtx, request.params[2], &keystore, true, request.params[3]);
-}
+ // Fetch previous transactions (inputs):
+ std::map<COutPoint, Coin> coins;
+ for (const CTxIn& txin : mtx.vin) {
+ coins[txin.prevout]; // Create empty map entry keyed by prevout.
+ }
+ FindCoins(coins);
-UniValue signrawtransaction(const JSONRPCRequest& request)
-{
- // This method should be removed entirely in V0.19, along with the entries in the
- // CRPCCommand table and rpc/client.cpp.
- throw JSONRPCError(RPC_METHOD_DEPRECATED, "signrawtransaction was removed in v0.18.\n"
- "Clients should transition to using signrawtransactionwithkey and signrawtransactionwithwallet");
+ return SignTransaction(mtx, request.params[2], &keystore, coins, true, request.params[3]);
}
static UniValue sendrawtransaction(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
- throw std::runtime_error(
- RPCHelpMan{"sendrawtransaction",
+ const RPCHelpMan help{"sendrawtransaction",
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
"\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
- {"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"},
+ {"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE),
+ "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
+ "/kB.\nSet to 0 to accept any fee rate.\n"},
},
RPCResult{
"\"hex\" (string) The transaction hash in hex\n"
@@ -1054,9 +806,16 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
},
- }.ToString());
+ };
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
+
+ RPCTypeCheck(request.params, {
+ UniValue::VSTR,
+ UniValueType(), // NUM or BOOL, checked later
+ });
// parse hex string from parameter
CMutableTransaction mtx;
@@ -1064,12 +823,22 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
- bool allowhighfees = false;
- if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool();
- const CAmount highfee{allowhighfees ? 0 : ::maxTxFee};
+ CAmount max_raw_tx_fee = DEFAULT_MAX_RAW_TX_FEE;
+ // TODO: temporary migration code for old clients. Remove in v0.20
+ if (request.params[1].isBool()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Second argument must be numeric (maxfeerate) and no longer supports a boolean. To allow a transaction with high fees, set maxfeerate to 0.");
+ } else if (!request.params[1].isNull()) {
+ size_t weight = GetTransactionWeight(*tx);
+ CFeeRate fr(AmountFromValue(request.params[1]));
+ // the +3/4 part rounds the value up, and is the same formula used when
+ // calculating the fee for a transaction
+ // (see GetVirtualTransactionSize)
+ max_raw_tx_fee = fr.GetFee((weight+3)/4);
+ }
+
uint256 txid;
std::string err_string;
- const TransactionError err = BroadcastTransaction(tx, txid, err_string, highfee);
+ const TransactionError err = BroadcastTransaction(tx, txid, err_string, max_raw_tx_fee);
if (TransactionError::OK != err) {
throw JSONRPCTransactionError(err, err_string);
}
@@ -1079,9 +848,7 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
static UniValue testmempoolaccept(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
- throw std::runtime_error(
- RPCHelpMan{"testmempoolaccept",
+ const RPCHelpMan help{"testmempoolaccept",
"\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n"
"\nThis checks if the transaction violates the consensus or policy rules.\n"
"\nSee sendrawtransaction call.\n",
@@ -1092,7 +859,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
},
},
- {"allowhighfees", RPCArg::Type::BOOL, /* default */ "false", "Allow high fees"},
+ {"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE), "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"},
},
RPCResult{
"[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n"
@@ -1114,10 +881,17 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
}
- RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL});
+ RPCTypeCheck(request.params, {
+ UniValue::VARR,
+ UniValueType(), // NUM or BOOL, checked later
+ });
+
if (request.params[0].get_array().size() != 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now");
}
@@ -1129,9 +903,17 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const uint256& tx_hash = tx->GetHash();
- CAmount max_raw_tx_fee = ::maxTxFee;
- if (!request.params[1].isNull() && request.params[1].get_bool()) {
- max_raw_tx_fee = 0;
+ CAmount max_raw_tx_fee = DEFAULT_MAX_RAW_TX_FEE;
+ // TODO: temporary migration code for old clients. Remove in v0.20
+ if (request.params[1].isBool()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Second argument must be numeric (maxfeerate) and no longer supports a boolean. To allow a transaction with high fees, set maxfeerate to 0.");
+ } else if (!request.params[1].isNull()) {
+ size_t weight = GetTransactionWeight(*tx);
+ CFeeRate fr(AmountFromValue(request.params[1]));
+ // the +3/4 part rounds the value up, and is the same formula used when
+ // calculating the fee for a transaction
+ // (see GetVirtualTransactionSize)
+ max_raw_tx_fee = fr.GetFee((weight+3)/4);
}
UniValue result(UniValue::VARR);
@@ -1500,7 +1282,6 @@ UniValue combinepsbt(const JSONRPCRequest& request)
throw JSONRPCTransactionError(error);
}
- UniValue result(UniValue::VOBJ);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << merged_psbt;
return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size());
@@ -1643,19 +1424,20 @@ UniValue createpsbt(const JSONRPCRequest& request)
UniValue converttopsbt(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
- RPCHelpMan{"converttopsbt",
+ const RPCHelpMan help{"converttopsbt",
"\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
{
{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},
- {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion.\n"
+ {"permitsigdata", RPCArg::Type::BOOL, /* default */ "false", "If true, any signatures in the input will be discarded and conversion\n"
" will continue. If false, RPC will fail if any signatures are present."},
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
- " If iswitness is not present, heuristic tests will be used in decoding. If true, only witness deserializaion\n"
- " will be tried. If false, only non-witness deserialization will be tried. Only has an effect if\n"
- " permitsigdata is true."},
+ "If iswitness is not present, heuristic tests will be used in decoding.\n"
+ "If true, only witness deserialization will be tried.\n"
+ "If false, only non-witness deserialization will be tried.\n"
+ "This boolean should reflect whether the transaction has inputs\n"
+ "(e.g. fully valid, or on-chain transactions), if known by the caller."
+ },
},
RPCResult{
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
@@ -1666,8 +1448,11 @@ UniValue converttopsbt(const JSONRPCRequest& request)
"\nConvert the transaction to a PSBT\n"
+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")
},
- }.ToString());
+ };
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
@@ -1676,8 +1461,8 @@ UniValue converttopsbt(const JSONRPCRequest& request)
bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool();
bool witness_specified = !request.params[2].isNull();
bool iswitness = witness_specified ? request.params[2].get_bool() : false;
- bool try_witness = permitsigdata ? (witness_specified ? iswitness : true) : false;
- bool try_no_witness = permitsigdata ? (witness_specified ? !iswitness : true) : true;
+ const bool try_witness = witness_specified ? iswitness : true;
+ const bool try_no_witness = witness_specified ? !iswitness : true;
if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
}
@@ -1862,21 +1647,21 @@ UniValue analyzepsbt(const JSONRPCRequest& request)
" \"has_utxo\" : true|false (boolean) Whether a UTXO is provided\n"
" \"is_final\" : true|false (boolean) Whether the input is finalized\n"
" \"missing\" : { (json object, optional) Things that are missing that are required to complete this input\n"
- " \"pubkeys\" : [ (array)\n"
+ " \"pubkeys\" : [ (array, optional)\n"
" \"keyid\" (string) Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing\n"
" ]\n"
- " \"signatures\" : [ (array)\n"
+ " \"signatures\" : [ (array, optional)\n"
" \"keyid\" (string) Public key ID, hash160 of the public key, of a public key whose signature is missing\n"
" ]\n"
- " \"redeemscript\" : \"hash\" (string) Hash160 of the redeemScript that is missing\n"
- " \"witnessscript\" : \"hash\" (string) SHA256 of the witnessScript that is missing\n"
+ " \"redeemscript\" : \"hash\" (string, optional) Hash160 of the redeemScript that is missing\n"
+ " \"witnessscript\" : \"hash\" (string, optional) SHA256 of the witnessScript that is missing\n"
" }\n"
- " \"next\" : \"role\" (string) Role of the next person that this input needs to go to\n"
+ " \"next\" : \"role\" (string, optional) Role of the next person that this input needs to go to\n"
" }\n"
" ,...\n"
" ]\n"
- " \"estimated_vsize\" : vsize (numeric) Estimated vsize of the final signed transaction\n"
- " \"estimated_feerate\" : feerate (numeric, optional) Estimated feerate of the final signed transaction. Shown only if all UTXO slots in the PSBT have been filled.\n"
+ " \"estimated_vsize\" : vsize (numeric, optional) Estimated vsize of the final signed transaction\n"
+ " \"estimated_feerate\" : feerate (numeric, optional) Estimated feerate of the final signed transaction in " + CURRENCY_UNIT + "/kB. Shown only if all UTXO slots in the PSBT have been filled.\n"
" \"fee\" : fee (numeric, optional) The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled.\n"
" \"next\" : \"role\" (string) Role of the next person that this psbt needs to go to\n"
"}\n"
@@ -1895,148 +1680,56 @@ UniValue analyzepsbt(const JSONRPCRequest& request)
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
- // Go through each input and build status
+ PSBTAnalysis psbta = AnalyzePSBT(psbtx);
+
UniValue result(UniValue::VOBJ);
UniValue inputs_result(UniValue::VARR);
- bool calc_fee = true;
- bool all_final = true;
- bool only_missing_sigs = true;
- bool only_missing_final = false;
- CAmount in_amt = 0;
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- PSBTInput& input = psbtx.inputs[i];
+ for (const auto& input : psbta.inputs) {
UniValue input_univ(UniValue::VOBJ);
UniValue missing(UniValue::VOBJ);
- // Check for a UTXO
- CTxOut utxo;
- if (psbtx.GetInputUTXO(utxo, i)) {
- in_amt += utxo.nValue;
- input_univ.pushKV("has_utxo", true);
- } else {
- input_univ.pushKV("has_utxo", false);
- input_univ.pushKV("is_final", false);
- input_univ.pushKV("next", "updater");
- calc_fee = false;
- }
+ input_univ.pushKV("has_utxo", input.has_utxo);
+ input_univ.pushKV("is_final", input.is_final);
+ input_univ.pushKV("next", PSBTRoleName(input.next));
- // Check if it is final
- if (!utxo.IsNull() && !PSBTInputSigned(input)) {
- input_univ.pushKV("is_final", false);
- all_final = false;
-
- // Figure out what is missing
- SignatureData outdata;
- bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata);
-
- // Things are missing
- if (!complete) {
- if (!outdata.missing_pubkeys.empty()) {
- // Missing pubkeys
- UniValue missing_pubkeys_univ(UniValue::VARR);
- for (const CKeyID& pubkey : outdata.missing_pubkeys) {
- missing_pubkeys_univ.push_back(HexStr(pubkey));
- }
- missing.pushKV("pubkeys", missing_pubkeys_univ);
- }
- if (!outdata.missing_redeem_script.IsNull()) {
- // Missing redeemScript
- missing.pushKV("redeemscript", HexStr(outdata.missing_redeem_script));
- }
- if (!outdata.missing_witness_script.IsNull()) {
- // Missing witnessScript
- missing.pushKV("witnessscript", HexStr(outdata.missing_witness_script));
- }
- if (!outdata.missing_sigs.empty()) {
- // Missing sigs
- UniValue missing_sigs_univ(UniValue::VARR);
- for (const CKeyID& pubkey : outdata.missing_sigs) {
- missing_sigs_univ.push_back(HexStr(pubkey));
- }
- missing.pushKV("signatures", missing_sigs_univ);
- }
- input_univ.pushKV("missing", missing);
-
- // If we are only missing signatures and nothing else, then next is signer
- if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
- input_univ.pushKV("next", "signer");
- } else {
- only_missing_sigs = false;
- input_univ.pushKV("next", "updater");
- }
- } else {
- only_missing_final = true;
- input_univ.pushKV("next", "finalizer");
+ if (!input.missing_pubkeys.empty()) {
+ UniValue missing_pubkeys_univ(UniValue::VARR);
+ for (const CKeyID& pubkey : input.missing_pubkeys) {
+ missing_pubkeys_univ.push_back(HexStr(pubkey));
+ }
+ missing.pushKV("pubkeys", missing_pubkeys_univ);
+ }
+ if (!input.missing_redeem_script.IsNull()) {
+ missing.pushKV("redeemscript", HexStr(input.missing_redeem_script));
+ }
+ if (!input.missing_witness_script.IsNull()) {
+ missing.pushKV("witnessscript", HexStr(input.missing_witness_script));
+ }
+ if (!input.missing_sigs.empty()) {
+ UniValue missing_sigs_univ(UniValue::VARR);
+ for (const CKeyID& pubkey : input.missing_sigs) {
+ missing_sigs_univ.push_back(HexStr(pubkey));
}
- } else if (!utxo.IsNull()){
- input_univ.pushKV("is_final", true);
+ missing.pushKV("signatures", missing_sigs_univ);
+ }
+ if (!missing.getKeys().empty()) {
+ input_univ.pushKV("missing", missing);
}
inputs_result.push_back(input_univ);
}
result.pushKV("inputs", inputs_result);
- if (all_final) {
- only_missing_sigs = false;
- result.pushKV("next", "extractor");
+ if (psbta.estimated_vsize != nullopt) {
+ result.pushKV("estimated_vsize", (int)*psbta.estimated_vsize);
}
- if (calc_fee) {
- // Get the output amount
- CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), 0,
- [](int a, const CTxOut& b) {
- return a += b.nValue;
- }
- );
-
- // Get the fee
- CAmount fee = in_amt - out_amt;
-
- // Estimate the size
- CMutableTransaction mtx(*psbtx.tx);
- CCoinsView view_dummy;
- CCoinsViewCache view(&view_dummy);
- bool success = true;
-
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- PSBTInput& input = psbtx.inputs[i];
- if (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true)) {
- mtx.vin[i].scriptSig = input.final_script_sig;
- mtx.vin[i].scriptWitness = input.final_script_witness;
-
- Coin newcoin;
- if (!psbtx.GetInputUTXO(newcoin.out, i)) {
- success = false;
- break;
- }
- newcoin.nHeight = 1;
- view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
- } else {
- success = false;
- break;
- }
- }
-
- if (success) {
- CTransaction ctx = CTransaction(mtx);
- size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
- result.pushKV("estimated_vsize", (int)size);
- // Estimate fee rate
- CFeeRate feerate(fee, size);
- result.pushKV("estimated_feerate", feerate.ToString());
- }
- result.pushKV("fee", ValueFromAmount(fee));
-
- if (only_missing_sigs) {
- result.pushKV("next", "signer");
- } else if (only_missing_final) {
- result.pushKV("next", "finalizer");
- } else if (all_final) {
- result.pushKV("next", "extractor");
- } else {
- result.pushKV("next", "updater");
- }
- } else {
- result.pushKV("next", "updater");
+ if (psbta.estimated_feerate != nullopt) {
+ result.pushKV("estimated_feerate", ValueFromAmount(psbta.estimated_feerate->GetFeePerK()));
+ }
+ if (psbta.fee != nullopt) {
+ result.pushKV("fee", ValueFromAmount(*psbta.fee));
}
+ result.pushKV("next", PSBTRoleName(psbta.next));
+
return result;
}
@@ -2048,11 +1741,10 @@ static const CRPCCommand commands[] =
{ "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime","replaceable"} },
{ "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring","iswitness"} },
{ "rawtransactions", "decodescript", &decodescript, {"hexstring"} },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees"} },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, {"hexstring","allowhighfees|maxfeerate"} },
{ "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} },
- { "hidden", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} },
{ "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} },
- { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} },
+ { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees|maxfeerate"} },
{ "rawtransactions", "decodepsbt", &decodepsbt, {"psbt"} },
{ "rawtransactions", "combinepsbt", &combinepsbt, {"txs"} },
{ "rawtransactions", "finalizepsbt", &finalizepsbt, {"psbt", "extract"} },
diff --git a/src/rpc/rawtransaction.h b/src/rpc/rawtransaction.h
deleted file mode 100644
index 52d701d1c3..0000000000
--- a/src/rpc/rawtransaction.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2017-2018 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_RPC_RAWTRANSACTION_H
-#define BITCOIN_RPC_RAWTRANSACTION_H
-
-class CBasicKeyStore;
-struct CMutableTransaction;
-class UniValue;
-
-namespace interfaces {
-class Chain;
-} // namespace interfaces
-
-/** Sign a transaction with the given keystore and previous transactions */
-UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);
-
-/** Create a transaction from univalue parameters */
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf);
-
-#endif // BITCOIN_RPC_RAWTRANSACTION_H
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
new file mode 100644
index 0000000000..9c4cdc3a90
--- /dev/null
+++ b/src/rpc/rawtransaction_util.cpp
@@ -0,0 +1,282 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 <rpc/rawtransaction_util.h>
+
+#include <coins.h>
+#include <core_io.h>
+#include <key_io.h>
+#include <keystore.h>
+#include <policy/policy.h>
+#include <primitives/transaction.h>
+#include <rpc/protocol.h>
+#include <rpc/util.h>
+#include <tinyformat.h>
+#include <univalue.h>
+#include <util/rbf.h>
+#include <util/strencodings.h>
+
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf)
+{
+ if (inputs_in.isNull() || outputs_in.isNull())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
+
+ UniValue inputs = inputs_in.get_array();
+ const bool outputs_is_obj = outputs_in.isObject();
+ UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
+
+ CMutableTransaction rawTx;
+
+ if (!locktime.isNull()) {
+ int64_t nLockTime = locktime.get_int64();
+ if (nLockTime < 0 || nLockTime > LOCKTIME_MAX)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
+ rawTx.nLockTime = nLockTime;
+ }
+
+ bool rbfOptIn = rbf.isTrue();
+
+ for (unsigned int idx = 0; idx < inputs.size(); idx++) {
+ const UniValue& input = inputs[idx];
+ const UniValue& o = input.get_obj();
+
+ uint256 txid = ParseHashO(o, "txid");
+
+ const UniValue& vout_v = find_value(o, "vout");
+ if (!vout_v.isNum())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
+ int nOutput = vout_v.get_int();
+ if (nOutput < 0)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
+
+ uint32_t nSequence;
+ if (rbfOptIn) {
+ nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
+ } else if (rawTx.nLockTime) {
+ nSequence = CTxIn::SEQUENCE_FINAL - 1;
+ } else {
+ nSequence = CTxIn::SEQUENCE_FINAL;
+ }
+
+ // set the sequence number if passed in the parameters object
+ const UniValue& sequenceObj = find_value(o, "sequence");
+ if (sequenceObj.isNum()) {
+ int64_t seqNr64 = sequenceObj.get_int64();
+ if (seqNr64 < 0 || seqNr64 > CTxIn::SEQUENCE_FINAL) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, sequence number is out of range");
+ } else {
+ nSequence = (uint32_t)seqNr64;
+ }
+ }
+
+ CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
+
+ rawTx.vin.push_back(in);
+ }
+
+ if (!outputs_is_obj) {
+ // Translate array of key-value pairs into dict
+ UniValue outputs_dict = UniValue(UniValue::VOBJ);
+ for (size_t i = 0; i < outputs.size(); ++i) {
+ const UniValue& output = outputs[i];
+ if (!output.isObject()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair not an object as expected");
+ }
+ if (output.size() != 1) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, key-value pair must contain exactly one key");
+ }
+ outputs_dict.pushKVs(output);
+ }
+ outputs = std::move(outputs_dict);
+ }
+
+ // Duplicate checking
+ std::set<CTxDestination> destinations;
+ bool has_data{false};
+
+ for (const std::string& name_ : outputs.getKeys()) {
+ if (name_ == "data") {
+ if (has_data) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, duplicate key: data");
+ }
+ has_data = true;
+ std::vector<unsigned char> data = ParseHexV(outputs[name_].getValStr(), "Data");
+
+ CTxOut out(0, CScript() << OP_RETURN << data);
+ rawTx.vout.push_back(out);
+ } else {
+ CTxDestination destination = DecodeDestination(name_);
+ if (!IsValidDestination(destination)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
+ }
+
+ if (!destinations.insert(destination).second) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + name_);
+ }
+
+ CScript scriptPubKey = GetScriptForDestination(destination);
+ CAmount nAmount = AmountFromValue(outputs[name_]);
+
+ CTxOut out(nAmount, scriptPubKey);
+ rawTx.vout.push_back(out);
+ }
+ }
+
+ if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(CTransaction(rawTx))) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
+ }
+
+ return rawTx;
+}
+
+/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
+static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
+{
+ UniValue entry(UniValue::VOBJ);
+ entry.pushKV("txid", txin.prevout.hash.ToString());
+ entry.pushKV("vout", (uint64_t)txin.prevout.n);
+ UniValue witness(UniValue::VARR);
+ for (unsigned int i = 0; i < txin.scriptWitness.stack.size(); i++) {
+ witness.push_back(HexStr(txin.scriptWitness.stack[i].begin(), txin.scriptWitness.stack[i].end()));
+ }
+ entry.pushKV("witness", witness);
+ entry.pushKV("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
+ entry.pushKV("sequence", (uint64_t)txin.nSequence);
+ entry.pushKV("error", strMessage);
+ vErrorsRet.push_back(entry);
+}
+
+UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxsUnival, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool is_temp_keystore, const UniValue& hashType)
+{
+ // Add previous txouts given in the RPC call:
+ if (!prevTxsUnival.isNull()) {
+ UniValue prevTxs = prevTxsUnival.get_array();
+ for (unsigned int idx = 0; idx < prevTxs.size(); ++idx) {
+ const UniValue& p = prevTxs[idx];
+ if (!p.isObject()) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
+ }
+
+ UniValue prevOut = p.get_obj();
+
+ RPCTypeCheckObj(prevOut,
+ {
+ {"txid", UniValueType(UniValue::VSTR)},
+ {"vout", UniValueType(UniValue::VNUM)},
+ {"scriptPubKey", UniValueType(UniValue::VSTR)},
+ });
+
+ uint256 txid = ParseHashO(prevOut, "txid");
+
+ int nOut = find_value(prevOut, "vout").get_int();
+ if (nOut < 0) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
+ }
+
+ COutPoint out(txid, nOut);
+ std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
+ CScript scriptPubKey(pkData.begin(), pkData.end());
+
+ {
+ auto coin = coins.find(out);
+ if (coin != coins.end() && !coin->second.IsSpent() && coin->second.out.scriptPubKey != scriptPubKey) {
+ std::string err("Previous output scriptPubKey mismatch:\n");
+ err = err + ScriptToAsmStr(coin->second.out.scriptPubKey) + "\nvs:\n"+
+ ScriptToAsmStr(scriptPubKey);
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
+ }
+ Coin newcoin;
+ newcoin.out.scriptPubKey = scriptPubKey;
+ newcoin.out.nValue = MAX_MONEY;
+ if (prevOut.exists("amount")) {
+ newcoin.out.nValue = AmountFromValue(find_value(prevOut, "amount"));
+ }
+ newcoin.nHeight = 1;
+ coins[out] = std::move(newcoin);
+ }
+
+ // if redeemScript and private keys were given, add redeemScript to the keystore so it can be signed
+ if (is_temp_keystore && (scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash())) {
+ RPCTypeCheckObj(prevOut,
+ {
+ {"redeemScript", UniValueType(UniValue::VSTR)},
+ {"witnessScript", UniValueType(UniValue::VSTR)},
+ }, true);
+ UniValue rs = find_value(prevOut, "redeemScript");
+ if (!rs.isNull()) {
+ std::vector<unsigned char> rsData(ParseHexV(rs, "redeemScript"));
+ CScript redeemScript(rsData.begin(), rsData.end());
+ keystore->AddCScript(redeemScript);
+ // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
+ // This is only for compatibility, it is encouraged to use the explicit witnessScript field instead.
+ keystore->AddCScript(GetScriptForWitness(redeemScript));
+ }
+ UniValue ws = find_value(prevOut, "witnessScript");
+ if (!ws.isNull()) {
+ std::vector<unsigned char> wsData(ParseHexV(ws, "witnessScript"));
+ CScript witnessScript(wsData.begin(), wsData.end());
+ keystore->AddCScript(witnessScript);
+ // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
+ keystore->AddCScript(GetScriptForWitness(witnessScript));
+ }
+ }
+ }
+ }
+
+ int nHashType = ParseSighashString(hashType);
+
+ bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
+
+ // Script verification errors
+ UniValue vErrors(UniValue::VARR);
+
+ // Use CTransaction for the constant parts of the
+ // transaction to avoid rehashing.
+ const CTransaction txConst(mtx);
+ // Sign what we can:
+ for (unsigned int i = 0; i < mtx.vin.size(); i++) {
+ CTxIn& txin = mtx.vin[i];
+ auto coin = coins.find(txin.prevout);
+ if (coin == coins.end() || coin->second.IsSpent()) {
+ TxInErrorToJSON(txin, vErrors, "Input not found or already spent");
+ continue;
+ }
+ const CScript& prevPubKey = coin->second.out.scriptPubKey;
+ const CAmount& amount = coin->second.out.nValue;
+
+ SignatureData sigdata = DataFromTransaction(mtx, i, coin->second.out);
+ // Only sign SIGHASH_SINGLE if there's a corresponding output:
+ if (!fHashSingle || (i < mtx.vout.size())) {
+ ProduceSignature(*keystore, MutableTransactionSignatureCreator(&mtx, i, amount, nHashType), prevPubKey, sigdata);
+ }
+
+ UpdateInput(txin, sigdata);
+
+ // amount must be specified for valid segwit signature
+ if (amount == MAX_MONEY && !txin.scriptWitness.IsNull()) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coin->second.out.ToString()));
+ }
+
+ ScriptError serror = SCRIPT_ERR_OK;
+ if (!VerifyScript(txin.scriptSig, prevPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) {
+ if (serror == SCRIPT_ERR_INVALID_STACK_OPERATION) {
+ // Unable to sign input and verification failed (possible attempt to partially sign).
+ TxInErrorToJSON(txin, vErrors, "Unable to sign input, invalid stack size (possibly missing key)");
+ } else {
+ TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
+ }
+ }
+ }
+ bool fComplete = vErrors.empty();
+
+ UniValue result(UniValue::VOBJ);
+ result.pushKV("hex", EncodeHexTx(CTransaction(mtx)));
+ result.pushKV("complete", fComplete);
+ if (!vErrors.empty()) {
+ result.pushKV("errors", vErrors);
+ }
+
+ return result;
+}
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
new file mode 100644
index 0000000000..c115d33a77
--- /dev/null
+++ b/src/rpc/rawtransaction_util.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2017-2018 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_RPC_RAWTRANSACTION_UTIL_H
+#define BITCOIN_RPC_RAWTRANSACTION_UTIL_H
+
+#include <map>
+
+class CBasicKeyStore;
+class UniValue;
+struct CMutableTransaction;
+class Coin;
+class COutPoint;
+
+/**
+ * Sign a transaction with the given keystore and previous transactions
+ *
+ * @param mtx The transaction to-be-signed
+ * @param prevTxs Array of previous txns outputs that tx depends on but may not yet be in the block chain
+ * @param keystore Temporary keystore containing signing keys
+ * @param coins Map of unspent outputs - coins in mempool and current chain UTXO set, may be extended by previous txns outputs after call
+ * @param tempKeystore Whether to use temporary keystore
+ * @param hashType The signature hash type
+ * @returns JSON object with details of signed transaction
+ */
+UniValue SignTransaction(CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore* keystore, std::map<COutPoint, Coin>& coins, bool tempKeystore, const UniValue& hashType);
+
+/** Create a transaction from univalue parameters */
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf);
+
+#endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index cd90573da0..ca17d379bc 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -7,11 +7,9 @@
#include <fs.h>
#include <key_io.h>
-#include <random.h>
#include <rpc/util.h>
#include <shutdown.h>
#include <sync.h>
-#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
@@ -30,6 +28,7 @@ static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server starte
static RPCTimerInterface* timerInterface = nullptr;
/* Map of name to timer. */
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
+static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);
struct RPCCommandExecutionInfo
{
@@ -76,108 +75,15 @@ void RPCServer::OnStopped(std::function<void ()> slot)
g_rpcSignals.Stopped.connect(slot);
}
-void RPCTypeCheck(const UniValue& params,
- const std::list<UniValueType>& typesExpected,
- bool fAllowNull)
-{
- unsigned int i = 0;
- for (const UniValueType& t : typesExpected) {
- if (params.size() <= i)
- break;
-
- const UniValue& v = params[i];
- if (!(fAllowNull && v.isNull())) {
- RPCTypeCheckArgument(v, t);
- }
- i++;
- }
-}
-
-void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
-{
- if (!typeExpected.typeAny && value.type() != typeExpected.type) {
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
- }
-}
-
-void RPCTypeCheckObj(const UniValue& o,
- const std::map<std::string, UniValueType>& typesExpected,
- bool fAllowNull,
- bool fStrict)
-{
- for (const auto& t : typesExpected) {
- const UniValue& v = find_value(o, t.first);
- if (!fAllowNull && v.isNull())
- throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
-
- if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
- std::string err = strprintf("Expected type %s for %s, got %s",
- uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
- throw JSONRPCError(RPC_TYPE_ERROR, err);
- }
- }
-
- if (fStrict)
- {
- for (const std::string& k : o.getKeys())
- {
- if (typesExpected.count(k) == 0)
- {
- std::string err = strprintf("Unexpected key %s", k);
- throw JSONRPCError(RPC_TYPE_ERROR, err);
- }
- }
- }
-}
-
-CAmount AmountFromValue(const UniValue& value)
-{
- if (!value.isNum() && !value.isStr())
- throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
- CAmount amount;
- if (!ParseFixedPoint(value.getValStr(), 8, &amount))
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- if (!MoneyRange(amount))
- throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
- return amount;
-}
-
-uint256 ParseHashV(const UniValue& v, std::string strName)
-{
- std::string strHex(v.get_str());
- if (64 != strHex.length())
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
- if (!IsHex(strHex)) // Note: IsHex("") is false
- throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
- return uint256S(strHex);
-}
-uint256 ParseHashO(const UniValue& o, std::string strKey)
-{
- return ParseHashV(find_value(o, strKey), strKey);
-}
-std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
-{
- std::string strHex;
- if (v.isStr())
- strHex = v.get_str();
- if (!IsHex(strHex))
- throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
- return ParseHex(strHex);
-}
-std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
-{
- return ParseHexV(find_value(o, strKey), strKey);
-}
-
std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
{
std::string strRet;
std::string category;
- std::set<rpcfn_type> setDone;
+ std::set<intptr_t> setDone;
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
for (const auto& entry : mapCommands)
- vCommands.push_back(make_pair(entry.second->category + entry.first, entry.second));
+ vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
sort(vCommands.begin(), vCommands.end());
JSONRPCRequest jreq(helpreq);
@@ -193,9 +99,9 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
jreq.strMethod = strMethod;
try
{
- rpcfn_type pfn = pcmd->actor;
- if (setDone.insert(pfn).second)
- (*pfn)(jreq);
+ UniValue unused_result;
+ if (setDone.insert(pcmd->unique_id).second)
+ pcmd->actor(jreq, unused_result, true /* last_handler */);
}
catch (const std::exception& e)
{
@@ -296,8 +202,20 @@ static UniValue getrpcinfo(const JSONRPCRequest& request)
RPCHelpMan{"getrpcinfo",
"\nReturns details of the RPC server.\n",
{},
- RPCResults{},
- RPCExamples{""},
+ RPCResult{
+ "{\n"
+ " \"active_commands\" (array) All active commands\n"
+ " [\n"
+ " { (object) Information about an active command\n"
+ " \"method\" (string) The name of the RPC command \n"
+ " \"duration\" (numeric) The running time in microseconds\n"
+ " },...\n"
+ " ]\n"
+ "}\n"
+ },
+ RPCExamples{
+ HelpExampleCli("getrpcinfo", "")
+ + HelpExampleRpc("getrpcinfo", "")},
}.ToString()
);
}
@@ -337,32 +255,32 @@ CRPCTable::CRPCTable()
const CRPCCommand *pcmd;
pcmd = &vRPCCommands[vcidx];
- mapCommands[pcmd->name] = pcmd;
+ mapCommands[pcmd->name].push_back(pcmd);
}
}
-const CRPCCommand *CRPCTable::operator[](const std::string &name) const
-{
- std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
- if (it == mapCommands.end())
- return nullptr;
- return (*it).second;
-}
-
bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
{
if (IsRPCRunning())
return false;
- // don't allow overwriting for now
- std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
- if (it != mapCommands.end())
- return false;
-
- mapCommands[name] = pcmd;
+ mapCommands[name].push_back(pcmd);
return true;
}
+bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
+{
+ auto it = mapCommands.find(name);
+ if (it != mapCommands.end()) {
+ auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
+ if (it->second.end() != new_end) {
+ it->second.erase(new_end, it->second.end());
+ return true;
+ }
+ }
+ return false;
+}
+
void StartRPC()
{
LogPrint(BCLog::RPC, "Starting RPC\n");
@@ -543,18 +461,28 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
}
// Find method
- const CRPCCommand *pcmd = tableRPC[request.strMethod];
- if (!pcmd)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
+ auto it = mapCommands.find(request.strMethod);
+ if (it != mapCommands.end()) {
+ UniValue result;
+ for (const auto& command : it->second) {
+ if (ExecuteCommand(*command, request, result, &command == &it->second.back())) {
+ return result;
+ }
+ }
+ }
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
+}
+static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
+{
try
{
RPCCommandExecution execution(request.strMethod);
// Execute, convert arguments to array if necessary
if (request.params.isObject()) {
- return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
+ return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
} else {
- return pcmd->actor(request);
+ return command.actor(request, result, last_handler);
}
}
catch (const std::exception& e)
@@ -570,17 +498,6 @@ std::vector<std::string> CRPCTable::listCommands() const
return commandList;
}
-std::string HelpExampleCli(const std::string& methodname, const std::string& args)
-{
- return "> bitcoin-cli " + methodname + " " + args + "\n";
-}
-
-std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
-{
- return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
- "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
-}
-
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
{
if (!timerInterface)
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 2d62a76f3c..431ff0bb7c 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -27,15 +27,6 @@ namespace RPCServer
void OnStopped(std::function<void ()> slot);
}
-/** Wrapper for UniValue::VType, which includes typeAny:
- * Used to denote don't care type. */
-struct UniValueType {
- UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
- UniValueType() : typeAny(true) {}
- bool typeAny;
- UniValue::VType type;
-};
-
class JSONRPCRequest
{
public:
@@ -65,26 +56,6 @@ void SetRPCWarmupFinished();
/* returns the current warmup state. */
bool RPCIsInWarmup(std::string *outStatus);
-/**
- * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
- * the right number of arguments are passed, just that any passed are the correct type.
- */
-void RPCTypeCheck(const UniValue& params,
- const std::list<UniValueType>& typesExpected, bool fAllowNull=false);
-
-/**
- * Type-check one argument; throws JSONRPCError if wrong type given.
- */
-void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected);
-
-/*
- Check for expected keys/value types in an Object.
-*/
-void RPCTypeCheckObj(const UniValue& o,
- const std::map<std::string, UniValueType>& typesExpected,
- bool fAllowNull = false,
- bool fStrict = false);
-
/** Opaque base class for timers returned by NewTimerFunc.
* This provides no methods at the moment, but makes sure that delete
* cleans up the whole state.
@@ -131,10 +102,31 @@ typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
class CRPCCommand
{
public:
+ //! RPC method handler reading request and assigning result. Should return
+ //! true if request is fully handled, false if it should be passed on to
+ //! subsequent handlers.
+ using Actor = std::function<bool(const JSONRPCRequest& request, UniValue& result, bool last_handler)>;
+
+ //! Constructor taking Actor callback supporting multiple handlers.
+ CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::string> args, intptr_t unique_id)
+ : category(std::move(category)), name(std::move(name)), actor(std::move(actor)), argNames(std::move(args)),
+ unique_id(unique_id)
+ {
+ }
+
+ //! Simplified constructor taking plain rpcfn_type function pointer.
+ CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args)
+ : CRPCCommand(category, name,
+ [fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn(request); return true; },
+ {args.begin(), args.end()}, intptr_t(fn))
+ {
+ }
+
std::string category;
std::string name;
- rpcfn_type actor;
+ Actor actor;
std::vector<std::string> argNames;
+ intptr_t unique_id;
};
/**
@@ -143,10 +135,9 @@ public:
class CRPCTable
{
private:
- std::map<std::string, const CRPCCommand*> mapCommands;
+ std::map<std::string, std::vector<const CRPCCommand*>> mapCommands;
public:
CRPCTable();
- const CRPCCommand* operator[](const std::string& name) const;
std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
/**
@@ -169,9 +160,7 @@ public:
*
* Returns false if RPC server is already running (dump concurrency protection).
*
- * Commands cannot be overwritten (returns false).
- *
- * Commands with different method names but the same callback function will
+ * Commands with different method names but the same unique_id will
* be considered aliases, and only the first registered method name will
* show up in the help text command listing. Aliased commands do not have
* to have the same behavior. Server and client code can distinguish
@@ -179,25 +168,13 @@ public:
* register different names, types, and numbers of parameters.
*/
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
+ bool removeCommand(const std::string& name, const CRPCCommand* pcmd);
};
bool IsDeprecatedRPCEnabled(const std::string& method);
extern CRPCTable tableRPC;
-/**
- * Utilities: convert hex-encoded Values
- * (throws error if not hex).
- */
-extern uint256 ParseHashV(const UniValue& v, std::string strName);
-extern uint256 ParseHashO(const UniValue& o, std::string strKey);
-extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
-extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
-
-extern CAmount AmountFromValue(const UniValue& value);
-extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
-extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
-
void StartRPC();
void InterruptRPC();
void StopRPC();
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 10979b43b0..4642cf16b1 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -4,12 +4,119 @@
#include <key_io.h>
#include <keystore.h>
+#include <outputtype.h>
#include <rpc/util.h>
#include <tinyformat.h>
#include <util/strencodings.h>
+#include <tuple>
+
InitInterfaces* g_rpc_interfaces = nullptr;
+void RPCTypeCheck(const UniValue& params,
+ const std::list<UniValueType>& typesExpected,
+ bool fAllowNull)
+{
+ unsigned int i = 0;
+ for (const UniValueType& t : typesExpected) {
+ if (params.size() <= i)
+ break;
+
+ const UniValue& v = params[i];
+ if (!(fAllowNull && v.isNull())) {
+ RPCTypeCheckArgument(v, t);
+ }
+ i++;
+ }
+}
+
+void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected)
+{
+ if (!typeExpected.typeAny && value.type() != typeExpected.type) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type())));
+ }
+}
+
+void RPCTypeCheckObj(const UniValue& o,
+ const std::map<std::string, UniValueType>& typesExpected,
+ bool fAllowNull,
+ bool fStrict)
+{
+ for (const auto& t : typesExpected) {
+ const UniValue& v = find_value(o, t.first);
+ if (!fAllowNull && v.isNull())
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
+
+ if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
+ std::string err = strprintf("Expected type %s for %s, got %s",
+ uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
+ throw JSONRPCError(RPC_TYPE_ERROR, err);
+ }
+ }
+
+ if (fStrict)
+ {
+ for (const std::string& k : o.getKeys())
+ {
+ if (typesExpected.count(k) == 0)
+ {
+ std::string err = strprintf("Unexpected key %s", k);
+ throw JSONRPCError(RPC_TYPE_ERROR, err);
+ }
+ }
+ }
+}
+
+CAmount AmountFromValue(const UniValue& value)
+{
+ if (!value.isNum() && !value.isStr())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
+ CAmount amount;
+ if (!ParseFixedPoint(value.getValStr(), 8, &amount))
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
+ if (!MoneyRange(amount))
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
+ return amount;
+}
+
+uint256 ParseHashV(const UniValue& v, std::string strName)
+{
+ std::string strHex(v.get_str());
+ if (64 != strHex.length())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d, for '%s')", strName, 64, strHex.length(), strHex));
+ if (!IsHex(strHex)) // Note: IsHex("") is false
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ return uint256S(strHex);
+}
+uint256 ParseHashO(const UniValue& o, std::string strKey)
+{
+ return ParseHashV(find_value(o, strKey), strKey);
+}
+std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName)
+{
+ std::string strHex;
+ if (v.isStr())
+ strHex = v.get_str();
+ if (!IsHex(strHex))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ return ParseHex(strHex);
+}
+std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey)
+{
+ return ParseHexV(find_value(o, strKey), strKey);
+}
+
+std::string HelpExampleCli(const std::string& methodname, const std::string& args)
+{
+ return "> bitcoin-cli " + methodname + " " + args + "\n";
+}
+
+std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
+{
+ return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
+ "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
+}
+
// Converts a hex string to a public key if possible
CPubKey HexToPubKey(const std::string& hex_in)
{
@@ -44,8 +151,8 @@ CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
return vchPubKey;
}
-// Creates a multisig redeemscript from a given list of public keys and number required.
-CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys)
+// Creates a multisig address from a given list of public keys, number of signatures required, and the address type
+CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out)
{
// Gather public keys
if (required < 1) {
@@ -58,13 +165,24 @@ CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey
throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
}
- CScript result = GetScriptForMultisig(required, pubkeys);
+ script_out = GetScriptForMultisig(required, pubkeys);
- if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)));
+ if (script_out.size() > MAX_SCRIPT_ELEMENT_SIZE) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", script_out.size(), MAX_SCRIPT_ELEMENT_SIZE)));
}
- return result;
+ // Check if any keys are uncompressed. If so, the type is legacy
+ for (const CPubKey& pk : pubkeys) {
+ if (!pk.IsCompressed()) {
+ type = OutputType::LEGACY;
+ break;
+ }
+ }
+
+ // Make the address
+ CTxDestination dest = AddAndGetDestinationForScript(keystore, script_out, type);
+
+ return dest;
}
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
@@ -77,7 +195,7 @@ public:
return UniValue(UniValue::VOBJ);
}
- UniValue operator()(const CKeyID& keyID) const
+ UniValue operator()(const PKHash& keyID) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", false);
@@ -85,7 +203,7 @@ public:
return obj;
}
- UniValue operator()(const CScriptID& scriptID) const
+ UniValue operator()(const ScriptHash& scriptID) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", true);
@@ -165,6 +283,10 @@ UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_s
}
}
+/**
+ * A pair of strings that can be aligned (through padding) with other Sections
+ * later on
+ */
struct Section {
Section(const std::string& left, const std::string& right)
: m_left{left}, m_right{right} {}
@@ -172,6 +294,10 @@ struct Section {
const std::string m_right;
};
+/**
+ * Keeps track of RPCArgs by transforming them into sections for the purpose
+ * of serializing everything to a single string
+ */
struct Sections {
std::vector<Section> m_sections;
size_t m_max_pad{0};
@@ -182,16 +308,26 @@ struct Sections {
m_sections.push_back(s);
}
+ /**
+ * Serializing RPCArgs depends on the outer type. Only arrays and
+ * dictionaries can be nested in json. The top-level outer type is "named
+ * arguments", a mix between a dictionary and arrays.
+ */
enum class OuterType {
ARR,
OBJ,
NAMED_ARG, // Only set on first recursion
};
+ /**
+ * Recursive helper to translate an RPCArg into sections
+ */
void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NAMED_ARG)
{
const auto indent = std::string(current_indent, ' ');
const auto indent_next = std::string(current_indent + 2, ' ');
+ const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name
+
switch (arg.m_type) {
case RPCArg::Type::STR_HEX:
case RPCArg::Type::STR:
@@ -201,10 +337,10 @@ struct Sections {
case RPCArg::Type::BOOL: {
if (outer_type == OuterType::NAMED_ARG) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
- if (arg.m_type_str.size() != 0 && outer_type == OuterType::OBJ) {
+ if (arg.m_type_str.size() != 0 && push_name) {
left += "\"" + arg.m_name + "\": " + arg.m_type_str.at(0);
} else {
- left += outer_type == OuterType::OBJ ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
+ left += push_name ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
}
left += ",";
PushSection({left, arg.ToDescriptionString()});
@@ -213,7 +349,7 @@ struct Sections {
case RPCArg::Type::OBJ:
case RPCArg::Type::OBJ_USER_KEYS: {
const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString();
- PushSection({indent + "{", right});
+ PushSection({indent + (push_name ? "\"" + arg.m_name + "\": " : "") + "{", right});
for (const auto& arg_inner : arg.m_inner) {
Push(arg_inner, current_indent + 2, OuterType::OBJ);
}
@@ -225,7 +361,7 @@ struct Sections {
}
case RPCArg::Type::ARR: {
auto left = indent;
- left += outer_type == OuterType::OBJ ? "\"" + arg.m_name + "\": " : "";
+ left += push_name ? "\"" + arg.m_name + "\": " : "";
left += "[";
const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString();
PushSection({left, right});
@@ -241,6 +377,9 @@ struct Sections {
}
}
+ /**
+ * Concatenate all sections with proper padding
+ */
std::string ToString() const
{
std::string ret;
@@ -529,7 +668,7 @@ std::string RPCArg::ToString(const bool oneline) const
assert(false);
}
-std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
+static std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
{
if (value.isNum()) {
return {0, value.get_int64()};
@@ -542,3 +681,19 @@ std::pair<int64_t, int64_t> ParseRange(const UniValue& value)
}
throw JSONRPCError(RPC_INVALID_PARAMETER, "Range must be specified as end or as [begin,end]");
}
+
+std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value)
+{
+ int64_t low, high;
+ std::tie(low, high) = ParseRange(value);
+ if (low < 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should be greater or equal than 0");
+ }
+ if ((high >> 31) != 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "End of range is too high");
+ }
+ if (high >= low + 1000000) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Range is too large");
+ }
+ return {low, high};
+}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index e4cc1fde44..0eb2fef5c3 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -6,6 +6,7 @@
#define BITCOIN_RPC_UTIL_H
#include <node/transaction.h>
+#include <outputtype.h>
#include <pubkey.h>
#include <rpc/protocol.h>
#include <script/standard.h>
@@ -26,9 +27,51 @@ struct InitInterfaces;
//! state to RPC method implementations.
extern InitInterfaces* g_rpc_interfaces;
+/** Wrapper for UniValue::VType, which includes typeAny:
+ * Used to denote don't care type. */
+struct UniValueType {
+ UniValueType(UniValue::VType _type) : typeAny(false), type(_type) {}
+ UniValueType() : typeAny(true) {}
+ bool typeAny;
+ UniValue::VType type;
+};
+
+/**
+ * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
+ * the right number of arguments are passed, just that any passed are the correct type.
+ */
+void RPCTypeCheck(const UniValue& params,
+ const std::list<UniValueType>& typesExpected, bool fAllowNull=false);
+
+/**
+ * Type-check one argument; throws JSONRPCError if wrong type given.
+ */
+void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected);
+
+/*
+ Check for expected keys/value types in an Object.
+*/
+void RPCTypeCheckObj(const UniValue& o,
+ const std::map<std::string, UniValueType>& typesExpected,
+ bool fAllowNull = false,
+ bool fStrict = false);
+
+/**
+ * Utilities: convert hex-encoded Values
+ * (throws error if not hex).
+ */
+extern uint256 ParseHashV(const UniValue& v, std::string strName);
+extern uint256 ParseHashO(const UniValue& o, std::string strKey);
+extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
+extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
+
+extern CAmount AmountFromValue(const UniValue& value);
+extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
+extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
+
CPubKey HexToPubKey(const std::string& hex_in);
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in);
-CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys);
+CTxDestination AddAndGetMultisigDestination(const int required, const std::vector<CPubKey>& pubkeys, OutputType type, CKeyStore& keystore, CScript& script_out);
UniValue DescribeAddress(const CTxDestination& dest);
@@ -39,7 +82,7 @@ RPCErrorCode RPCErrorFromTransactionError(TransactionError terr);
UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = "");
//! Parse a JSON range specified as int64, or [int64, int64]
-std::pair<int64_t, int64_t> ParseRange(const UniValue& value);
+std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value);
struct RPCArg {
enum class Type {
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 43448d7222..50119ba184 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -164,6 +164,9 @@ struct PubkeyProvider
/** Get the descriptor string form including private data (if available in arg). */
virtual bool ToPrivateString(const SigningProvider& arg, std::string& out) const = 0;
+
+ /** Derive a private key, if private data is available in arg. */
+ virtual bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const = 0;
};
class OriginPubkeyProvider final : public PubkeyProvider
@@ -195,6 +198,10 @@ public:
ret = "[" + OriginString() + "]" + std::move(sub);
return true;
}
+ bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
+ {
+ return m_provider->GetPrivKey(pos, arg, key);
+ }
};
/** An object representing a parsed constant public key in a descriptor. */
@@ -222,6 +229,10 @@ public:
ret = EncodeSecret(key);
return true;
}
+ bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
+ {
+ return arg.GetKey(m_pubkey.GetID(), key);
+ }
};
enum class DeriveType {
@@ -266,14 +277,9 @@ public:
{
if (key) {
if (IsHardened()) {
- CExtKey extkey;
- if (!GetExtKey(arg, extkey)) return false;
- for (auto entry : m_path) {
- extkey.Derive(extkey, entry);
- }
- if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
- if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
- *key = extkey.Neuter().pubkey;
+ CKey priv_key;
+ if (!GetPrivKey(pos, arg, priv_key)) return false;
+ *key = priv_key.GetPubKey();
} else {
// TODO: optimize by caching
CExtPubKey extkey = m_extkey;
@@ -312,6 +318,18 @@ public:
}
return true;
}
+ bool GetPrivKey(int pos, const SigningProvider& arg, CKey& key) const override
+ {
+ CExtKey extkey;
+ if (!GetExtKey(arg, extkey)) return false;
+ for (auto entry : m_path) {
+ extkey.Derive(extkey, entry);
+ }
+ if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
+ if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
+ key = extkey.key;
+ return true;
+ }
};
/** Base class for all Descriptor implementations. */
@@ -436,7 +454,7 @@ public:
pubkeys.reserve(entries.size());
for (auto& entry : entries) {
pubkeys.push_back(entry.first);
- out.origins.emplace(entry.first.GetID(), std::move(entry.second));
+ out.origins.emplace(entry.first.GetID(), std::make_pair<CPubKey, KeyOriginInfo>(CPubKey(entry.first), std::move(entry.second)));
}
if (m_script_arg) {
for (const auto& subscript : subscripts) {
@@ -462,6 +480,20 @@ public:
Span<const unsigned char> span = MakeSpan(cache);
return ExpandHelper(pos, DUMMY_SIGNING_PROVIDER, &span, output_scripts, out, nullptr) && span.size() == 0;
}
+
+ void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const final
+ {
+ for (const auto& p : m_pubkey_args) {
+ CKey key;
+ if (!p->GetPrivKey(pos, provider, key)) continue;
+ out.keys.emplace(key.GetPubKey().GetID(), key);
+ }
+ if (m_script_arg) {
+ FlatSigningProvider subprovider;
+ m_script_arg->ExpandPrivate(pos, provider, subprovider);
+ out = Merge(out, subprovider);
+ }
+ }
};
/** Construct a vector with one element, which is moved into it. */
@@ -514,7 +546,7 @@ protected:
{
CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]);
- return Singleton(GetScriptForDestination(id));
+ return Singleton(GetScriptForDestination(PKHash(id)));
}
public:
PKHDescriptor(std::unique_ptr<PubkeyProvider> prov) : DescriptorImpl(Singleton(std::move(prov)), {}, "pkh") {}
@@ -544,12 +576,12 @@ protected:
CKeyID id = keys[0].GetID();
out.pubkeys.emplace(id, keys[0]);
ret.emplace_back(GetScriptForRawPubKey(keys[0])); // P2PK
- ret.emplace_back(GetScriptForDestination(id)); // P2PKH
+ ret.emplace_back(GetScriptForDestination(PKHash(id))); // P2PKH
if (keys[0].IsCompressed()) {
CScript p2wpkh = GetScriptForDestination(WitnessV0KeyHash(id));
out.scripts.emplace(CScriptID(p2wpkh), p2wpkh);
ret.emplace_back(p2wpkh);
- ret.emplace_back(GetScriptForDestination(CScriptID(p2wpkh))); // P2SH-P2WPKH
+ ret.emplace_back(GetScriptForDestination(ScriptHash(p2wpkh))); // P2SH-P2WPKH
}
return ret;
}
@@ -572,7 +604,7 @@ public:
class SHDescriptor final : public DescriptorImpl
{
protected:
- std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(CScriptID(*script))); }
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript* script, FlatSigningProvider&) const override { return Singleton(GetScriptForDestination(ScriptHash(*script))); }
public:
SHDescriptor(std::unique_ptr<DescriptorImpl> desc) : DescriptorImpl({}, std::move(desc), "sh") {}
};
diff --git a/src/script/descriptor.h b/src/script/descriptor.h
index 907a102284..af7ae229ca 100644
--- a/src/script/descriptor.h
+++ b/src/script/descriptor.h
@@ -60,6 +60,14 @@ struct Descriptor {
* out: scripts and public keys necessary for solving the expanded scriptPubKeys will be put here (may be equal to provider).
*/
virtual bool ExpandFromCache(int pos, const std::vector<unsigned char>& cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const = 0;
+
+ /** Expand the private key for a descriptor at a specified position, if possible.
+ *
+ * pos: the position at which to expand the descriptor. If IsRange() is false, this is ignored.
+ * provider: the provider to query for the private keys.
+ * out: any private keys available for the specified pos will be placed here.
+ */
+ virtual void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const = 0;
};
/** Parse a descriptor string. Included private keys are put in out.
diff --git a/src/script/ismine.h b/src/script/ismine.h
deleted file mode 100644
index 601e70f709..0000000000
--- a/src/script/ismine.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 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_SCRIPT_ISMINE_H
-#define BITCOIN_SCRIPT_ISMINE_H
-
-#include <script/standard.h>
-
-#include <stdint.h>
-
-class CKeyStore;
-class CScript;
-
-/** IsMine() return codes */
-enum isminetype
-{
- ISMINE_NO = 0,
- ISMINE_WATCH_ONLY = 1,
- ISMINE_SPENDABLE = 2,
- ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
-};
-/** used for bitflags of isminetype */
-typedef uint8_t isminefilter;
-
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
-
-#endif // BITCOIN_SCRIPT_ISMINE_H
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 982aa241e7..0666a385d1 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -5,7 +5,6 @@
#include <script/script.h>
-#include <tinyformat.h>
#include <util/strencodings.h>
const char* GetOpName(opcodetype opcode)
diff --git a/src/script/script.h b/src/script/script.h
index 1d8ddba2f2..11e8661a5b 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -581,13 +581,4 @@ struct CScriptWitness
std::string ToString() const;
};
-class CReserveScript
-{
-public:
- CScript reserveScript;
- virtual void KeepScript() {}
- CReserveScript() {}
- virtual ~CReserveScript() {}
-};
-
#endif // BITCOIN_SCRIPT_SCRIPT_H
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 94005cf6f3..eaf5363bd7 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -5,7 +5,6 @@
#include <script/sigcache.h>
-#include <memusage.h>
#include <pubkey.h>
#include <random.h>
#include <uint256.h>
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 320956d0c4..36dd68a3d8 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -483,7 +483,13 @@ bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& inf
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
bool FlatSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const { return LookupHelper(pubkeys, keyid, pubkey); }
-bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const { return LookupHelper(origins, keyid, info); }
+bool FlatSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
+{
+ std::pair<CPubKey, KeyOriginInfo> out;
+ bool ret = LookupHelper(origins, keyid, out);
+ if (ret) info = std::move(out.second);
+ return ret;
+}
bool FlatSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const { return LookupHelper(keys, keyid, key); }
FlatSigningProvider Merge(const FlatSigningProvider& a, const FlatSigningProvider& b)
diff --git a/src/script/sign.h b/src/script/sign.h
index 491fb54c45..f746325b90 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -77,7 +77,7 @@ struct FlatSigningProvider final : public SigningProvider
{
std::map<CScriptID, CScript> scripts;
std::map<CKeyID, CPubKey> pubkeys;
- std::map<CKeyID, KeyOriginInfo> origins;
+ std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> origins;
std::map<CKeyID, CKey> keys;
bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 31bfd04b0f..b7d6cd925c 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -8,8 +8,6 @@
#include <crypto/sha256.h>
#include <pubkey.h>
#include <script/script.h>
-#include <util/system.h>
-#include <util/strencodings.h>
typedef std::vector<unsigned char> valtype;
@@ -19,6 +17,10 @@ unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
+ScriptHash::ScriptHash(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
+
+PKHash::PKHash(const CPubKey& pubkey) : uint160(pubkey.GetID()) {}
+
WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
{
CSHA256().Write(in.data(), in.size()).Finalize(begin());
@@ -162,17 +164,17 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
if (!pubKey.IsValid())
return false;
- addressRet = pubKey.GetID();
+ addressRet = PKHash(pubKey);
return true;
}
else if (whichType == TX_PUBKEYHASH)
{
- addressRet = CKeyID(uint160(vSolutions[0]));
+ addressRet = PKHash(uint160(vSolutions[0]));
return true;
}
else if (whichType == TX_SCRIPTHASH)
{
- addressRet = CScriptID(uint160(vSolutions[0]));
+ addressRet = ScriptHash(uint160(vSolutions[0]));
return true;
} else if (whichType == TX_WITNESS_V0_KEYHASH) {
WitnessV0KeyHash hash;
@@ -217,7 +219,7 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
if (!pubKey.IsValid())
continue;
- CTxDestination address = pubKey.GetID();
+ CTxDestination address = PKHash(pubKey);
addressRet.push_back(address);
}
@@ -250,13 +252,13 @@ public:
return false;
}
- bool operator()(const CKeyID &keyID) const {
+ bool operator()(const PKHash &keyID) const {
script->clear();
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
return true;
}
- bool operator()(const CScriptID &scriptID) const {
+ bool operator()(const ScriptHash &scriptID) const {
script->clear();
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
return true;
diff --git a/src/script/standard.h b/src/script/standard.h
index fc20fb6a08..e45e2d92cc 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -73,6 +73,22 @@ public:
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};
+struct PKHash : public uint160
+{
+ PKHash() : uint160() {}
+ explicit PKHash(const uint160& hash) : uint160(hash) {}
+ explicit PKHash(const CPubKey& pubkey);
+ using uint160::uint160;
+};
+
+struct ScriptHash : public uint160
+{
+ ScriptHash() : uint160() {}
+ explicit ScriptHash(const uint160& hash) : uint160(hash) {}
+ explicit ScriptHash(const CScript& script);
+ using uint160::uint160;
+};
+
struct WitnessV0ScriptHash : public uint256
{
WitnessV0ScriptHash() : uint256() {}
@@ -113,14 +129,14 @@ struct WitnessUnknown
/**
* A txout script template with a specific destination. It is either:
* * CNoDestination: no destination set
- * * CKeyID: TX_PUBKEYHASH destination (P2PKH)
- * * CScriptID: TX_SCRIPTHASH destination (P2SH)
+ * * PKHash: TX_PUBKEYHASH destination (P2PKH)
+ * * ScriptHash: TX_SCRIPTHASH destination (P2SH)
* * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
* * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
* * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
-typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
+typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
/** Check whether a CTxDestination is a CNoDestination. */
bool IsValidDestination(const CTxDestination& dest);
@@ -153,8 +169,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
* multisig scripts, this populates the addressRet vector with the pubkey IDs
* and nRequiredRet with the n required to spend. For other destinations,
* addressRet is populated with a single value and nRequiredRet is set to 1.
- * Returns true if successful. Currently does not extract address from
- * pay-to-witness scripts.
+ * Returns true if successful.
*
* Note: this function confuses destinations (a subset of CScripts that are
* encodable as an address) with key identifiers (of keys involved in a
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index 87fea161ba..55d325aeef 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -1,5 +1,6 @@
bench_inv
bench_ecdh
+bench_ecmult
bench_sign
bench_verify
bench_schnorr_verify
diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml
index 2439529242..74f658f4d1 100644
--- a/src/secp256k1/.travis.yml
+++ b/src/secp256k1/.travis.yml
@@ -1,5 +1,5 @@
language: c
-sudo: false
+os: linux
addons:
apt:
packages: libgmp-dev
@@ -11,7 +11,7 @@ cache:
- src/java/guava/
env:
global:
- - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
+ - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- SCALAR=32bit RECOVERY=yes
@@ -29,7 +29,7 @@ env:
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
- EXTRAFLAGS=CFLAGS=-O0
- - BUILD=check-java ECDH=yes EXPERIMENTAL=yes
+ - BUILD=check-java JNI=yes ECDH=yes EXPERIMENTAL=yes
matrix:
fast_finish: true
include:
@@ -65,5 +65,4 @@ before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
-os: linux
+ - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index c071fbe275..9e5b7dcce0 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -42,6 +42,8 @@ noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
noinst_HEADERS += src/util.h
+noinst_HEADERS += src/scratch.h
+noinst_HEADERS += src/scratch_impl.h
noinst_HEADERS += src/testrand.h
noinst_HEADERS += src/testrand_impl.h
noinst_HEADERS += src/hash.h
@@ -79,7 +81,7 @@ libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
noinst_PROGRAMS =
if USE_BENCHMARK
-noinst_PROGRAMS += bench_verify bench_sign bench_internal
+noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_sign_SOURCES = src/bench_sign.c
@@ -87,6 +89,9 @@ bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
+bench_ecmult_SOURCES = src/bench_ecmult.c
+bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
+bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
endif
TESTS =
@@ -109,7 +114,7 @@ exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDE
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
-exhaustive_tests_LDADD = $(SECP_LIBS)
+exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
@@ -146,7 +151,6 @@ endif
if USE_ECMULT_STATIC_PRECOMPUTATION
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
-CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
gen_context_OBJECTS = gen_context.o
gen_context_BIN = gen_context$(BUILD_EXEEXT)
@@ -154,11 +158,12 @@ gen_%.o: src/gen_%.c
$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
$(gen_context_BIN): $(gen_context_OBJECTS)
- $(CC_FOR_BUILD) $^ -o $@
+ $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
$(tests_OBJECTS): src/ecmult_static_context.h
$(bench_internal_OBJECTS): src/ecmult_static_context.h
+$(bench_ecmult_OBJECTS): src/ecmult_static_context.h
src/ecmult_static_context.h: $(gen_context_BIN)
./$(gen_context_BIN)
diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
index 1fc3627614..cdc78d87d4 100644
--- a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
+++ b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4
@@ -1,5 +1,5 @@
# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
+# https://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
# ===========================================================================
#
# SYNOPSIS
@@ -44,7 +44,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 10
+#serial 14
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
@@ -66,9 +66,17 @@ else
fi
case "$host_os" in
- darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
- _JINC="$_JTOPDIR/Headers";;
- *) _JINC="$_JTOPDIR/include";;
+ darwin*) # Apple Java headers are inside the Xcode bundle.
+ macos_version=$(sw_vers -productVersion | sed -n -e 's/^@<:@0-9@:>@*.\(@<:@0-9@:>@*\).@<:@0-9@:>@*/\1/p')
+ if @<:@ "$macos_version" -gt "7" @:>@; then
+ _JTOPDIR="$(xcrun --show-sdk-path)/System/Library/Frameworks/JavaVM.framework"
+ _JINC="$_JTOPDIR/Headers"
+ else
+ _JTOPDIR="/System/Library/Frameworks/JavaVM.framework"
+ _JINC="$_JTOPDIR/Headers"
+ fi
+ ;;
+ *) _JINC="$_JTOPDIR/include";;
esac
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
_AS_ECHO_LOG([_JINC=$_JINC])
@@ -76,30 +84,27 @@ _AS_ECHO_LOG([_JINC=$_JINC])
# On Mac OS X 10.6.4, jni.h is a symlink:
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
# -> ../../CurrentJDK/Headers/jni.h.
-
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
[
-if test -f "$_JINC/jni.h"; then
- ac_cv_jni_header_path="$_JINC"
- JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
-else
- _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
- if test -f "$_JTOPDIR/include/jni.h"; then
- ac_cv_jni_header_path="$_JTOPDIR/include"
+ if test -f "$_JINC/jni.h"; then
+ ac_cv_jni_header_path="$_JINC"
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
else
- ac_cv_jni_header_path=none
+ _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
+ if test -f "$_JTOPDIR/include/jni.h"; then
+ ac_cv_jni_header_path="$_JTOPDIR/include"
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
+ else
+ ac_cv_jni_header_path=none
+ fi
fi
-fi
])
-
-
# get the likely subdirectories for system specific java includes
case "$host_os" in
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
-darwin*) _JNI_INC_SUBDIRS="darwin";;
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
+darwin*) _JNI_INC_SUBDIRS="darwin";;
linux*) _JNI_INC_SUBDIRS="linux genunix";;
osf*) _JNI_INC_SUBDIRS="alpha";;
solaris*) _JNI_INC_SUBDIRS="solaris";;
@@ -112,9 +117,9 @@ if test "x$ac_cv_jni_header_path" != "xnone"; then
# add any subdirectories that are present
for JINCSUBDIR in $_JNI_INC_SUBDIRS
do
- if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
- JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
- fi
+ if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
+ JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
+ fi
done
fi
])
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
index b74acb8c13..3b3975cbdd 100644
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
@@ -48,7 +48,6 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
EC_KEY_free(eckey);
ECDSA_SIG *sig_openssl;
sig_openssl = ECDSA_SIG_new();
- (void)sig_openssl->r;
ECDSA_SIG_free(sig_openssl);
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
AC_MSG_RESULT([$has_openssl_ec])
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index e5fcbcb4ed..3b7a328c8a 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -85,9 +85,9 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
])
AC_ARG_ENABLE(benchmark,
- AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
+ AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is yes)]),
[use_benchmark=$enableval],
- [use_benchmark=no])
+ [use_benchmark=yes])
AC_ARG_ENABLE(coverage,
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
@@ -135,9 +135,9 @@ AC_ARG_ENABLE(module_recovery,
[enable_module_recovery=no])
AC_ARG_ENABLE(jni,
- AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
+ AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is no)]),
[use_jni=$enableval],
- [use_jni=auto])
+ [use_jni=no])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
@@ -153,12 +153,6 @@ AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
AC_CHECK_TYPES([__int128])
-AC_MSG_CHECKING([for __builtin_expect])
-AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
- [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
- [ AC_MSG_RESULT([no])
- ])
-
if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
CFLAGS="$CFLAGS -O0 --coverage"
@@ -168,27 +162,54 @@ else
fi
if test x"$use_ecmult_static_precomputation" != x"no"; then
+ # Temporarily switch to an environment for the native compiler
save_cross_compiling=$cross_compiling
cross_compiling=no
- TEMP_CC="$CC"
+ SAVE_CC="$CC"
CC="$CC_FOR_BUILD"
- AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS_FOR_BUILD"
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS_FOR_BUILD"
+ SAVE_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS_FOR_BUILD"
+
+ warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function"
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $warn_CFLAGS_FOR_BUILD"
+ AC_MSG_CHECKING([if native ${CC_FOR_BUILD} supports ${warn_CFLAGS_FOR_BUILD}])
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
+ [ AC_MSG_RESULT([yes]) ],
+ [ AC_MSG_RESULT([no])
+ CFLAGS="$saved_CFLAGS"
+ ])
+
+ AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}])
AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([], [return 0])],
+ [AC_LANG_PROGRAM([], [])],
[working_native_cc=yes],
[working_native_cc=no],[dnl])
- CC="$TEMP_CC"
+
+ CFLAGS_FOR_BUILD="$CFLAGS"
+
+ # Restore the environment
cross_compiling=$save_cross_compiling
+ CC="$SAVE_CC"
+ CFLAGS="$SAVE_CFLAGS"
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
if test x"$working_native_cc" = x"no"; then
+ AC_MSG_RESULT([no])
set_precomp=no
+ m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.])
if test x"$use_ecmult_static_precomputation" = x"yes"; then
- AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
else
- AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
+ AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
fi
else
- AC_MSG_RESULT([ok])
+ AC_MSG_RESULT([yes])
set_precomp=yes
fi
else
@@ -441,17 +462,6 @@ if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi
-AC_MSG_NOTICE([Using static precomputation: $set_precomp])
-AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
-AC_MSG_NOTICE([Using field implementation: $set_field])
-AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
-AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
-AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
-AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
-AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
-AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
-AC_MSG_NOTICE([Using jni: $use_jni])
-
if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
AC_MSG_NOTICE([WARNING: experimental build])
@@ -481,7 +491,7 @@ AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
-AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
+AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
@@ -491,3 +501,24 @@ unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
AC_OUTPUT
+
+echo
+echo "Build Options:"
+echo " with endomorphism = $use_endomorphism"
+echo " with ecmult precomp = $set_precomp"
+echo " with jni = $use_jni"
+echo " with benchmarks = $use_benchmark"
+echo " with coverage = $enable_coverage"
+echo " module ecdh = $enable_module_ecdh"
+echo " module recovery = $enable_module_recovery"
+echo
+echo " asm = $set_asm"
+echo " bignum = $set_bignum"
+echo " field = $set_field"
+echo " scalar = $set_scalar"
+echo
+echo " CC = $CC"
+echo " CFLAGS = $CFLAGS"
+echo " CPPFLAGS = $CPPFLAGS"
+echo " LDFLAGS = $LDFLAGS"
+echo
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 3e9c098d19..43af09c330 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -42,6 +42,19 @@ extern "C" {
*/
typedef struct secp256k1_context_struct secp256k1_context;
+/** Opaque data structure that holds rewriteable "scratch space"
+ *
+ * The purpose of this structure is to replace dynamic memory allocations,
+ * because we target architectures where this may not be available. It is
+ * essentially a resizable (within specified parameters) block of bytes,
+ * which is initially created either by memory allocation or TODO as a pointer
+ * into some fixed rewritable space.
+ *
+ * Unlike the context object, this cannot safely be shared between threads
+ * without additional synchronization logic.
+ */
+typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
+
/** Opaque data structure that holds a parsed and valid public key.
*
* The exact representation of data inside is implementation defined and not
@@ -166,6 +179,13 @@ typedef int (*secp256k1_nonce_function)(
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
+/** A simple secp256k1 context object with no precomputed tables. These are useful for
+ * type serialization/parsing functions which require a context object to maintain
+ * API consistency, but currently do not require expensive precomputations or dynamic
+ * allocations.
+ */
+SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
+
/** Create a secp256k1 context object.
*
* Returns: a newly created context object.
@@ -243,6 +263,26 @@ SECP256K1_API void secp256k1_context_set_error_callback(
const void* data
) SECP256K1_ARG_NONNULL(1);
+/** Create a secp256k1 scratch space object.
+ *
+ * Returns: a newly created scratch space.
+ * Args: ctx: an existing context object (cannot be NULL)
+ * In: max_size: maximum amount of memory to allocate
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
+ const secp256k1_context* ctx,
+ size_t max_size
+) SECP256K1_ARG_NONNULL(1);
+
+/** Destroy a secp256k1 scratch space.
+ *
+ * The pointer may not be used afterwards.
+ * Args: scratch: space to destroy
+ */
+SECP256K1_API void secp256k1_scratch_space_destroy(
+ secp256k1_scratch_space* scratch
+);
+
/** Parse a variable-length public key into the pubkey object.
*
* Returns: 1 if the public key was fully valid.
@@ -498,7 +538,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
*
* Returns: 1 always
* Args: ctx: pointer to a context object
- * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
+ * In/Out: seckey: pointer to the 32-byte private key to be negated (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
const secp256k1_context* ctx,
@@ -575,7 +615,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization to protect against side-channel leakage.
- * Returns: 1: randomization successfully updated
+ * Returns: 1: randomization successfully updated or nothing to randomize
* 0: error
* Args: ctx: pointer to a context object (cannot be NULL)
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
@@ -590,6 +630,11 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
* that it does not affect function results, but shields against attacks which
* rely on any input-dependent behaviour.
*
+ * This function has currently an effect only on contexts initialized for signing
+ * because randomization is currently used only for signing. However, this is not
+ * guaranteed and may change in the future. It is safe to call this function on
+ * contexts not initialized for signing; then it will have no effect and return 1.
+ *
* You should call this after secp256k1_context_create or
* secp256k1_context_clone, and may call this repeatedly afterwards.
*/
diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h
index 88492dc1a4..df5fde235c 100644
--- a/src/secp256k1/include/secp256k1_ecdh.h
+++ b/src/secp256k1/include/secp256k1_ecdh.h
@@ -7,21 +7,45 @@
extern "C" {
#endif
+/** A pointer to a function that applies hash function to a point
+ *
+ * Returns: 1 if a point was successfully hashed. 0 will cause ecdh to fail
+ * Out: output: pointer to an array to be filled by the function
+ * In: x: pointer to a 32-byte x coordinate
+ * y: pointer to a 32-byte y coordinate
+ * data: Arbitrary data pointer that is passed through
+ */
+typedef int (*secp256k1_ecdh_hash_function)(
+ unsigned char *output,
+ const unsigned char *x,
+ const unsigned char *y,
+ void *data
+);
+
+/** An implementation of SHA256 hash function that applies to compressed public key. */
+SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
+
+/** A default ecdh hash function (currently equal to secp256k1_ecdh_hash_function_sha256). */
+SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
+
/** Compute an EC Diffie-Hellman secret in constant time
* Returns: 1: exponentiation was successful
* 0: scalar was invalid (zero or overflow)
* Args: ctx: pointer to a context object (cannot be NULL)
- * Out: result: a 32-byte array which will be populated by an ECDH
- * secret computed from the point and scalar
+ * Out: output: pointer to an array to be filled by the function
* In: pubkey: a pointer to a secp256k1_pubkey containing an
* initialized public key
* privkey: a 32-byte scalar with which to multiply the point
+ * hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used
+ * data: Arbitrary data pointer that is passed through
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
const secp256k1_context* ctx,
- unsigned char *result,
+ unsigned char *output,
const secp256k1_pubkey *pubkey,
- const unsigned char *privkey
+ const unsigned char *privkey,
+ secp256k1_ecdh_hash_function hashfp,
+ void *data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in
index a0d006f113..694e98eef5 100644
--- a/src/secp256k1/libsecp256k1.pc.in
+++ b/src/secp256k1/libsecp256k1.pc.in
@@ -8,6 +8,6 @@ Description: Optimized C library for EC operations on curve secp256k1
URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
-Libs.private: @SECP_LIBS@
Libs: -L${libdir} -lsecp256k1
+Libs.private: @SECP_LIBS@
diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h
index d5ebe01301..5b59783f68 100644
--- a/src/secp256k1/src/bench.h
+++ b/src/secp256k1/src/bench.h
@@ -8,6 +8,7 @@
#define SECP256K1_BENCH_H
#include <stdio.h>
+#include <string.h>
#include <math.h>
#include "sys/time.h"
@@ -63,4 +64,19 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
printf("us\n");
}
+int have_flag(int argc, char** argv, char *flag) {
+ char** argm = argv + argc;
+ argv++;
+ if (argv == argm) {
+ return 1;
+ }
+ while (argv != NULL && argv != argm) {
+ if (strcmp(*argv, flag) == 0) {
+ return 1;
+ }
+ argv++;
+ }
+ return 0;
+}
+
#endif /* SECP256K1_BENCH_H */
diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c
index cde5e2dbb4..c1dd5a6ac9 100644
--- a/src/secp256k1/src/bench_ecdh.c
+++ b/src/secp256k1/src/bench_ecdh.c
@@ -15,11 +15,11 @@ typedef struct {
secp256k1_context *ctx;
secp256k1_pubkey point;
unsigned char scalar[32];
-} bench_ecdh_t;
+} bench_ecdh_data;
static void bench_ecdh_setup(void* arg) {
int i;
- bench_ecdh_t *data = (bench_ecdh_t*)arg;
+ bench_ecdh_data *data = (bench_ecdh_data*)arg;
const unsigned char point[] = {
0x03,
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
@@ -39,15 +39,15 @@ static void bench_ecdh_setup(void* arg) {
static void bench_ecdh(void* arg) {
int i;
unsigned char res[32];
- bench_ecdh_t *data = (bench_ecdh_t*)arg;
+ bench_ecdh_data *data = (bench_ecdh_data*)arg;
for (i = 0; i < 20000; i++) {
- CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
+ CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
}
}
int main(void) {
- bench_ecdh_t data;
+ bench_ecdh_data data;
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);
return 0;
diff --git a/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c
new file mode 100644
index 0000000000..6d0ed1f436
--- /dev/null
+++ b/src/secp256k1/src/bench_ecmult.c
@@ -0,0 +1,207 @@
+/**********************************************************************
+ * Copyright (c) 2017 Pieter Wuille *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+#include <stdio.h>
+
+#include "include/secp256k1.h"
+
+#include "util.h"
+#include "hash_impl.h"
+#include "num_impl.h"
+#include "field_impl.h"
+#include "group_impl.h"
+#include "scalar_impl.h"
+#include "ecmult_impl.h"
+#include "bench.h"
+#include "secp256k1.c"
+
+#define POINTS 32768
+#define ITERS 10000
+
+typedef struct {
+ /* Setup once in advance */
+ secp256k1_context* ctx;
+ secp256k1_scratch_space* scratch;
+ secp256k1_scalar* scalars;
+ secp256k1_ge* pubkeys;
+ secp256k1_scalar* seckeys;
+ secp256k1_gej* expected_output;
+ secp256k1_ecmult_multi_func ecmult_multi;
+
+ /* Changes per test */
+ size_t count;
+ int includes_g;
+
+ /* Changes per test iteration */
+ size_t offset1;
+ size_t offset2;
+
+ /* Test output. */
+ secp256k1_gej* output;
+} bench_data;
+
+static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) {
+ bench_data* data = (bench_data*)arg;
+ if (data->includes_g) ++idx;
+ if (idx == 0) {
+ *sc = data->scalars[data->offset1];
+ *ge = secp256k1_ge_const_g;
+ } else {
+ *sc = data->scalars[(data->offset1 + idx) % POINTS];
+ *ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS];
+ }
+ return 1;
+}
+
+static void bench_ecmult(void* arg) {
+ bench_data* data = (bench_data*)arg;
+
+ size_t count = data->count;
+ int includes_g = data->includes_g;
+ size_t iters = 1 + ITERS / count;
+ size_t iter;
+
+ for (iter = 0; iter < iters; ++iter) {
+ data->ecmult_multi(&data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
+ data->offset1 = (data->offset1 + count) % POINTS;
+ data->offset2 = (data->offset2 + count - 1) % POINTS;
+ }
+}
+
+static void bench_ecmult_setup(void* arg) {
+ bench_data* data = (bench_data*)arg;
+ data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
+ data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
+}
+
+static void bench_ecmult_teardown(void* arg) {
+ bench_data* data = (bench_data*)arg;
+ size_t iters = 1 + ITERS / data->count;
+ size_t iter;
+ /* Verify the results in teardown, to avoid doing comparisons while benchmarking. */
+ for (iter = 0; iter < iters; ++iter) {
+ secp256k1_gej tmp;
+ secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL);
+ CHECK(secp256k1_gej_is_infinity(&tmp));
+ }
+}
+
+static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
+ secp256k1_sha256 sha256;
+ unsigned char c[11] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
+ unsigned char buf[32];
+ int overflow = 0;
+ c[6] = num;
+ c[7] = num >> 8;
+ c[8] = num >> 16;
+ c[9] = num >> 24;
+ secp256k1_sha256_initialize(&sha256);
+ secp256k1_sha256_write(&sha256, c, sizeof(c));
+ secp256k1_sha256_finalize(&sha256, buf);
+ secp256k1_scalar_set_b32(scalar, buf, &overflow);
+ CHECK(!overflow);
+}
+
+static void run_test(bench_data* data, size_t count, int includes_g) {
+ char str[32];
+ static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
+ size_t iters = 1 + ITERS / count;
+ size_t iter;
+
+ data->count = count;
+ data->includes_g = includes_g;
+
+ /* Compute (the negation of) the expected results directly. */
+ data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
+ data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
+ for (iter = 0; iter < iters; ++iter) {
+ secp256k1_scalar tmp;
+ secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS];
+ size_t i = 0;
+ for (i = 0; i + 1 < count; ++i) {
+ secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]);
+ secp256k1_scalar_add(&total, &total, &tmp);
+ }
+ secp256k1_scalar_negate(&total, &total);
+ secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->expected_output[iter], NULL, &zero, &total);
+ }
+
+ /* Run the benchmark. */
+ sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count);
+ run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * (1 + ITERS / count));
+}
+
+int main(int argc, char **argv) {
+ bench_data data;
+ int i, p;
+ secp256k1_gej* pubkeys_gej;
+ size_t scratch_size;
+
+ data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
+ scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
+ data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
+ data.ecmult_multi = secp256k1_ecmult_multi_var;
+
+ if (argc > 1) {
+ if(have_flag(argc, argv, "pippenger_wnaf")) {
+ printf("Using pippenger_wnaf:\n");
+ data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
+ } else if(have_flag(argc, argv, "strauss_wnaf")) {
+ printf("Using strauss_wnaf:\n");
+ data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
+ } else if(have_flag(argc, argv, "simple")) {
+ printf("Using simple algorithm:\n");
+ data.ecmult_multi = secp256k1_ecmult_multi_var;
+ secp256k1_scratch_space_destroy(data.scratch);
+ data.scratch = NULL;
+ } else {
+ fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
+ fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
+ return 1;
+ }
+ }
+
+ /* Allocate stuff */
+ data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
+ data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
+ data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
+ data.expected_output = malloc(sizeof(secp256k1_gej) * (ITERS + 1));
+ data.output = malloc(sizeof(secp256k1_gej) * (ITERS + 1));
+
+ /* Generate a set of scalars, and private/public keypairs. */
+ pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
+ secp256k1_gej_set_ge(&pubkeys_gej[0], &secp256k1_ge_const_g);
+ secp256k1_scalar_set_int(&data.seckeys[0], 1);
+ for (i = 0; i < POINTS; ++i) {
+ generate_scalar(i, &data.scalars[i]);
+ if (i) {
+ secp256k1_gej_double_var(&pubkeys_gej[i], &pubkeys_gej[i - 1], NULL);
+ secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
+ }
+ }
+ secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS);
+ free(pubkeys_gej);
+
+ for (i = 1; i <= 8; ++i) {
+ run_test(&data, i, 1);
+ }
+
+ for (p = 0; p <= 11; ++p) {
+ for (i = 9; i <= 16; ++i) {
+ run_test(&data, i << p, 1);
+ }
+ }
+ secp256k1_context_destroy(data.ctx);
+ if (data.scratch != NULL) {
+ secp256k1_scratch_space_destroy(data.scratch);
+ }
+ free(data.scalars);
+ free(data.pubkeys);
+ free(data.seckeys);
+ free(data.output);
+ free(data.expected_output);
+
+ return(0);
+}
diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c
index 0809f77bda..9071724331 100644
--- a/src/secp256k1/src/bench_internal.c
+++ b/src/secp256k1/src/bench_internal.c
@@ -25,10 +25,10 @@ typedef struct {
secp256k1_gej gej_x, gej_y;
unsigned char data[64];
int wnaf[256];
-} bench_inv_t;
+} bench_inv;
void bench_setup(void* arg) {
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
static const unsigned char init_x[32] = {
0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
@@ -58,7 +58,7 @@ void bench_setup(void* arg) {
void bench_scalar_add(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 2000000; i++) {
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
@@ -67,7 +67,7 @@ void bench_scalar_add(void* arg) {
void bench_scalar_negate(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 2000000; i++) {
secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
@@ -76,7 +76,7 @@ void bench_scalar_negate(void* arg) {
void bench_scalar_sqr(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
@@ -85,7 +85,7 @@ void bench_scalar_sqr(void* arg) {
void bench_scalar_mul(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
@@ -95,7 +95,7 @@ void bench_scalar_mul(void* arg) {
#ifdef USE_ENDOMORPHISM
void bench_scalar_split(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_scalar l, r;
@@ -107,7 +107,7 @@ void bench_scalar_split(void* arg) {
void bench_scalar_inverse(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 2000; i++) {
secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
@@ -117,7 +117,7 @@ void bench_scalar_inverse(void* arg) {
void bench_scalar_inverse_var(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 2000; i++) {
secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
@@ -127,7 +127,7 @@ void bench_scalar_inverse_var(void* arg) {
void bench_field_normalize(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 2000000; i++) {
secp256k1_fe_normalize(&data->fe_x);
@@ -136,7 +136,7 @@ void bench_field_normalize(void* arg) {
void bench_field_normalize_weak(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 2000000; i++) {
secp256k1_fe_normalize_weak(&data->fe_x);
@@ -145,7 +145,7 @@ void bench_field_normalize_weak(void* arg) {
void bench_field_mul(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
@@ -154,7 +154,7 @@ void bench_field_mul(void* arg) {
void bench_field_sqr(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
@@ -163,7 +163,7 @@ void bench_field_sqr(void* arg) {
void bench_field_inverse(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_fe_inv(&data->fe_x, &data->fe_x);
@@ -173,7 +173,7 @@ void bench_field_inverse(void* arg) {
void bench_field_inverse_var(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
@@ -183,17 +183,19 @@ void bench_field_inverse_var(void* arg) {
void bench_field_sqrt(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
+ secp256k1_fe t;
for (i = 0; i < 20000; i++) {
- secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
+ t = data->fe_x;
+ secp256k1_fe_sqrt(&data->fe_x, &t);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
void bench_group_double_var(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
@@ -202,7 +204,7 @@ void bench_group_double_var(void* arg) {
void bench_group_add_var(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
@@ -211,7 +213,7 @@ void bench_group_add_var(void* arg) {
void bench_group_add_affine(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
@@ -220,7 +222,7 @@ void bench_group_add_affine(void* arg) {
void bench_group_add_affine_var(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 200000; i++) {
secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
@@ -229,7 +231,7 @@ void bench_group_add_affine_var(void* arg) {
void bench_group_jacobi_var(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_gej_has_quad_y_var(&data->gej_x);
@@ -238,7 +240,7 @@ void bench_group_jacobi_var(void* arg) {
void bench_ecmult_wnaf(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
@@ -248,10 +250,10 @@ void bench_ecmult_wnaf(void* arg) {
void bench_wnaf_const(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
- secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A);
+ secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}
@@ -259,8 +261,8 @@ void bench_wnaf_const(void* arg) {
void bench_sha256(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
- secp256k1_sha256_t sha;
+ bench_inv *data = (bench_inv*)arg;
+ secp256k1_sha256 sha;
for (i = 0; i < 20000; i++) {
secp256k1_sha256_initialize(&sha);
@@ -271,8 +273,8 @@ void bench_sha256(void* arg) {
void bench_hmac_sha256(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
- secp256k1_hmac_sha256_t hmac;
+ bench_inv *data = (bench_inv*)arg;
+ secp256k1_hmac_sha256 hmac;
for (i = 0; i < 20000; i++) {
secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
@@ -283,8 +285,8 @@ void bench_hmac_sha256(void* arg) {
void bench_rfc6979_hmac_sha256(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
- secp256k1_rfc6979_hmac_sha256_t rng;
+ bench_inv *data = (bench_inv*)arg;
+ secp256k1_rfc6979_hmac_sha256 rng;
for (i = 0; i < 20000; i++) {
secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
@@ -311,7 +313,7 @@ void bench_context_sign(void* arg) {
#ifndef USE_NUM_NONE
void bench_num_jacobi(void* arg) {
int i;
- bench_inv_t *data = (bench_inv_t*)arg;
+ bench_inv *data = (bench_inv*)arg;
secp256k1_num nx, norder;
secp256k1_scalar_get_num(&nx, &data->scalar_x);
@@ -324,23 +326,8 @@ void bench_num_jacobi(void* arg) {
}
#endif
-int have_flag(int argc, char** argv, char *flag) {
- char** argm = argv + argc;
- argv++;
- if (argv == argm) {
- return 1;
- }
- while (argv != NULL && argv != argm) {
- if (strcmp(*argv, flag) == 0) {
- return 1;
- }
- argv++;
- }
- return 0;
-}
-
int main(int argc, char **argv) {
- bench_inv_t data;
+ bench_inv data;
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);
diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c
index 6489378cc6..b806eed94e 100644
--- a/src/secp256k1/src/bench_recover.c
+++ b/src/secp256k1/src/bench_recover.c
@@ -13,11 +13,11 @@ typedef struct {
secp256k1_context *ctx;
unsigned char msg[32];
unsigned char sig[64];
-} bench_recover_t;
+} bench_recover_data;
void bench_recover(void* arg) {
int i;
- bench_recover_t *data = (bench_recover_t*)arg;
+ bench_recover_data *data = (bench_recover_data*)arg;
secp256k1_pubkey pubkey;
unsigned char pubkeyc[33];
@@ -38,7 +38,7 @@ void bench_recover(void* arg) {
void bench_recover_setup(void* arg) {
int i;
- bench_recover_t *data = (bench_recover_t*)arg;
+ bench_recover_data *data = (bench_recover_data*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = 1 + i;
@@ -49,7 +49,7 @@ void bench_recover_setup(void* arg) {
}
int main(void) {
- bench_recover_t data;
+ bench_recover_data data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c
index ed7224d757..544b43963c 100644
--- a/src/secp256k1/src/bench_sign.c
+++ b/src/secp256k1/src/bench_sign.c
@@ -12,11 +12,11 @@ typedef struct {
secp256k1_context* ctx;
unsigned char msg[32];
unsigned char key[32];
-} bench_sign_t;
+} bench_sign;
static void bench_sign_setup(void* arg) {
int i;
- bench_sign_t *data = (bench_sign_t*)arg;
+ bench_sign *data = (bench_sign*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = i + 1;
@@ -26,9 +26,9 @@ static void bench_sign_setup(void* arg) {
}
}
-static void bench_sign(void* arg) {
+static void bench_sign_run(void* arg) {
int i;
- bench_sign_t *data = (bench_sign_t*)arg;
+ bench_sign *data = (bench_sign*)arg;
unsigned char sig[74];
for (i = 0; i < 20000; i++) {
@@ -45,11 +45,11 @@ static void bench_sign(void* arg) {
}
int main(void) {
- bench_sign_t data;
+ bench_sign data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
- run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
+ run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000);
secp256k1_context_destroy(data.ctx);
return 0;
diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h
index 1ab9a68ec0..7c5b789325 100644
--- a/src/secp256k1/src/eckey_impl.h
+++ b/src/secp256k1/src/eckey_impl.h
@@ -18,7 +18,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
secp256k1_fe x;
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
- } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
+ } else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
secp256k1_fe x, y;
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
return 0;
diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h
index 6d44aba60b..3d75a960f4 100644
--- a/src/secp256k1/src/ecmult.h
+++ b/src/secp256k1/src/ecmult.h
@@ -1,5 +1,5 @@
/**********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
+ * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
@@ -9,6 +9,8 @@
#include "num.h"
#include "group.h"
+#include "scalar.h"
+#include "scratch.h"
typedef struct {
/* For accelerating the computation of a*P + b*G: */
@@ -28,4 +30,19 @@ static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx
/** Double multiply: R = na*A + ng*G */
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
+typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
+
+/**
+ * Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai.
+ * Chooses the right algorithm for a given number of points and scratch space
+ * size. Resets and overwrites the given scratch space. If the points do not
+ * fit in the scratch space the algorithm is repeatedly run with batches of
+ * points. If no scratch space is given then a simple algorithm is used that
+ * simply multiplies the points with the corresponding scalars and adds them up.
+ * Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
+ * 0 if there is not enough scratch space for a single point or
+ * callback returns 0
+ */
+static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
+
#endif /* SECP256K1_ECMULT_H */
diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h
index 72bf7d7582..d4804b8b68 100644
--- a/src/secp256k1/src/ecmult_const.h
+++ b/src/secp256k1/src/ecmult_const.h
@@ -10,6 +10,8 @@
#include "scalar.h"
#include "group.h"
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
+/* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
+ * one because we internally sometimes add 2 to the number during the WNAF conversion. */
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
#endif /* SECP256K1_ECMULT_CONST_H */
diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h
index 7d7a172b7b..8411752eb0 100644
--- a/src/secp256k1/src/ecmult_const_impl.h
+++ b/src/secp256k1/src/ecmult_const_impl.h
@@ -12,13 +12,6 @@
#include "ecmult_const.h"
#include "ecmult_impl.h"
-#ifdef USE_ENDOMORPHISM
- #define WNAF_BITS 128
-#else
- #define WNAF_BITS 256
-#endif
-#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w))
-
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
int m; \
@@ -55,7 +48,7 @@
*
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
*/
-static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
+static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) {
int global_sign;
int skew = 0;
int word = 0;
@@ -74,9 +67,14 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
* and we'd lose any performance benefit. Instead, we use a technique from
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
- * this, and having the caller compensate after doing the multiplication. */
-
- /* Negative numbers will be negated to keep their bit representation below the maximum width */
+ * this, and having the caller compensate after doing the multiplication.
+ *
+ * In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
+ * particular, to ensure that the outputs from the endomorphism-split fit into
+ * 128 bits). If we negate, the parity of our number flips, inverting which of
+ * {1, 2} we want to add to the scalar when ensuring that it's odd. Further
+ * complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
+ * we need to special-case it in this logic. */
flip = secp256k1_scalar_is_high(&s);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ !secp256k1_scalar_is_even(&s);
@@ -95,7 +93,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
/* 4 */
u_last = secp256k1_scalar_shr_int(&s, w);
- while (word * w < WNAF_BITS) {
+ while (word * w < size) {
int sign;
int even;
@@ -115,37 +113,44 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
wnaf[word] = u * global_sign;
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
- VERIFY_CHECK(word == WNAF_SIZE(w));
+ VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
return skew;
}
-
-static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
+static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge tmpa;
secp256k1_fe Z;
int skew_1;
- int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
#ifdef USE_ENDOMORPHISM
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
int skew_lam;
secp256k1_scalar q_1, q_lam;
#endif
+ int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
int i;
secp256k1_scalar sc = *scalar;
/* build wnaf representation for q. */
+ int rsize = size;
+#ifdef USE_ENDOMORPHISM
+ if (size > 128) {
+ rsize = 128;
+ /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
+ secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
+ skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128);
+ skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128);
+ } else
+#endif
+ {
+ skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size);
#ifdef USE_ENDOMORPHISM
- /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
- secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
- skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1);
- skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
-#else
- skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
+ skew_lam = 0;
#endif
+ }
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
@@ -159,26 +164,30 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_fe_normalize_weak(&pre_a[i].y);
}
#ifdef USE_ENDOMORPHISM
- for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
+ if (size > 128) {
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
+ }
}
#endif
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
- i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)];
+ i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
#ifdef USE_ENDOMORPHISM
- i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)];
- VERIFY_CHECK(i != 0);
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
- secp256k1_gej_add_ge(r, r, &tmpa);
+ if (size > 128) {
+ i = wnaf_lam[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
+ VERIFY_CHECK(i != 0);
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+ }
#endif
/* remaining loop iterations */
- for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) {
+ for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
@@ -190,10 +199,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
#ifdef USE_ENDOMORPHISM
- n = wnaf_lam[i];
- ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
- VERIFY_CHECK(n != 0);
- secp256k1_gej_add_ge(r, r, &tmpa);
+ if (size > 128) {
+ n = wnaf_lam[i];
+ ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
+ VERIFY_CHECK(n != 0);
+ secp256k1_gej_add_ge(r, r, &tmpa);
+ }
#endif
}
@@ -213,14 +224,18 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_ge_set_gej(&correction, &tmpj);
secp256k1_ge_to_storage(&correction_1_stor, a);
#ifdef USE_ENDOMORPHISM
- secp256k1_ge_to_storage(&correction_lam_stor, a);
+ if (size > 128) {
+ secp256k1_ge_to_storage(&correction_lam_stor, a);
+ }
#endif
secp256k1_ge_to_storage(&a2_stor, &correction);
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
#ifdef USE_ENDOMORPHISM
- secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
+ if (size > 128) {
+ secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
+ }
#endif
/* Apply the correction */
@@ -229,10 +244,12 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_gej_add_ge(r, r, &correction);
#ifdef USE_ENDOMORPHISM
- secp256k1_ge_from_storage(&correction, &correction_lam_stor);
- secp256k1_ge_neg(&correction, &correction);
- secp256k1_ge_mul_lambda(&correction, &correction);
- secp256k1_gej_add_ge(r, r, &correction);
+ if (size > 128) {
+ secp256k1_ge_from_storage(&correction, &correction_lam_stor);
+ secp256k1_ge_neg(&correction, &correction);
+ secp256k1_ge_mul_lambda(&correction, &correction);
+ secp256k1_gej_add_ge(r, r, &correction);
+ }
#endif
}
}
diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h
index 9615b932dd..d64505dc00 100644
--- a/src/secp256k1/src/ecmult_gen_impl.h
+++ b/src/secp256k1/src/ecmult_gen_impl.h
@@ -77,7 +77,7 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
}
}
- secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);
+ secp256k1_ge_set_all_gej_var(prec, precj, 1024);
}
for (j = 0; j < 64; j++) {
for (i = 0; i < 16; i++) {
@@ -161,7 +161,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_gej gb;
secp256k1_fe s;
unsigned char nonce32[32];
- secp256k1_rfc6979_hmac_sha256_t rng;
+ secp256k1_rfc6979_hmac_sha256 rng;
int retry;
unsigned char keydata[64] = {0};
if (seed32 == NULL) {
diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h
index 93d3794cb4..1986914a4f 100644
--- a/src/secp256k1/src/ecmult_impl.h
+++ b/src/secp256k1/src/ecmult_impl.h
@@ -1,13 +1,14 @@
-/**********************************************************************
- * Copyright (c) 2013, 2014 Pieter Wuille *
- * Distributed under the MIT software license, see the accompanying *
- * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
- **********************************************************************/
+/*****************************************************************************
+ * Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php. *
+ *****************************************************************************/
#ifndef SECP256K1_ECMULT_IMPL_H
#define SECP256K1_ECMULT_IMPL_H
#include <string.h>
+#include <stdint.h>
#include "group.h"
#include "scalar.h"
@@ -41,9 +42,36 @@
#endif
#endif
+#ifdef USE_ENDOMORPHISM
+ #define WNAF_BITS 128
+#else
+ #define WNAF_BITS 256
+#endif
+#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w))
+#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w)
+
/** The number of entries a table with precomputed multiples needs to have. */
#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2))
+/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
+#define PIPPENGER_SCRATCH_OBJECTS 6
+#define STRAUSS_SCRATCH_OBJECTS 6
+
+#define PIPPENGER_MAX_BUCKET_WINDOW 12
+
+/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */
+#ifdef USE_ENDOMORPHISM
+ #define ECMULT_PIPPENGER_THRESHOLD 88
+#else
+ #define ECMULT_PIPPENGER_THRESHOLD 160
+#endif
+
+#ifdef USE_ENDOMORPHISM
+ #define ECMULT_MAX_POINTS_PER_BATCH 5000000
+#else
+ #define ECMULT_MAX_POINTS_PER_BATCH 10000000
+#endif
+
/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
* the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
* contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
@@ -109,24 +137,135 @@ static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *p
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
}
-static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) {
- secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n);
- secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n);
- secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n);
+static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp256k1_ge_storage *pre, const secp256k1_gej *a) {
+ secp256k1_gej d;
+ secp256k1_ge d_ge, p_ge;
+ secp256k1_gej pj;
+ secp256k1_fe zi;
+ secp256k1_fe zr;
+ secp256k1_fe dx_over_dz_squared;
int i;
- /* Compute the odd multiples in Jacobian form. */
- secp256k1_ecmult_odd_multiples_table(n, prej, zr, a);
- /* Convert them in batch to affine coordinates. */
- secp256k1_ge_set_table_gej_var(prea, prej, zr, n);
- /* Convert them to compact storage form. */
- for (i = 0; i < n; i++) {
- secp256k1_ge_to_storage(&pre[i], &prea[i]);
+ VERIFY_CHECK(!a->infinity);
+
+ secp256k1_gej_double_var(&d, a, NULL);
+
+ /* First, we perform all the additions in an isomorphic curve obtained by multiplying
+ * all `z` coordinates by 1/`d.z`. In these coordinates `d` is affine so we can use
+ * `secp256k1_gej_add_ge_var` to perform the additions. For each addition, we store
+ * the resulting y-coordinate and the z-ratio, since we only have enough memory to
+ * store two field elements. These are sufficient to efficiently undo the isomorphism
+ * and recompute all the `x`s.
+ */
+ d_ge.x = d.x;
+ d_ge.y = d.y;
+ d_ge.infinity = 0;
+
+ secp256k1_ge_set_gej_zinv(&p_ge, a, &d.z);
+ pj.x = p_ge.x;
+ pj.y = p_ge.y;
+ pj.z = a->z;
+ pj.infinity = 0;
+
+ for (i = 0; i < (n - 1); i++) {
+ secp256k1_fe_normalize_var(&pj.y);
+ secp256k1_fe_to_storage(&pre[i].y, &pj.y);
+ secp256k1_gej_add_ge_var(&pj, &pj, &d_ge, &zr);
+ secp256k1_fe_normalize_var(&zr);
+ secp256k1_fe_to_storage(&pre[i].x, &zr);
}
- free(prea);
- free(prej);
- free(zr);
+ /* Invert d.z in the same batch, preserving pj.z so we can extract 1/d.z */
+ secp256k1_fe_mul(&zi, &pj.z, &d.z);
+ secp256k1_fe_inv_var(&zi, &zi);
+
+ /* Directly set `pre[n - 1]` to `pj`, saving the inverted z-coordinate so
+ * that we can combine it with the saved z-ratios to compute the other zs
+ * without any more inversions. */
+ secp256k1_ge_set_gej_zinv(&p_ge, &pj, &zi);
+ secp256k1_ge_to_storage(&pre[n - 1], &p_ge);
+
+ /* Compute the actual x-coordinate of D, which will be needed below. */
+ secp256k1_fe_mul(&d.z, &zi, &pj.z); /* d.z = 1/d.z */
+ secp256k1_fe_sqr(&dx_over_dz_squared, &d.z);
+ secp256k1_fe_mul(&dx_over_dz_squared, &dx_over_dz_squared, &d.x);
+
+ /* Going into the second loop, we have set `pre[n-1]` to its final affine
+ * form, but still need to set `pre[i]` for `i` in 0 through `n-2`. We
+ * have `zi = (p.z * d.z)^-1`, where
+ *
+ * `p.z` is the z-coordinate of the point on the isomorphic curve
+ * which was ultimately assigned to `pre[n-1]`.
+ * `d.z` is the multiplier that must be applied to all z-coordinates
+ * to move from our isomorphic curve back to secp256k1; so the
+ * product `p.z * d.z` is the z-coordinate of the secp256k1
+ * point assigned to `pre[n-1]`.
+ *
+ * All subsequent inverse-z-coordinates can be obtained by multiplying this
+ * factor by successive z-ratios, which is much more efficient than directly
+ * computing each one.
+ *
+ * Importantly, these inverse-zs will be coordinates of points on secp256k1,
+ * while our other stored values come from computations on the isomorphic
+ * curve. So in the below loop, we will take care not to actually use `zi`
+ * or any derived values until we're back on secp256k1.
+ */
+ i = n - 1;
+ while (i > 0) {
+ secp256k1_fe zi2, zi3;
+ const secp256k1_fe *rzr;
+ i--;
+
+ secp256k1_ge_from_storage(&p_ge, &pre[i]);
+
+ /* For each remaining point, we extract the z-ratio from the stored
+ * x-coordinate, compute its z^-1 from that, and compute the full
+ * point from that. */
+ rzr = &p_ge.x;
+ secp256k1_fe_mul(&zi, &zi, rzr);
+ secp256k1_fe_sqr(&zi2, &zi);
+ secp256k1_fe_mul(&zi3, &zi2, &zi);
+ /* To compute the actual x-coordinate, we use the stored z ratio and
+ * y-coordinate, which we obtained from `secp256k1_gej_add_ge_var`
+ * in the loop above, as well as the inverse of the square of its
+ * z-coordinate. We store the latter in the `zi2` variable, which is
+ * computed iteratively starting from the overall Z inverse then
+ * multiplying by each z-ratio in turn.
+ *
+ * Denoting the z-ratio as `rzr`, we observe that it is equal to `h`
+ * from the inside of the above `gej_add_ge_var` call. This satisfies
+ *
+ * rzr = d_x * z^2 - x * d_z^2
+ *
+ * where (`d_x`, `d_z`) are Jacobian coordinates of `D` and `(x, z)`
+ * are Jacobian coordinates of our desired point -- except both are on
+ * the isomorphic curve that we were using when we called `gej_add_ge_var`.
+ * To get back to secp256k1, we must multiply both `z`s by `d_z`, or
+ * equivalently divide both `x`s by `d_z^2`. Our equation then becomes
+ *
+ * rzr = d_x * z^2 / d_z^2 - x
+ *
+ * (The left-hand-side, being a ratio of z-coordinates, is unaffected
+ * by the isomorphism.)
+ *
+ * Rearranging to solve for `x`, we have
+ *
+ * x = d_x * z^2 / d_z^2 - rzr
+ *
+ * But what we actually want is the affine coordinate `X = x/z^2`,
+ * which will satisfy
+ *
+ * X = d_x / d_z^2 - rzr / z^2
+ * = dx_over_dz_squared - rzr * zi2
+ */
+ secp256k1_fe_mul(&p_ge.x, rzr, &zi2);
+ secp256k1_fe_negate(&p_ge.x, &p_ge.x, 1);
+ secp256k1_fe_add(&p_ge.x, &dx_over_dz_squared);
+ /* y is stored_y/z^3, as we expect */
+ secp256k1_fe_mul(&p_ge.y, &p_ge.y, &zi3);
+ /* Store */
+ secp256k1_ge_to_storage(&pre[i], &p_ge);
+ }
}
/** The following two macro retrieves a particular odd multiple from a table
@@ -138,7 +277,8 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge
if ((n) > 0) { \
*(r) = (pre)[((n)-1)/2]; \
} else { \
- secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \
+ *(r) = (pre)[(-(n)-1)/2]; \
+ secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
} \
} while(0)
@@ -150,7 +290,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge
secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
} else { \
secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
- secp256k1_ge_neg((r), (r)); \
+ secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
} \
} while(0)
@@ -174,7 +314,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G));
/* precompute the tables with odd multiples */
- secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb);
+ secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj);
#ifdef USE_ENDOMORPHISM
{
@@ -188,7 +328,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const
for (i = 0; i < 128; i++) {
secp256k1_gej_double_var(&g_128j, &g_128j, NULL);
}
- secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb);
+ secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j);
}
#endif
}
@@ -283,50 +423,78 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
return last_set_bit + 1;
}
-static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
- secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
- secp256k1_ge tmpa;
- secp256k1_fe Z;
+struct secp256k1_strauss_point_state {
#ifdef USE_ENDOMORPHISM
- secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_scalar na_1, na_lam;
- /* Splitted G factors. */
- secp256k1_scalar ng_1, ng_128;
int wnaf_na_1[130];
int wnaf_na_lam[130];
int bits_na_1;
int bits_na_lam;
- int wnaf_ng_1[129];
- int bits_ng_1;
- int wnaf_ng_128[129];
- int bits_ng_128;
#else
int wnaf_na[256];
int bits_na;
+#endif
+ size_t input_pos;
+};
+
+struct secp256k1_strauss_state {
+ secp256k1_gej* prej;
+ secp256k1_fe* zr;
+ secp256k1_ge* pre_a;
+#ifdef USE_ENDOMORPHISM
+ secp256k1_ge* pre_a_lam;
+#endif
+ struct secp256k1_strauss_point_state* ps;
+};
+
+static void secp256k1_ecmult_strauss_wnaf(const secp256k1_ecmult_context *ctx, const struct secp256k1_strauss_state *state, secp256k1_gej *r, int num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
+ secp256k1_ge tmpa;
+ secp256k1_fe Z;
+#ifdef USE_ENDOMORPHISM
+ /* Splitted G factors. */
+ secp256k1_scalar ng_1, ng_128;
+ int wnaf_ng_1[129];
+ int bits_ng_1 = 0;
+ int wnaf_ng_128[129];
+ int bits_ng_128 = 0;
+#else
int wnaf_ng[256];
- int bits_ng;
+ int bits_ng = 0;
#endif
int i;
- int bits;
+ int bits = 0;
+ int np;
+ int no = 0;
+ for (np = 0; np < num; ++np) {
+ if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
+ continue;
+ }
+ state->ps[no].input_pos = np;
#ifdef USE_ENDOMORPHISM
- /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
- secp256k1_scalar_split_lambda(&na_1, &na_lam, na);
-
- /* build wnaf representation for na_1 and na_lam. */
- bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A);
- bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A);
- VERIFY_CHECK(bits_na_1 <= 130);
- VERIFY_CHECK(bits_na_lam <= 130);
- bits = bits_na_1;
- if (bits_na_lam > bits) {
- bits = bits_na_lam;
- }
+ /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
+ secp256k1_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]);
+
+ /* build wnaf representation for na_1 and na_lam. */
+ state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 130, &state->ps[no].na_1, WINDOW_A);
+ state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 130, &state->ps[no].na_lam, WINDOW_A);
+ VERIFY_CHECK(state->ps[no].bits_na_1 <= 130);
+ VERIFY_CHECK(state->ps[no].bits_na_lam <= 130);
+ if (state->ps[no].bits_na_1 > bits) {
+ bits = state->ps[no].bits_na_1;
+ }
+ if (state->ps[no].bits_na_lam > bits) {
+ bits = state->ps[no].bits_na_lam;
+ }
#else
- /* build wnaf representation for na. */
- bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A);
- bits = bits_na;
+ /* build wnaf representation for na. */
+ state->ps[no].bits_na = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na, 256, &na[np], WINDOW_A);
+ if (state->ps[no].bits_na > bits) {
+ bits = state->ps[no].bits_na;
+ }
#endif
+ ++no;
+ }
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
@@ -338,29 +506,51 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
* isomorphism to efficiently add with a known Z inverse.
*/
- secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a);
+ if (no > 0) {
+ /* Compute the odd multiples in Jacobian form. */
+ secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]);
+ for (np = 1; np < no; ++np) {
+ secp256k1_gej tmp = a[state->ps[np].input_pos];
+#ifdef VERIFY
+ secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
+#endif
+ secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
+ secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp);
+ secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z));
+ }
+ /* Bring them to the same Z denominator. */
+ secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr);
+ } else {
+ secp256k1_fe_set_int(&Z, 1);
+ }
#ifdef USE_ENDOMORPHISM
- for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
- secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
+ for (np = 0; np < no; ++np) {
+ for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
+ secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]);
+ }
}
- /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
- secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
+ if (ng) {
+ /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
+ secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
- /* Build wnaf representation for ng_1 and ng_128 */
- bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
- bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);
- if (bits_ng_1 > bits) {
- bits = bits_ng_1;
- }
- if (bits_ng_128 > bits) {
- bits = bits_ng_128;
+ /* Build wnaf representation for ng_1 and ng_128 */
+ bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
+ bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);
+ if (bits_ng_1 > bits) {
+ bits = bits_ng_1;
+ }
+ if (bits_ng_128 > bits) {
+ bits = bits_ng_128;
+ }
}
#else
- bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
- if (bits_ng > bits) {
- bits = bits_ng;
+ if (ng) {
+ bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G);
+ if (bits_ng > bits) {
+ bits = bits_ng;
+ }
}
#endif
@@ -370,13 +560,15 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
int n;
secp256k1_gej_double_var(r, r, NULL);
#ifdef USE_ENDOMORPHISM
- if (i < bits_na_1 && (n = wnaf_na_1[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
- secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
- }
- if (i < bits_na_lam && (n = wnaf_na_lam[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
- secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
+ for (np = 0; np < no; ++np) {
+ if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
+ ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
+ secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
+ }
+ if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
+ ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
+ secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
+ }
}
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
@@ -387,9 +579,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
}
#else
- if (i < bits_na && (n = wnaf_na[i])) {
- ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
- secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
+ for (np = 0; np < no; ++np) {
+ if (i < state->ps[np].bits_na && (n = state->ps[np].wnaf_na[i])) {
+ ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
+ secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
+ }
}
if (i < bits_ng && (n = wnaf_ng[i])) {
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G);
@@ -403,4 +597,585 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej
}
}
+static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
+ secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
+ secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
+ struct secp256k1_strauss_point_state ps[1];
+#ifdef USE_ENDOMORPHISM
+ secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
+#endif
+ struct secp256k1_strauss_state state;
+
+ state.prej = prej;
+ state.zr = zr;
+ state.pre_a = pre_a;
+#ifdef USE_ENDOMORPHISM
+ state.pre_a_lam = pre_a_lam;
+#endif
+ state.ps = ps;
+ secp256k1_ecmult_strauss_wnaf(ctx, &state, r, 1, a, na, ng);
+}
+
+static size_t secp256k1_strauss_scratch_size(size_t n_points) {
+#ifdef USE_ENDOMORPHISM
+ static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
+#else
+ static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
+#endif
+ return n_points*point_size;
+}
+
+static int secp256k1_ecmult_strauss_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
+ secp256k1_gej* points;
+ secp256k1_scalar* scalars;
+ struct secp256k1_strauss_state state;
+ size_t i;
+
+ secp256k1_gej_set_infinity(r);
+ if (inp_g_sc == NULL && n_points == 0) {
+ return 1;
+ }
+
+ if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) {
+ return 0;
+ }
+ points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_gej));
+ scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_scalar));
+ state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
+ state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
+#ifdef USE_ENDOMORPHISM
+ state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
+ state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A);
+#else
+ state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
+#endif
+ state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
+
+ for (i = 0; i < n_points; i++) {
+ secp256k1_ge point;
+ if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) {
+ secp256k1_scratch_deallocate_frame(scratch);
+ return 0;
+ }
+ secp256k1_gej_set_ge(&points[i], &point);
+ }
+ secp256k1_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc);
+ secp256k1_scratch_deallocate_frame(scratch);
+ return 1;
+}
+
+/* Wrapper for secp256k1_ecmult_multi_func interface */
+static int secp256k1_ecmult_strauss_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
+ return secp256k1_ecmult_strauss_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
+}
+
+static size_t secp256k1_strauss_max_points(secp256k1_scratch *scratch) {
+ return secp256k1_scratch_max_allocation(scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1);
+}
+
+/** Convert a number to WNAF notation.
+ * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
+ * It has the following guarantees:
+ * - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w)
+ * - the number of words set is always WNAF_SIZE(w)
+ * - the returned skew is 0 or 1
+ */
+static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) {
+ int skew = 0;
+ int pos;
+ int max_pos;
+ int last_w;
+ const secp256k1_scalar *work = s;
+
+ if (secp256k1_scalar_is_zero(s)) {
+ for (pos = 0; pos < WNAF_SIZE(w); pos++) {
+ wnaf[pos] = 0;
+ }
+ return 0;
+ }
+
+ if (secp256k1_scalar_is_even(s)) {
+ skew = 1;
+ }
+
+ wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew;
+ /* Compute last window size. Relevant when window size doesn't divide the
+ * number of bits in the scalar */
+ last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w;
+
+ /* Store the position of the first nonzero word in max_pos to allow
+ * skipping leading zeros when calculating the wnaf. */
+ for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) {
+ int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w);
+ if(val != 0) {
+ break;
+ }
+ wnaf[pos] = 0;
+ }
+ max_pos = pos;
+ pos = 1;
+
+ while (pos <= max_pos) {
+ int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w);
+ if ((val & 1) == 0) {
+ wnaf[pos - 1] -= (1 << w);
+ wnaf[pos] = (val + 1);
+ } else {
+ wnaf[pos] = val;
+ }
+ /* Set a coefficient to zero if it is 1 or -1 and the proceeding digit
+ * is strictly negative or strictly positive respectively. Only change
+ * coefficients at previous positions because above code assumes that
+ * wnaf[pos - 1] is odd.
+ */
+ if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) {
+ if (wnaf[pos - 1] == 1) {
+ wnaf[pos - 2] += 1 << w;
+ } else {
+ wnaf[pos - 2] -= 1 << w;
+ }
+ wnaf[pos - 1] = 0;
+ }
+ ++pos;
+ }
+
+ return skew;
+}
+
+struct secp256k1_pippenger_point_state {
+ int skew_na;
+ size_t input_pos;
+};
+
+struct secp256k1_pippenger_state {
+ int *wnaf_na;
+ struct secp256k1_pippenger_point_state* ps;
+};
+
+/*
+ * pippenger_wnaf computes the result of a multi-point multiplication as
+ * follows: The scalars are brought into wnaf with n_wnaf elements each. Then
+ * for every i < n_wnaf, first each point is added to a "bucket" corresponding
+ * to the point's wnaf[i]. Second, the buckets are added together such that
+ * r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ...
+ */
+static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_window, struct secp256k1_pippenger_state *state, secp256k1_gej *r, const secp256k1_scalar *sc, const secp256k1_ge *pt, size_t num) {
+ size_t n_wnaf = WNAF_SIZE(bucket_window+1);
+ size_t np;
+ size_t no = 0;
+ int i;
+ int j;
+
+ for (np = 0; np < num; ++np) {
+ if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) {
+ continue;
+ }
+ state->ps[no].input_pos = np;
+ state->ps[no].skew_na = secp256k1_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1);
+ no++;
+ }
+ secp256k1_gej_set_infinity(r);
+
+ if (no == 0) {
+ return 1;
+ }
+
+ for (i = n_wnaf - 1; i >= 0; i--) {
+ secp256k1_gej running_sum;
+
+ for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) {
+ secp256k1_gej_set_infinity(&buckets[j]);
+ }
+
+ for (np = 0; np < no; ++np) {
+ int n = state->wnaf_na[np*n_wnaf + i];
+ struct secp256k1_pippenger_point_state point_state = state->ps[np];
+ secp256k1_ge tmp;
+ int idx;
+
+ if (i == 0) {
+ /* correct for wnaf skew */
+ int skew = point_state.skew_na;
+ if (skew) {
+ secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]);
+ secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL);
+ }
+ }
+ if (n > 0) {
+ idx = (n - 1)/2;
+ secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL);
+ } else if (n < 0) {
+ idx = -(n + 1)/2;
+ secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]);
+ secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL);
+ }
+ }
+
+ for(j = 0; j < bucket_window; j++) {
+ secp256k1_gej_double_var(r, r, NULL);
+ }
+
+ secp256k1_gej_set_infinity(&running_sum);
+ /* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ...
+ * = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ...
+ * + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...)
+ * using an intermediate running sum:
+ * running_sum = bucket[0] + bucket[1] + bucket[2] + ...
+ *
+ * The doubling is done implicitly by deferring the final window doubling (of 'r').
+ */
+ for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) {
+ secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL);
+ secp256k1_gej_add_var(r, r, &running_sum, NULL);
+ }
+
+ secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL);
+ secp256k1_gej_double_var(r, r, NULL);
+ secp256k1_gej_add_var(r, r, &running_sum, NULL);
+ }
+ return 1;
+}
+
+/**
+ * Returns optimal bucket_window (number of bits of a scalar represented by a
+ * set of buckets) for a given number of points.
+ */
+static int secp256k1_pippenger_bucket_window(size_t n) {
+#ifdef USE_ENDOMORPHISM
+ if (n <= 1) {
+ return 1;
+ } else if (n <= 4) {
+ return 2;
+ } else if (n <= 20) {
+ return 3;
+ } else if (n <= 57) {
+ return 4;
+ } else if (n <= 136) {
+ return 5;
+ } else if (n <= 235) {
+ return 6;
+ } else if (n <= 1260) {
+ return 7;
+ } else if (n <= 4420) {
+ return 9;
+ } else if (n <= 7880) {
+ return 10;
+ } else if (n <= 16050) {
+ return 11;
+ } else {
+ return PIPPENGER_MAX_BUCKET_WINDOW;
+ }
+#else
+ if (n <= 1) {
+ return 1;
+ } else if (n <= 11) {
+ return 2;
+ } else if (n <= 45) {
+ return 3;
+ } else if (n <= 100) {
+ return 4;
+ } else if (n <= 275) {
+ return 5;
+ } else if (n <= 625) {
+ return 6;
+ } else if (n <= 1850) {
+ return 7;
+ } else if (n <= 3400) {
+ return 8;
+ } else if (n <= 9630) {
+ return 9;
+ } else if (n <= 17900) {
+ return 10;
+ } else if (n <= 32800) {
+ return 11;
+ } else {
+ return PIPPENGER_MAX_BUCKET_WINDOW;
+ }
+#endif
+}
+
+/**
+ * Returns the maximum optimal number of points for a bucket_window.
+ */
+static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) {
+ switch(bucket_window) {
+#ifdef USE_ENDOMORPHISM
+ case 1: return 1;
+ case 2: return 4;
+ case 3: return 20;
+ case 4: return 57;
+ case 5: return 136;
+ case 6: return 235;
+ case 7: return 1260;
+ case 8: return 1260;
+ case 9: return 4420;
+ case 10: return 7880;
+ case 11: return 16050;
+ case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX;
+#else
+ case 1: return 1;
+ case 2: return 11;
+ case 3: return 45;
+ case 4: return 100;
+ case 5: return 275;
+ case 6: return 625;
+ case 7: return 1850;
+ case 8: return 3400;
+ case 9: return 9630;
+ case 10: return 17900;
+ case 11: return 32800;
+ case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX;
+#endif
+ }
+ return 0;
+}
+
+
+#ifdef USE_ENDOMORPHISM
+SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) {
+ secp256k1_scalar tmp = *s1;
+ secp256k1_scalar_split_lambda(s1, s2, &tmp);
+ secp256k1_ge_mul_lambda(p2, p1);
+
+ if (secp256k1_scalar_is_high(s1)) {
+ secp256k1_scalar_negate(s1, s1);
+ secp256k1_ge_neg(p1, p1);
+ }
+ if (secp256k1_scalar_is_high(s2)) {
+ secp256k1_scalar_negate(s2, s2);
+ secp256k1_ge_neg(p2, p2);
+ }
+}
+#endif
+
+/**
+ * Returns the scratch size required for a given number of points (excluding
+ * base point G) without considering alignment.
+ */
+static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) {
+#ifdef USE_ENDOMORPHISM
+ size_t entries = 2*n_points + 2;
+#else
+ size_t entries = n_points + 1;
+#endif
+ size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int);
+ return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size;
+}
+
+static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
+ /* Use 2(n+1) with the endomorphism, n+1 without, when calculating batch
+ * sizes. The reason for +1 is that we add the G scalar to the list of
+ * other scalars. */
+#ifdef USE_ENDOMORPHISM
+ size_t entries = 2*n_points + 2;
+#else
+ size_t entries = n_points + 1;
+#endif
+ secp256k1_ge *points;
+ secp256k1_scalar *scalars;
+ secp256k1_gej *buckets;
+ struct secp256k1_pippenger_state *state_space;
+ size_t idx = 0;
+ size_t point_idx = 0;
+ int i, j;
+ int bucket_window;
+
+ (void)ctx;
+ secp256k1_gej_set_infinity(r);
+ if (inp_g_sc == NULL && n_points == 0) {
+ return 1;
+ }
+
+ bucket_window = secp256k1_pippenger_bucket_window(n_points);
+ if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points, bucket_window), PIPPENGER_SCRATCH_OBJECTS)) {
+ return 0;
+ }
+ points = (secp256k1_ge *) secp256k1_scratch_alloc(scratch, entries * sizeof(*points));
+ scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(scratch, entries * sizeof(*scalars));
+ state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(scratch, sizeof(*state_space));
+ state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(scratch, entries * sizeof(*state_space->ps));
+ state_space->wnaf_na = (int *) secp256k1_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
+ buckets = (secp256k1_gej *) secp256k1_scratch_alloc(scratch, sizeof(*buckets) << bucket_window);
+
+ if (inp_g_sc != NULL) {
+ scalars[0] = *inp_g_sc;
+ points[0] = secp256k1_ge_const_g;
+ idx++;
+#ifdef USE_ENDOMORPHISM
+ secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]);
+ idx++;
+#endif
+ }
+
+ while (point_idx < n_points) {
+ if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) {
+ secp256k1_scratch_deallocate_frame(scratch);
+ return 0;
+ }
+ idx++;
+#ifdef USE_ENDOMORPHISM
+ secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]);
+ idx++;
+#endif
+ point_idx++;
+ }
+
+ secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx);
+
+ /* Clear data */
+ for(i = 0; (size_t)i < idx; i++) {
+ secp256k1_scalar_clear(&scalars[i]);
+ state_space->ps[i].skew_na = 0;
+ for(j = 0; j < WNAF_SIZE(bucket_window+1); j++) {
+ state_space->wnaf_na[i * WNAF_SIZE(bucket_window+1) + j] = 0;
+ }
+ }
+ for(i = 0; i < 1<<bucket_window; i++) {
+ secp256k1_gej_clear(&buckets[i]);
+ }
+ secp256k1_scratch_deallocate_frame(scratch);
+ return 1;
+}
+
+/* Wrapper for secp256k1_ecmult_multi_func interface */
+static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
+ return secp256k1_ecmult_pippenger_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
+}
+
+/**
+ * Returns the maximum number of points in addition to G that can be used with
+ * a given scratch space. The function ensures that fewer points may also be
+ * used.
+ */
+static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
+ size_t max_alloc = secp256k1_scratch_max_allocation(scratch, PIPPENGER_SCRATCH_OBJECTS);
+ int bucket_window;
+ size_t res = 0;
+
+ for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) {
+ size_t n_points;
+ size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window);
+ size_t space_for_points;
+ size_t space_overhead;
+ size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int);
+
+#ifdef USE_ENDOMORPHISM
+ entry_size = 2*entry_size;
+#endif
+ space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state);
+ if (space_overhead > max_alloc) {
+ break;
+ }
+ space_for_points = max_alloc - space_overhead;
+
+ n_points = space_for_points/entry_size;
+ n_points = n_points > max_points ? max_points : n_points;
+ if (n_points > res) {
+ res = n_points;
+ }
+ if (n_points < max_points) {
+ /* A larger bucket_window may support even more points. But if we
+ * would choose that then the caller couldn't safely use any number
+ * smaller than what this function returns */
+ break;
+ }
+ }
+ return res;
+}
+
+/* Computes ecmult_multi by simply multiplying and adding each point. Does not
+ * require a scratch space */
+static int secp256k1_ecmult_multi_simple_var(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
+ size_t point_idx;
+ secp256k1_scalar szero;
+ secp256k1_gej tmpj;
+
+ secp256k1_scalar_set_int(&szero, 0);
+ secp256k1_gej_set_infinity(r);
+ secp256k1_gej_set_infinity(&tmpj);
+ /* r = inp_g_sc*G */
+ secp256k1_ecmult(ctx, r, &tmpj, &szero, inp_g_sc);
+ for (point_idx = 0; point_idx < n_points; point_idx++) {
+ secp256k1_ge point;
+ secp256k1_gej pointj;
+ secp256k1_scalar scalar;
+ if (!cb(&scalar, &point, point_idx, cbdata)) {
+ return 0;
+ }
+ /* r += scalar*point */
+ secp256k1_gej_set_ge(&pointj, &point);
+ secp256k1_ecmult(ctx, &tmpj, &pointj, &scalar, NULL);
+ secp256k1_gej_add_var(r, r, &tmpj, NULL);
+ }
+ return 1;
+}
+
+/* Compute the number of batches and the batch size given the maximum batch size and the
+ * total number of points */
+static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) {
+ if (max_n_batch_points == 0) {
+ return 0;
+ }
+ if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) {
+ max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
+ }
+ if (n == 0) {
+ *n_batches = 0;
+ *n_batch_points = 0;
+ return 1;
+ }
+ /* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
+ *n_batches = 1 + (n - 1) / max_n_batch_points;
+ *n_batch_points = 1 + (n - 1) / *n_batches;
+ return 1;
+}
+
+typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
+static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
+ size_t i;
+
+ int (*f)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
+ size_t n_batches;
+ size_t n_batch_points;
+
+ secp256k1_gej_set_infinity(r);
+ if (inp_g_sc == NULL && n == 0) {
+ return 1;
+ } else if (n == 0) {
+ secp256k1_scalar szero;
+ secp256k1_scalar_set_int(&szero, 0);
+ secp256k1_ecmult(ctx, r, r, &szero, inp_g_sc);
+ return 1;
+ }
+ if (scratch == NULL) {
+ return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
+ }
+
+ /* Compute the batch sizes for pippenger given a scratch space. If it's greater than a threshold
+ * use pippenger. Otherwise use strauss */
+ if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(scratch), n)) {
+ return 0;
+ }
+ if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
+ f = secp256k1_ecmult_pippenger_batch;
+ } else {
+ if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(scratch), n)) {
+ return 0;
+ }
+ f = secp256k1_ecmult_strauss_batch;
+ }
+ for(i = 0; i < n_batches; i++) {
+ size_t nbp = n < n_batch_points ? n : n_batch_points;
+ size_t offset = n_batch_points*i;
+ secp256k1_gej tmp;
+ if (!f(ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) {
+ return 0;
+ }
+ secp256k1_gej_add_var(r, r, &tmp, NULL);
+ n -= nbp;
+ }
+ return 1;
+}
+
#endif /* SECP256K1_ECMULT_IMPL_H */
diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h
index 727c5267fb..5ff03c8abc 100644
--- a/src/secp256k1/src/field_10x26.h
+++ b/src/secp256k1/src/field_10x26.h
@@ -10,7 +10,9 @@
#include <stdint.h>
typedef struct {
- /* X = sum(i=0..9, elem[i]*2^26) mod n */
+ /* X = sum(i=0..9, n[i]*2^(i*26)) mod p
+ * where p = 2^256 - 0x1000003D1
+ */
uint32_t n[10];
#ifdef VERIFY
int magnitude;
diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h
index 94f8132fc8..4ae4fdcec8 100644
--- a/src/secp256k1/src/field_10x26_impl.h
+++ b/src/secp256k1/src/field_10x26_impl.h
@@ -8,7 +8,6 @@
#define SECP256K1_FIELD_REPR_IMPL_H
#include "util.h"
-#include "num.h"
#include "field.h"
#ifdef VERIFY
@@ -486,7 +485,8 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
VERIFY_BITS(b[9], 26);
/** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
- * px is a shorthand for sum(a[i]*b[x-i], i=0..x).
+ * for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
+ * for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9)
* Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
*/
@@ -1069,6 +1069,7 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
+ VERIFY_CHECK(a != b);
#endif
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY
diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h
index bccd8feb4d..fc5bfe357e 100644
--- a/src/secp256k1/src/field_5x52.h
+++ b/src/secp256k1/src/field_5x52.h
@@ -10,7 +10,9 @@
#include <stdint.h>
typedef struct {
- /* X = sum(i=0..4, elem[i]*2^52) mod n */
+ /* X = sum(i=0..4, n[i]*2^(i*52)) mod p
+ * where p = 2^256 - 0x1000003D1
+ */
uint64_t n[5];
#ifdef VERIFY
int magnitude;
diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h
index 957c61b014..f4263320d5 100644
--- a/src/secp256k1/src/field_5x52_impl.h
+++ b/src/secp256k1/src/field_5x52_impl.h
@@ -12,7 +12,6 @@
#endif
#include "util.h"
-#include "num.h"
#include "field.h"
#if defined(USE_ASM_X86_64)
@@ -422,6 +421,7 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
+ VERIFY_CHECK(a != b);
#endif
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY
diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h
index 95a0d1791c..bcbfb92ac2 100644
--- a/src/secp256k1/src/field_5x52_int128_impl.h
+++ b/src/secp256k1/src/field_5x52_int128_impl.h
@@ -32,9 +32,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(b[3], 56);
VERIFY_BITS(b[4], 52);
VERIFY_CHECK(r != b);
+ VERIFY_CHECK(a != b);
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
- * px is a shorthand for sum(a[i]*b[x-i], i=0..x).
+ * for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
+ * for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
* Note that [x 0 0 0 0 0] = [x*R].
*/
diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h
index 20428648af..6070caccfe 100644
--- a/src/secp256k1/src/field_impl.h
+++ b/src/secp256k1/src/field_impl.h
@@ -12,6 +12,7 @@
#endif
#include "util.h"
+#include "num.h"
#if defined(USE_FIELD_10X26)
#include "field_10x26_impl.h"
@@ -48,6 +49,8 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
+ VERIFY_CHECK(r != a);
+
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
* 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c
index 1835fd491d..87d296ebf0 100644
--- a/src/secp256k1/src/gen_context.c
+++ b/src/secp256k1/src/gen_context.c
@@ -41,7 +41,7 @@ int main(int argc, char **argv) {
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
- fprintf(fp, "#include \"group.h\"\n");
+ fprintf(fp, "#include \"src/group.h\"\n");
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h
index ea1302deb8..8e122ab429 100644
--- a/src/secp256k1/src/group.h
+++ b/src/secp256k1/src/group.h
@@ -65,12 +65,7 @@ static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
-static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);
-
-/** Set a batch of group elements equal to the inputs given in jacobian
- * coordinates (with known z-ratios). zr must contain the known z-ratios such
- * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
-static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len);
+static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
* the same global z "denominator". zr must contain the known z-ratios such
@@ -79,6 +74,9 @@ static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej
* stored in globalz. */
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
+/** Set a group element (affine) equal to the point at infinity. */
+static void secp256k1_ge_set_infinity(secp256k1_ge *r);
+
/** Set a group element (jacobian) equal to the point at infinity. */
static void secp256k1_gej_set_infinity(secp256k1_gej *r);
diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h
index b31b6c12ef..9b93c39e92 100644
--- a/src/secp256k1/src/group_impl.h
+++ b/src/secp256k1/src/group_impl.h
@@ -38,22 +38,22 @@
*/
#if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 199
-const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
);
-const int CURVE_B = 4;
+static const int CURVE_B = 4;
# elif EXHAUSTIVE_TEST_ORDER == 13
-const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
+static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
);
-const int CURVE_B = 2;
+static const int CURVE_B = 2;
# else
# error No known generator for the specified exhaustive test group order.
# endif
@@ -68,7 +68,7 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
);
-const int CURVE_B = 7;
+static const int CURVE_B = 7;
#endif
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
@@ -126,46 +126,43 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
r->y = a->y;
}
-static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {
- secp256k1_fe *az;
- secp256k1_fe *azi;
+static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
+ secp256k1_fe u;
size_t i;
- size_t count = 0;
- az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);
+ size_t last_i = SIZE_MAX;
+
for (i = 0; i < len; i++) {
if (!a[i].infinity) {
- az[count++] = a[i].z;
+ /* Use destination's x coordinates as scratch space */
+ if (last_i == SIZE_MAX) {
+ r[i].x = a[i].z;
+ } else {
+ secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z);
+ }
+ last_i = i;
}
}
+ if (last_i == SIZE_MAX) {
+ return;
+ }
+ secp256k1_fe_inv_var(&u, &r[last_i].x);
- azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
- secp256k1_fe_inv_all_var(azi, az, count);
- free(az);
-
- count = 0;
- for (i = 0; i < len; i++) {
- r[i].infinity = a[i].infinity;
+ i = last_i;
+ while (i > 0) {
+ i--;
if (!a[i].infinity) {
- secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
+ secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u);
+ secp256k1_fe_mul(&u, &u, &a[last_i].z);
+ last_i = i;
}
}
- free(azi);
-}
-
-static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {
- size_t i = len - 1;
- secp256k1_fe zi;
+ VERIFY_CHECK(!a[last_i].infinity);
+ r[last_i].x = u;
- if (len > 0) {
- /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */
- secp256k1_fe_inv(&zi, &a[i].z);
- secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
-
- /* Work out way backwards, using the z-ratios to scale the x/y values. */
- while (i > 0) {
- secp256k1_fe_mul(&zi, &zi, &zr[i]);
- i--;
- secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
+ for (i = 0; i < len; i++) {
+ r[i].infinity = a[i].infinity;
+ if (!a[i].infinity) {
+ secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
}
}
}
@@ -178,6 +175,8 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
/* The z of the final point gives us the "global Z" for the table. */
r[i].x = a[i].x;
r[i].y = a[i].y;
+ /* Ensure all y values are in weak normal form for fast negation of points */
+ secp256k1_fe_normalize_weak(&r[i].y);
*globalz = a[i].z;
r[i].infinity = 0;
zs = zr[i];
@@ -200,6 +199,12 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->z);
}
+static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
+ r->infinity = 1;
+ secp256k1_fe_clear(&r->x);
+ secp256k1_fe_clear(&r->y);
+}
+
static void secp256k1_gej_clear(secp256k1_gej *r) {
r->infinity = 0;
secp256k1_fe_clear(&r->x);
diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h
index e08d25d225..de26e4b89f 100644
--- a/src/secp256k1/src/hash.h
+++ b/src/secp256k1/src/hash.h
@@ -14,28 +14,28 @@ typedef struct {
uint32_t s[8];
uint32_t buf[16]; /* In big endian */
size_t bytes;
-} secp256k1_sha256_t;
+} secp256k1_sha256;
-static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash);
-static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size);
-static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32);
+static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
+static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size);
+static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32);
typedef struct {
- secp256k1_sha256_t inner, outer;
-} secp256k1_hmac_sha256_t;
+ secp256k1_sha256 inner, outer;
+} secp256k1_hmac_sha256;
-static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size);
-static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size);
-static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32);
+static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
+static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
+static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
typedef struct {
unsigned char v[32];
unsigned char k[32];
int retry;
-} secp256k1_rfc6979_hmac_sha256_t;
+} secp256k1_rfc6979_hmac_sha256;
-static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen);
-static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
-static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
+static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
+static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
+static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
#endif /* SECP256K1_HASH_H */
diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h
index 4c9964ee06..009f26beba 100644
--- a/src/secp256k1/src/hash_impl.h
+++ b/src/secp256k1/src/hash_impl.h
@@ -33,7 +33,7 @@
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#endif
-static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
+static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
hash->s[0] = 0x6a09e667ul;
hash->s[1] = 0xbb67ae85ul;
hash->s[2] = 0x3c6ef372ul;
@@ -128,14 +128,15 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
s[7] += h;
}
-static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) {
+static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
size_t bufsize = hash->bytes & 0x3F;
hash->bytes += len;
while (bufsize + len >= 64) {
/* Fill the buffer, and process it. */
- memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);
- data += 64 - bufsize;
- len -= 64 - bufsize;
+ size_t chunk_len = 64 - bufsize;
+ memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
+ data += chunk_len;
+ len -= chunk_len;
secp256k1_sha256_transform(hash->s, hash->buf);
bufsize = 0;
}
@@ -145,7 +146,7 @@ static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char
}
}
-static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) {
+static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint32_t sizedesc[2];
uint32_t out[8];
@@ -161,14 +162,14 @@ static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *o
memcpy(out32, (const unsigned char*)out, 32);
}
-static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) {
- int n;
+static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
+ size_t n;
unsigned char rkey[64];
- if (keylen <= 64) {
+ if (keylen <= sizeof(rkey)) {
memcpy(rkey, key, keylen);
- memset(rkey + keylen, 0, 64 - keylen);
+ memset(rkey + keylen, 0, sizeof(rkey) - keylen);
} else {
- secp256k1_sha256_t sha256;
+ secp256k1_sha256 sha256;
secp256k1_sha256_initialize(&sha256);
secp256k1_sha256_write(&sha256, key, keylen);
secp256k1_sha256_finalize(&sha256, rkey);
@@ -176,24 +177,24 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons
}
secp256k1_sha256_initialize(&hash->outer);
- for (n = 0; n < 64; n++) {
+ for (n = 0; n < sizeof(rkey); n++) {
rkey[n] ^= 0x5c;
}
- secp256k1_sha256_write(&hash->outer, rkey, 64);
+ secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey));
secp256k1_sha256_initialize(&hash->inner);
- for (n = 0; n < 64; n++) {
+ for (n = 0; n < sizeof(rkey); n++) {
rkey[n] ^= 0x5c ^ 0x36;
}
- secp256k1_sha256_write(&hash->inner, rkey, 64);
- memset(rkey, 0, 64);
+ secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
+ memset(rkey, 0, sizeof(rkey));
}
-static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) {
+static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
secp256k1_sha256_write(&hash->inner, data, size);
}
-static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) {
+static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) {
unsigned char temp[32];
secp256k1_sha256_finalize(&hash->inner, temp);
secp256k1_sha256_write(&hash->outer, temp, 32);
@@ -202,8 +203,8 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign
}
-static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) {
- secp256k1_hmac_sha256_t hmac;
+static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
+ secp256k1_hmac_sha256 hmac;
static const unsigned char zero[1] = {0x00};
static const unsigned char one[1] = {0x01};
@@ -232,11 +233,11 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
rng->retry = 0;
}
-static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) {
+static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
/* RFC6979 3.2.h. */
static const unsigned char zero[1] = {0x00};
if (rng->retry) {
- secp256k1_hmac_sha256_t hmac;
+ secp256k1_hmac_sha256 hmac;
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
secp256k1_hmac_sha256_write(&hmac, zero, 1);
@@ -247,7 +248,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
}
while (outlen > 0) {
- secp256k1_hmac_sha256_t hmac;
+ secp256k1_hmac_sha256 hmac;
int now = outlen;
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
@@ -263,7 +264,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
rng->retry = 1;
}
-static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) {
+static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
memset(rng->k, 0, 32);
memset(rng->v, 0, 32);
rng->retry = 0;
diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
index c00d08899b..d766a1029c 100644
--- a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
+++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java
@@ -52,7 +52,7 @@ public class NativeSecp256k1Test {
}
/**
- * This tests secret key verify() for a invalid secretkey
+ * This tests secret key verify() for an invalid secretkey
*/
public static void testSecKeyVerifyNeg() throws AssertFailException{
boolean result = false;
diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
index bcef7b32ce..b50970b4f2 100644
--- a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
+++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
@@ -83,7 +83,7 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
secp256k1_ecdsa_signature sig[72];
- int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
+ int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL);
unsigned char outputSer[72];
size_t outputLen = 72;
@@ -353,7 +353,9 @@ SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1e
ctx,
nonce_res,
&pubkey,
- secdata
+ secdata,
+ NULL,
+ NULL
);
}
diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h
index 01ecba4d53..44cb68e750 100644
--- a/src/secp256k1/src/modules/ecdh/main_impl.h
+++ b/src/secp256k1/src/modules/ecdh/main_impl.h
@@ -10,16 +10,35 @@
#include "include/secp256k1_ecdh.h"
#include "ecmult_const_impl.h"
-int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
+static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
+ unsigned char version = (y[31] & 0x01) | 0x02;
+ secp256k1_sha256 sha;
+ (void)data;
+
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(&sha, &version, 1);
+ secp256k1_sha256_write(&sha, x, 32);
+ secp256k1_sha256_finalize(&sha, output);
+
+ return 1;
+}
+
+const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
+const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
+
+int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
int ret = 0;
int overflow = 0;
secp256k1_gej res;
secp256k1_ge pt;
secp256k1_scalar s;
VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(result != NULL);
+ ARG_CHECK(output != NULL);
ARG_CHECK(point != NULL);
ARG_CHECK(scalar != NULL);
+ if (hashfp == NULL) {
+ hashfp = secp256k1_ecdh_hash_function_default;
+ }
secp256k1_pubkey_load(ctx, &pt, point);
secp256k1_scalar_set_b32(&s, scalar, &overflow);
@@ -27,24 +46,18 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const se
ret = 0;
} else {
unsigned char x[32];
- unsigned char y[1];
- secp256k1_sha256_t sha;
+ unsigned char y[32];
- secp256k1_ecmult_const(&res, &pt, &s);
+ secp256k1_ecmult_const(&res, &pt, &s, 256);
secp256k1_ge_set_gej(&pt, &res);
- /* Compute a hash of the point in compressed form
- * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
- * expect its output to be secret and has a timing sidechannel. */
+
+ /* Compute a hash of the point */
secp256k1_fe_normalize(&pt.x);
secp256k1_fe_normalize(&pt.y);
secp256k1_fe_get_b32(x, &pt.x);
- y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
+ secp256k1_fe_get_b32(y, &pt.y);
- secp256k1_sha256_initialize(&sha);
- secp256k1_sha256_write(&sha, y, sizeof(y));
- secp256k1_sha256_write(&sha, x, sizeof(x));
- secp256k1_sha256_finalize(&sha, result);
- ret = 1;
+ ret = hashfp(output, x, y, data);
}
secp256k1_scalar_clear(&s);
diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h
index cec30b67c6..fe26e8fb69 100644
--- a/src/secp256k1/src/modules/ecdh/tests_impl.h
+++ b/src/secp256k1/src/modules/ecdh/tests_impl.h
@@ -7,6 +7,23 @@
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
#define SECP256K1_MODULE_ECDH_TESTS_H
+int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
+ (void)output;
+ (void)x;
+ (void)y;
+ (void)data;
+ return 0;
+}
+
+int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
+ (void)data;
+ /* Save x and y as uncompressed public key */
+ output[0] = 0x04;
+ memcpy(output + 1, x, 32);
+ memcpy(output + 33, y, 32);
+ return 1;
+}
+
void test_ecdh_api(void) {
/* Setup context that just counts errors */
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
@@ -21,15 +38,15 @@ void test_ecdh_api(void) {
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
/* Check all NULLs are detected */
- CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
+ CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
CHECK(ecount == 0);
- CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
+ CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
CHECK(ecount == 1);
- CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
+ CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
CHECK(ecount == 2);
- CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
+ CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
CHECK(ecount == 3);
- CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
+ CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
CHECK(ecount == 3);
/* Cleanup */
@@ -44,29 +61,36 @@ void test_ecdh_generator_basepoint(void) {
s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */
for (i = 0; i < 100; ++i) {
- secp256k1_sha256_t sha;
+ secp256k1_sha256 sha;
unsigned char s_b32[32];
- unsigned char output_ecdh[32];
+ unsigned char output_ecdh[65];
unsigned char output_ser[32];
- unsigned char point_ser[33];
+ unsigned char point_ser[65];
size_t point_ser_len = sizeof(point_ser);
secp256k1_scalar s;
random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s);
- /* compute using ECDH function */
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
- CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);
- /* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
+
+ /* compute using ECDH function with custom hash function */
+ CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
+ /* compute "explicitly" */
+ CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
+ /* compare */
+ CHECK(memcmp(output_ecdh, point_ser, 65) == 0);
+
+ /* compute using ECDH function with default hash function */
+ CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
+ /* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
- CHECK(point_ser_len == sizeof(point_ser));
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
secp256k1_sha256_finalize(&sha, output_ser);
/* compare */
- CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
+ CHECK(memcmp(output_ecdh, output_ser, 32) == 0);
}
}
@@ -89,11 +113,14 @@ void test_bad_scalar(void) {
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
/* Try to multiply it by bad values */
- CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
- CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0);
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0);
/* ...and a good one */
s_overflow[31] -= 1;
- CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1);
+
+ /* Hash function failure results in ecdh failure */
+ CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
}
void run_ecdh_tests(void) {
diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h
index db1ebf94be..d378335d99 100644
--- a/src/secp256k1/src/scalar_4x64_impl.h
+++ b/src/secp256k1/src/scalar_4x64_impl.h
@@ -376,7 +376,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* extract m6 */
"movq %%r8, %q6\n"
: "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
- : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
+ : "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
/* Reduce 385 bits into 258. */
@@ -455,7 +455,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* extract p4 */
"movq %%r9, %q4\n"
: "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4)
- : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
+ : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc");
/* Reduce 258 bits into 256. */
@@ -501,7 +501,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* Extract c */
"movq %%r9, %q0\n"
: "=g"(c)
- : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
+ : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
#else
uint128_t c;
diff --git a/src/secp256k1/src/scratch.h b/src/secp256k1/src/scratch.h
new file mode 100644
index 0000000000..fef377af0d
--- /dev/null
+++ b/src/secp256k1/src/scratch.h
@@ -0,0 +1,39 @@
+/**********************************************************************
+ * Copyright (c) 2017 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_SCRATCH_
+#define _SECP256K1_SCRATCH_
+
+#define SECP256K1_SCRATCH_MAX_FRAMES 5
+
+/* The typedef is used internally; the struct name is used in the public API
+ * (where it is exposed as a different typedef) */
+typedef struct secp256k1_scratch_space_struct {
+ void *data[SECP256K1_SCRATCH_MAX_FRAMES];
+ size_t offset[SECP256K1_SCRATCH_MAX_FRAMES];
+ size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES];
+ size_t frame;
+ size_t max_size;
+ const secp256k1_callback* error_callback;
+} secp256k1_scratch;
+
+static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
+
+static void secp256k1_scratch_destroy(secp256k1_scratch* scratch);
+
+/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */
+static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects);
+
+/** Deallocates a stack frame */
+static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch);
+
+/** Returns the maximum allocation the scratch space will allow */
+static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects);
+
+/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */
+static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n);
+
+#endif
diff --git a/src/secp256k1/src/scratch_impl.h b/src/secp256k1/src/scratch_impl.h
new file mode 100644
index 0000000000..abed713b21
--- /dev/null
+++ b/src/secp256k1/src/scratch_impl.h
@@ -0,0 +1,86 @@
+/**********************************************************************
+ * Copyright (c) 2017 Andrew Poelstra *
+ * Distributed under the MIT software license, see the accompanying *
+ * file COPYING or http://www.opensource.org/licenses/mit-license.php.*
+ **********************************************************************/
+
+#ifndef _SECP256K1_SCRATCH_IMPL_H_
+#define _SECP256K1_SCRATCH_IMPL_H_
+
+#include "scratch.h"
+
+/* Using 16 bytes alignment because common architectures never have alignment
+ * requirements above 8 for any of the types we care about. In addition we
+ * leave some room because currently we don't care about a few bytes.
+ * TODO: Determine this at configure time. */
+#define ALIGNMENT 16
+
+static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) {
+ secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret));
+ if (ret != NULL) {
+ memset(ret, 0, sizeof(*ret));
+ ret->max_size = max_size;
+ ret->error_callback = error_callback;
+ }
+ return ret;
+}
+
+static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) {
+ if (scratch != NULL) {
+ VERIFY_CHECK(scratch->frame == 0);
+ free(scratch);
+ }
+}
+
+static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) {
+ size_t i = 0;
+ size_t allocated = 0;
+ for (i = 0; i < scratch->frame; i++) {
+ allocated += scratch->frame_size[i];
+ }
+ if (scratch->max_size - allocated <= objects * ALIGNMENT) {
+ return 0;
+ }
+ return scratch->max_size - allocated - objects * ALIGNMENT;
+}
+
+static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) {
+ VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES);
+
+ if (n <= secp256k1_scratch_max_allocation(scratch, objects)) {
+ n += objects * ALIGNMENT;
+ scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n);
+ if (scratch->data[scratch->frame] == NULL) {
+ return 0;
+ }
+ scratch->frame_size[scratch->frame] = n;
+ scratch->offset[scratch->frame] = 0;
+ scratch->frame++;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) {
+ VERIFY_CHECK(scratch->frame > 0);
+ scratch->frame -= 1;
+ free(scratch->data[scratch->frame]);
+}
+
+static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) {
+ void *ret;
+ size_t frame = scratch->frame - 1;
+ size = ((size + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
+
+ if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) {
+ return NULL;
+ }
+ ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]);
+ memset(ret, 0, size);
+ scratch->offset[frame] += size;
+
+ return ret;
+}
+
+#endif
diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c
index 4f8c01655b..15981f46e2 100644
--- a/src/secp256k1/src/secp256k1.c
+++ b/src/secp256k1/src/secp256k1.c
@@ -17,6 +17,7 @@
#include "ecdsa_impl.h"
#include "eckey_impl.h"
#include "hash_impl.h"
+#include "scratch_impl.h"
#define ARG_CHECK(cond) do { \
if (EXPECT(!(cond), 0)) { \
@@ -55,6 +56,14 @@ struct secp256k1_context_struct {
secp256k1_callback error_callback;
};
+static const secp256k1_context secp256k1_context_no_precomp_ = {
+ { 0 },
+ { 0 },
+ { default_illegal_callback_fn, 0 },
+ { default_error_callback_fn, 0 }
+};
+const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_no_precomp_;
+
secp256k1_context* secp256k1_context_create(unsigned int flags) {
secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context));
ret->illegal_callback = default_illegal_callback;
@@ -90,6 +99,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
}
void secp256k1_context_destroy(secp256k1_context* ctx) {
+ CHECK(ctx != secp256k1_context_no_precomp);
if (ctx != NULL) {
secp256k1_ecmult_context_clear(&ctx->ecmult_ctx);
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
@@ -99,6 +109,7 @@ void secp256k1_context_destroy(secp256k1_context* ctx) {
}
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
+ CHECK(ctx != secp256k1_context_no_precomp);
if (fun == NULL) {
fun = default_illegal_callback_fn;
}
@@ -107,6 +118,7 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(
}
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
+ CHECK(ctx != secp256k1_context_no_precomp);
if (fun == NULL) {
fun = default_error_callback_fn;
}
@@ -114,13 +126,22 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
ctx->error_callback.data = data;
}
+secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) {
+ VERIFY_CHECK(ctx != NULL);
+ return secp256k1_scratch_create(&ctx->error_callback, max_size);
+}
+
+void secp256k1_scratch_space_destroy(secp256k1_scratch_space* scratch) {
+ secp256k1_scratch_destroy(scratch);
+}
+
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
if (sizeof(secp256k1_ge_storage) == 64) {
/* When the secp256k1_ge_storage type is exactly 64 byte, use its
* representation inside secp256k1_pubkey, as conversion is very fast.
* Note that secp256k1_pubkey_save must use the same representation. */
secp256k1_ge_storage s;
- memcpy(&s, &pubkey->data[0], 64);
+ memcpy(&s, &pubkey->data[0], sizeof(s));
secp256k1_ge_from_storage(ge, &s);
} else {
/* Otherwise, fall back to 32-byte big endian for X and Y. */
@@ -137,7 +158,7 @@ static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) {
if (sizeof(secp256k1_ge_storage) == 64) {
secp256k1_ge_storage s;
secp256k1_ge_to_storage(&s, ge);
- memcpy(&pubkey->data[0], &s, 64);
+ memcpy(&pubkey->data[0], &s, sizeof(s));
} else {
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
secp256k1_fe_normalize_var(&ge->x);
@@ -307,10 +328,15 @@ int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_s
secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m));
}
+static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *offset, const void *data, unsigned int len) {
+ memcpy(buf + *offset, data, len);
+ *offset += len;
+}
+
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
unsigned char keydata[112];
- int keylen = 64;
- secp256k1_rfc6979_hmac_sha256_t rng;
+ unsigned int offset = 0;
+ secp256k1_rfc6979_hmac_sha256 rng;
unsigned int i;
/* We feed a byte array to the PRNG as input, consisting of:
* - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
@@ -320,17 +346,15 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
* different argument mixtures to emulate each other and result in the same
* nonces.
*/
- memcpy(keydata, key32, 32);
- memcpy(keydata + 32, msg32, 32);
+ buffer_append(keydata, &offset, key32, 32);
+ buffer_append(keydata, &offset, msg32, 32);
if (data != NULL) {
- memcpy(keydata + 64, data, 32);
- keylen = 96;
+ buffer_append(keydata, &offset, data, 32);
}
if (algo16 != NULL) {
- memcpy(keydata + keylen, algo16, 16);
- keylen += 16;
+ buffer_append(keydata, &offset, algo16, 16);
}
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen);
+ secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset);
memset(keydata, 0, sizeof(keydata));
for (i = 0; i <= counter; i++) {
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
@@ -546,8 +570,9 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
VERIFY_CHECK(ctx != NULL);
- ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
- secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
+ if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
+ secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
+ }
return 1;
}
diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h
index 1255574209..30a91e5296 100644
--- a/src/secp256k1/src/testrand_impl.h
+++ b/src/secp256k1/src/testrand_impl.h
@@ -13,7 +13,7 @@
#include "testrand.h"
#include "hash.h"
-static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng;
+static secp256k1_rfc6979_hmac_sha256 secp256k1_test_rng;
static uint32_t secp256k1_test_rng_precomputed[8];
static int secp256k1_test_rng_precomputed_used = 8;
static uint64_t secp256k1_test_rng_integer;
diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c
index 3d9bd5ebb4..f1c4db929a 100644
--- a/src/secp256k1/src/tests.c
+++ b/src/secp256k1/src/tests.c
@@ -23,6 +23,9 @@
#include "openssl/ec.h"
#include "openssl/ecdsa.h"
#include "openssl/obj_mac.h"
+# if OPENSSL_VERSION_NUMBER < 0x10100000L
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {*pr = sig->r; *ps = sig->s;}
+# endif
#endif
#include "contrib/lax_der_parsing.c"
@@ -215,8 +218,12 @@ void run_context_tests(void) {
CHECK(ecount == 3);
CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1);
CHECK(ecount == 3);
- CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0);
- CHECK(ecount == 4);
+ CHECK(secp256k1_context_randomize(vrfy, ctmp) == 1);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_context_randomize(vrfy, NULL) == 1);
+ CHECK(ecount == 3);
+ CHECK(secp256k1_context_randomize(sign, ctmp) == 1);
+ CHECK(ecount2 == 14);
CHECK(secp256k1_context_randomize(sign, NULL) == 1);
CHECK(ecount2 == 14);
secp256k1_context_set_illegal_callback(vrfy, NULL, NULL);
@@ -248,6 +255,44 @@ void run_context_tests(void) {
secp256k1_context_destroy(NULL);
}
+void run_scratch_tests(void) {
+ int32_t ecount = 0;
+ secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
+ secp256k1_scratch_space *scratch;
+
+ /* Test public API */
+ secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
+
+ scratch = secp256k1_scratch_space_create(none, 1000);
+ CHECK(scratch != NULL);
+ CHECK(ecount == 0);
+
+ /* Test internal API */
+ CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000);
+ CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 1000);
+
+ /* Allocating 500 bytes with no frame fails */
+ CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL);
+ CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000);
+
+ /* ...but pushing a new stack frame does affect the max allocation */
+ CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1 == 1));
+ CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 500); /* 500 - ALIGNMENT */
+ CHECK(secp256k1_scratch_alloc(scratch, 500) != NULL);
+ CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL);
+
+ CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1) == 0);
+
+ /* ...and this effect is undone by popping the frame */
+ secp256k1_scratch_deallocate_frame(scratch);
+ CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000);
+ CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL);
+
+ /* cleanup */
+ secp256k1_scratch_space_destroy(scratch);
+ secp256k1_context_destroy(none);
+}
+
/***** HASH TESTS *****/
void run_sha256_tests(void) {
@@ -270,7 +315,7 @@ void run_sha256_tests(void) {
int i;
for (i = 0; i < 8; i++) {
unsigned char out[32];
- secp256k1_sha256_t hasher;
+ secp256k1_sha256 hasher;
secp256k1_sha256_initialize(&hasher);
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
secp256k1_sha256_finalize(&hasher, out);
@@ -313,7 +358,7 @@ void run_hmac_sha256_tests(void) {
};
int i;
for (i = 0; i < 6; i++) {
- secp256k1_hmac_sha256_t hasher;
+ secp256k1_hmac_sha256 hasher;
unsigned char out[32];
secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
@@ -345,7 +390,7 @@ void run_rfc6979_hmac_sha256_tests(void) {
{0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94}
};
- secp256k1_rfc6979_hmac_sha256_t rng;
+ secp256k1_rfc6979_hmac_sha256 rng;
unsigned char out[32];
int i;
@@ -2054,7 +2099,6 @@ void test_ge(void) {
/* Test batch gej -> ge conversion with and without known z ratios. */
{
secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe));
- secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge));
for (i = 0; i < 4 * runs + 1; i++) {
/* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */
@@ -2062,20 +2106,33 @@ void test_ge(void) {
secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z);
}
}
- secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1);
- secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback);
+ secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1);
for (i = 0; i < 4 * runs + 1; i++) {
secp256k1_fe s;
random_fe_non_zero(&s);
secp256k1_gej_rescale(&gej[i], &s);
- ge_equals_gej(&ge_set_table[i], &gej[i]);
ge_equals_gej(&ge_set_all[i], &gej[i]);
}
- free(ge_set_table);
free(ge_set_all);
free(zr);
}
+ /* Test batch gej -> ge conversion with many infinities. */
+ for (i = 0; i < 4 * runs + 1; i++) {
+ random_group_element_test(&ge[i]);
+ /* randomly set half the points to infinitiy */
+ if(secp256k1_fe_is_odd(&ge[i].x)) {
+ secp256k1_ge_set_infinity(&ge[i]);
+ }
+ secp256k1_gej_set_ge(&gej[i], &ge[i]);
+ }
+ /* batch invert */
+ secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1);
+ /* check result */
+ for (i = 0; i < 4 * runs + 1; i++) {
+ ge_equals_gej(&ge[i], &gej[i]);
+ }
+
free(ge);
free(gej);
free(zinv);
@@ -2405,7 +2462,7 @@ void ecmult_const_random_mult(void) {
0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956
);
secp256k1_gej b;
- secp256k1_ecmult_const(&b, &a, &xn);
+ secp256k1_ecmult_const(&b, &a, &xn, 256);
CHECK(secp256k1_ge_is_valid_var(&a));
ge_equals_gej(&expected_b, &b);
@@ -2421,12 +2478,12 @@ void ecmult_const_commutativity(void) {
random_scalar_order_test(&a);
random_scalar_order_test(&b);
- secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a);
- secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b);
+ secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a, 256);
+ secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b, 256);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
- secp256k1_ecmult_const(&res1, &mid1, &b);
- secp256k1_ecmult_const(&res2, &mid2, &a);
+ secp256k1_ecmult_const(&res1, &mid1, &b, 256);
+ secp256k1_ecmult_const(&res2, &mid2, &a, 256);
secp256k1_ge_set_gej(&mid1, &res1);
secp256k1_ge_set_gej(&mid2, &res2);
ge_equals_ge(&mid1, &mid2);
@@ -2442,13 +2499,13 @@ void ecmult_const_mult_zero_one(void) {
secp256k1_scalar_negate(&negone, &one);
random_group_element_test(&point);
- secp256k1_ecmult_const(&res1, &point, &zero);
+ secp256k1_ecmult_const(&res1, &point, &zero, 3);
secp256k1_ge_set_gej(&res2, &res1);
CHECK(secp256k1_ge_is_infinity(&res2));
- secp256k1_ecmult_const(&res1, &point, &one);
+ secp256k1_ecmult_const(&res1, &point, &one, 2);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
- secp256k1_ecmult_const(&res1, &point, &negone);
+ secp256k1_ecmult_const(&res1, &point, &negone, 256);
secp256k1_gej_neg(&res1, &res1);
secp256k1_ge_set_gej(&res2, &res1);
ge_equals_ge(&res2, &point);
@@ -2474,7 +2531,7 @@ void ecmult_const_chain_multiply(void) {
for (i = 0; i < 100; ++i) {
secp256k1_ge tmp;
secp256k1_ge_set_gej(&tmp, &point);
- secp256k1_ecmult_const(&point, &tmp, &scalar);
+ secp256k1_ecmult_const(&point, &tmp, &scalar, 256);
}
secp256k1_ge_set_gej(&res, &point);
ge_equals_gej(&res, &expected_point);
@@ -2487,6 +2544,446 @@ void run_ecmult_const_tests(void) {
ecmult_const_chain_multiply();
}
+typedef struct {
+ secp256k1_scalar *sc;
+ secp256k1_ge *pt;
+} ecmult_multi_data;
+
+static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ecmult_multi_data *data = (ecmult_multi_data*) cbdata;
+ *sc = data->sc[idx];
+ *pt = data->pt[idx];
+ return 1;
+}
+
+static int ecmult_multi_false_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ (void)sc;
+ (void)pt;
+ (void)idx;
+ (void)cbdata;
+ return 0;
+}
+
+void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func ecmult_multi) {
+ int ncount;
+ secp256k1_scalar szero;
+ secp256k1_scalar sc[32];
+ secp256k1_ge pt[32];
+ secp256k1_gej r;
+ secp256k1_gej r2;
+ ecmult_multi_data data;
+ secp256k1_scratch *scratch_empty;
+
+ data.sc = sc;
+ data.pt = pt;
+ secp256k1_scalar_set_int(&szero, 0);
+
+ /* No points to multiply */
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
+
+ /* Check 1- and 2-point multiplies against ecmult */
+ for (ncount = 0; ncount < count; ncount++) {
+ secp256k1_ge ptg;
+ secp256k1_gej ptgj;
+ random_scalar_order(&sc[0]);
+ random_scalar_order(&sc[1]);
+
+ random_group_element_test(&ptg);
+ secp256k1_gej_set_ge(&ptgj, &ptg);
+ pt[0] = ptg;
+ pt[1] = secp256k1_ge_const_g;
+
+ /* only G scalar */
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
+ secp256k1_gej_neg(&r2, &r2);
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+
+ /* 1-point */
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
+ secp256k1_gej_neg(&r2, &r2);
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+
+ /* Try to multiply 1 point, but scratch space is empty */
+ scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
+ CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
+ secp256k1_scratch_destroy(scratch_empty);
+
+ /* Try to multiply 1 point, but callback returns false */
+ CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
+
+ /* 2-point */
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
+ secp256k1_gej_neg(&r2, &r2);
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+
+ /* 2-point with G scalar */
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
+ secp256k1_gej_neg(&r2, &r2);
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ /* Check infinite outputs of various forms */
+ for (ncount = 0; ncount < count; ncount++) {
+ secp256k1_ge ptg;
+ size_t i, j;
+ size_t sizes[] = { 2, 10, 32 };
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 32; i++) {
+ random_scalar_order(&sc[i]);
+ secp256k1_ge_set_infinity(&pt[i]);
+ }
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 32; i++) {
+ random_group_element_test(&ptg);
+ pt[i] = ptg;
+ secp256k1_scalar_set_int(&sc[i], 0);
+ }
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ for (j = 0; j < 3; j++) {
+ random_group_element_test(&ptg);
+ for (i = 0; i < 16; i++) {
+ random_scalar_order(&sc[2*i]);
+ secp256k1_scalar_negate(&sc[2*i + 1], &sc[2*i]);
+ pt[2 * i] = ptg;
+ pt[2 * i + 1] = ptg;
+ }
+
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(secp256k1_gej_is_infinity(&r));
+
+ random_scalar_order(&sc[0]);
+ for (i = 0; i < 16; i++) {
+ random_group_element_test(&ptg);
+
+ sc[2*i] = sc[0];
+ sc[2*i+1] = sc[0];
+ pt[2 * i] = ptg;
+ secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]);
+ }
+
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ random_group_element_test(&ptg);
+ secp256k1_scalar_set_int(&sc[0], 0);
+ pt[0] = ptg;
+ for (i = 1; i < 32; i++) {
+ pt[i] = ptg;
+
+ random_scalar_order(&sc[i]);
+ secp256k1_scalar_add(&sc[0], &sc[0], &sc[i]);
+ secp256k1_scalar_negate(&sc[i], &sc[i]);
+ }
+
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ /* Check random points, constant scalar */
+ for (ncount = 0; ncount < count; ncount++) {
+ size_t i;
+ secp256k1_gej_set_infinity(&r);
+
+ random_scalar_order(&sc[0]);
+ for (i = 0; i < 20; i++) {
+ secp256k1_ge ptg;
+ sc[i] = sc[0];
+ random_group_element_test(&ptg);
+ pt[i] = ptg;
+ secp256k1_gej_add_ge_var(&r, &r, &pt[i], NULL);
+ }
+
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_gej_neg(&r2, &r2);
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ /* Check random scalars, constant point */
+ for (ncount = 0; ncount < count; ncount++) {
+ size_t i;
+ secp256k1_ge ptg;
+ secp256k1_gej p0j;
+ secp256k1_scalar rs;
+ secp256k1_scalar_set_int(&rs, 0);
+
+ random_group_element_test(&ptg);
+ for (i = 0; i < 20; i++) {
+ random_scalar_order(&sc[i]);
+ pt[i] = ptg;
+ secp256k1_scalar_add(&rs, &rs, &sc[i]);
+ }
+
+ secp256k1_gej_set_ge(&p0j, &pt[0]);
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_gej_neg(&r2, &r2);
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+ }
+
+ /* Sanity check that zero scalars don't cause problems */
+ for (ncount = 0; ncount < 20; ncount++) {
+ random_scalar_order(&sc[ncount]);
+ random_group_element_test(&pt[ncount]);
+ }
+
+ secp256k1_scalar_clear(&sc[0]);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
+ secp256k1_scalar_clear(&sc[1]);
+ secp256k1_scalar_clear(&sc[2]);
+ secp256k1_scalar_clear(&sc[3]);
+ secp256k1_scalar_clear(&sc[4]);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
+ CHECK(secp256k1_gej_is_infinity(&r));
+
+ /* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */
+ {
+ const size_t TOP = 8;
+ size_t s0i, s1i;
+ size_t t0i, t1i;
+ secp256k1_ge ptg;
+ secp256k1_gej ptgj;
+
+ random_group_element_test(&ptg);
+ secp256k1_gej_set_ge(&ptgj, &ptg);
+
+ for(t0i = 0; t0i < TOP; t0i++) {
+ for(t1i = 0; t1i < TOP; t1i++) {
+ secp256k1_gej t0p, t1p;
+ secp256k1_scalar t0, t1;
+
+ secp256k1_scalar_set_int(&t0, (t0i + 1) / 2);
+ secp256k1_scalar_cond_negate(&t0, t0i & 1);
+ secp256k1_scalar_set_int(&t1, (t1i + 1) / 2);
+ secp256k1_scalar_cond_negate(&t1, t1i & 1);
+
+ secp256k1_ecmult(&ctx->ecmult_ctx, &t0p, &ptgj, &t0, &szero);
+ secp256k1_ecmult(&ctx->ecmult_ctx, &t1p, &ptgj, &t1, &szero);
+
+ for(s0i = 0; s0i < TOP; s0i++) {
+ for(s1i = 0; s1i < TOP; s1i++) {
+ secp256k1_scalar tmp1, tmp2;
+ secp256k1_gej expected, actual;
+
+ secp256k1_ge_set_gej(&pt[0], &t0p);
+ secp256k1_ge_set_gej(&pt[1], &t1p);
+
+ secp256k1_scalar_set_int(&sc[0], (s0i + 1) / 2);
+ secp256k1_scalar_cond_negate(&sc[0], s0i & 1);
+ secp256k1_scalar_set_int(&sc[1], (s1i + 1) / 2);
+ secp256k1_scalar_cond_negate(&sc[1], s1i & 1);
+
+ secp256k1_scalar_mul(&tmp1, &t0, &sc[0]);
+ secp256k1_scalar_mul(&tmp2, &t1, &sc[1]);
+ secp256k1_scalar_add(&tmp1, &tmp1, &tmp2);
+
+ secp256k1_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero);
+ CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
+ secp256k1_gej_neg(&expected, &expected);
+ secp256k1_gej_add_var(&actual, &actual, &expected, NULL);
+ CHECK(secp256k1_gej_is_infinity(&actual));
+ }
+ }
+ }
+ }
+ }
+}
+
+void test_secp256k1_pippenger_bucket_window_inv(void) {
+ int i;
+
+ CHECK(secp256k1_pippenger_bucket_window_inv(0) == 0);
+ for(i = 1; i <= PIPPENGER_MAX_BUCKET_WINDOW; i++) {
+#ifdef USE_ENDOMORPHISM
+ /* Bucket_window of 8 is not used with endo */
+ if (i == 8) {
+ continue;
+ }
+#endif
+ CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)) == i);
+ if (i != PIPPENGER_MAX_BUCKET_WINDOW) {
+ CHECK(secp256k1_pippenger_bucket_window(secp256k1_pippenger_bucket_window_inv(i)+1) > i);
+ }
+ }
+}
+
+/**
+ * Probabilistically test the function returning the maximum number of possible points
+ * for a given scratch space.
+ */
+void test_ecmult_multi_pippenger_max_points(void) {
+ size_t scratch_size = secp256k1_rand_int(256);
+ size_t max_size = secp256k1_pippenger_scratch_size(secp256k1_pippenger_bucket_window_inv(PIPPENGER_MAX_BUCKET_WINDOW-1)+512, 12);
+ secp256k1_scratch *scratch;
+ size_t n_points_supported;
+ int bucket_window = 0;
+
+ for(; scratch_size < max_size; scratch_size+=256) {
+ scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size);
+ CHECK(scratch != NULL);
+ n_points_supported = secp256k1_pippenger_max_points(scratch);
+ if (n_points_supported == 0) {
+ secp256k1_scratch_destroy(scratch);
+ continue;
+ }
+ bucket_window = secp256k1_pippenger_bucket_window(n_points_supported);
+ CHECK(secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS));
+ secp256k1_scratch_deallocate_frame(scratch);
+ secp256k1_scratch_destroy(scratch);
+ }
+ CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW);
+}
+
+void test_ecmult_multi_batch_size_helper(void) {
+ size_t n_batches, n_batch_points, max_n_batch_points, n;
+
+ max_n_batch_points = 0;
+ n = 1;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0);
+
+ max_n_batch_points = 1;
+ n = 0;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
+ CHECK(n_batches == 0);
+ CHECK(n_batch_points == 0);
+
+ max_n_batch_points = 2;
+ n = 5;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
+ CHECK(n_batches == 3);
+ CHECK(n_batch_points == 2);
+
+ max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
+ n = ECMULT_MAX_POINTS_PER_BATCH;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
+ CHECK(n_batches == 1);
+ CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH);
+
+ max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1;
+ n = ECMULT_MAX_POINTS_PER_BATCH + 1;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
+ CHECK(n_batches == 2);
+ CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1);
+
+ max_n_batch_points = 1;
+ n = SIZE_MAX;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
+ CHECK(n_batches == SIZE_MAX);
+ CHECK(n_batch_points == 1);
+
+ max_n_batch_points = 2;
+ n = SIZE_MAX;
+ CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
+ CHECK(n_batches == SIZE_MAX/2 + 1);
+ CHECK(n_batch_points == 2);
+}
+
+/**
+ * Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to
+ * 1 <= i <= num points.
+ */
+void test_ecmult_multi_batching(void) {
+ static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD;
+ secp256k1_scalar scG;
+ secp256k1_scalar szero;
+ secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_scalar) * n_points);
+ secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * n_points);
+ secp256k1_gej r;
+ secp256k1_gej r2;
+ ecmult_multi_data data;
+ int i;
+ secp256k1_scratch *scratch;
+
+ secp256k1_gej_set_infinity(&r2);
+ secp256k1_scalar_set_int(&szero, 0);
+
+ /* Get random scalars and group elements and compute result */
+ random_scalar_order(&scG);
+ secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r2, &szero, &scG);
+ for(i = 0; i < n_points; i++) {
+ secp256k1_ge ptg;
+ secp256k1_gej ptgj;
+ random_group_element_test(&ptg);
+ secp256k1_gej_set_ge(&ptgj, &ptg);
+ pt[i] = ptg;
+ random_scalar_order(&sc[i]);
+ secp256k1_ecmult(&ctx->ecmult_ctx, &ptgj, &ptgj, &sc[i], NULL);
+ secp256k1_gej_add_var(&r2, &r2, &ptgj, NULL);
+ }
+ data.sc = sc;
+ data.pt = pt;
+
+ /* Test with empty scratch space */
+ scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
+ CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1));
+ secp256k1_scratch_destroy(scratch);
+
+ /* Test with space for 1 point in pippenger. That's not enough because
+ * ecmult_multi selects strauss which requires more memory. */
+ scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
+ CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1));
+ secp256k1_scratch_destroy(scratch);
+
+ secp256k1_gej_neg(&r2, &r2);
+ for(i = 1; i <= n_points; i++) {
+ if (i > ECMULT_PIPPENGER_THRESHOLD) {
+ int bucket_window = secp256k1_pippenger_bucket_window(i);
+ size_t scratch_size = secp256k1_pippenger_scratch_size(i, bucket_window);
+ scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
+ } else {
+ size_t scratch_size = secp256k1_strauss_scratch_size(i);
+ scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
+ }
+ CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
+ secp256k1_gej_add_var(&r, &r, &r2, NULL);
+ CHECK(secp256k1_gej_is_infinity(&r));
+ secp256k1_scratch_destroy(scratch);
+ }
+ free(sc);
+ free(pt);
+}
+
+void run_ecmult_multi_tests(void) {
+ secp256k1_scratch *scratch;
+
+ test_secp256k1_pippenger_bucket_window_inv();
+ test_ecmult_multi_pippenger_max_points();
+ scratch = secp256k1_scratch_create(&ctx->error_callback, 819200);
+ test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
+ test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
+ test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
+ test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
+ secp256k1_scratch_destroy(scratch);
+
+ /* Run test_ecmult_multi with space for exactly one point */
+ scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
+ test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
+ secp256k1_scratch_destroy(scratch);
+
+ test_ecmult_multi_batch_size_helper();
+ test_ecmult_multi_batching();
+}
+
void test_wnaf(const secp256k1_scalar *number, int w) {
secp256k1_scalar x, two, t;
int wnaf[256];
@@ -2541,6 +3038,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
int wnaf[256] = {0};
int i;
int skew;
+ int bits = 256;
secp256k1_scalar num = *number;
secp256k1_scalar_set_int(&x, 0);
@@ -2550,10 +3048,11 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
for (i = 0; i < 16; ++i) {
secp256k1_scalar_shr_int(&num, 8);
}
+ bits = 128;
#endif
- skew = secp256k1_wnaf_const(wnaf, num, w);
+ skew = secp256k1_wnaf_const(wnaf, num, w, bits);
- for (i = WNAF_SIZE(w); i >= 0; --i) {
+ for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) {
secp256k1_scalar t;
int v = wnaf[i];
CHECK(v != 0); /* check nonzero */
@@ -2575,6 +3074,110 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
CHECK(secp256k1_scalar_eq(&x, &num));
}
+void test_fixed_wnaf(const secp256k1_scalar *number, int w) {
+ secp256k1_scalar x, shift;
+ int wnaf[256] = {0};
+ int i;
+ int skew;
+ secp256k1_scalar num = *number;
+
+ secp256k1_scalar_set_int(&x, 0);
+ secp256k1_scalar_set_int(&shift, 1 << w);
+ /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */
+#ifdef USE_ENDOMORPHISM
+ for (i = 0; i < 16; ++i) {
+ secp256k1_scalar_shr_int(&num, 8);
+ }
+#endif
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+
+ for (i = WNAF_SIZE(w)-1; i >= 0; --i) {
+ secp256k1_scalar t;
+ int v = wnaf[i];
+ CHECK(v == 0 || v & 1); /* check parity */
+ CHECK(v > -(1 << w)); /* check range above */
+ CHECK(v < (1 << w)); /* check range below */
+
+ secp256k1_scalar_mul(&x, &x, &shift);
+ if (v >= 0) {
+ secp256k1_scalar_set_int(&t, v);
+ } else {
+ secp256k1_scalar_set_int(&t, -v);
+ secp256k1_scalar_negate(&t, &t);
+ }
+ secp256k1_scalar_add(&x, &x, &t);
+ }
+ /* If skew is 1 then add 1 to num */
+ secp256k1_scalar_cadd_bit(&num, 0, skew == 1);
+ CHECK(secp256k1_scalar_eq(&x, &num));
+}
+
+/* Checks that the first 8 elements of wnaf are equal to wnaf_expected and the
+ * rest is 0.*/
+void test_fixed_wnaf_small_helper(int *wnaf, int *wnaf_expected, int w) {
+ int i;
+ for (i = WNAF_SIZE(w)-1; i >= 8; --i) {
+ CHECK(wnaf[i] == 0);
+ }
+ for (i = 7; i >= 0; --i) {
+ CHECK(wnaf[i] == wnaf_expected[i]);
+ }
+}
+
+void test_fixed_wnaf_small(void) {
+ int w = 4;
+ int wnaf[256] = {0};
+ int i;
+ int skew;
+ secp256k1_scalar num;
+
+ secp256k1_scalar_set_int(&num, 0);
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+ for (i = WNAF_SIZE(w)-1; i >= 0; --i) {
+ int v = wnaf[i];
+ CHECK(v == 0);
+ }
+ CHECK(skew == 0);
+
+ secp256k1_scalar_set_int(&num, 1);
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+ for (i = WNAF_SIZE(w)-1; i >= 1; --i) {
+ int v = wnaf[i];
+ CHECK(v == 0);
+ }
+ CHECK(wnaf[0] == 1);
+ CHECK(skew == 0);
+
+ {
+ int wnaf_expected[8] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf };
+ secp256k1_scalar_set_int(&num, 0xffffffff);
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+ test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
+ CHECK(skew == 0);
+ }
+ {
+ int wnaf_expected[8] = { -1, -1, -1, -1, -1, -1, -1, 0xf };
+ secp256k1_scalar_set_int(&num, 0xeeeeeeee);
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+ test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
+ CHECK(skew == 1);
+ }
+ {
+ int wnaf_expected[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
+ secp256k1_scalar_set_int(&num, 0x01010101);
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+ test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
+ CHECK(skew == 0);
+ }
+ {
+ int wnaf_expected[8] = { -0xf, 0, 0xf, -0xf, 0, 0xf, 1, 0 };
+ secp256k1_scalar_set_int(&num, 0x01ef1ef1);
+ skew = secp256k1_wnaf_fixed(wnaf, &num, w);
+ test_fixed_wnaf_small_helper(wnaf, wnaf_expected, w);
+ CHECK(skew == 0);
+ }
+}
+
void run_wnaf(void) {
int i;
secp256k1_scalar n = {{0}};
@@ -2585,12 +3188,15 @@ void run_wnaf(void) {
test_constant_wnaf(&n, 4);
n.d[0] = 2;
test_constant_wnaf(&n, 4);
+ /* Test 0 */
+ test_fixed_wnaf_small();
/* Random tests */
for (i = 0; i < count; i++) {
random_scalar_order(&n);
test_wnaf(&n, 4+(i%10));
test_constant_wnaf_negate(&n);
test_constant_wnaf(&n, 4 + (i % 10));
+ test_fixed_wnaf(&n, 4 + (i % 10));
}
secp256k1_scalar_set_int(&n, 0);
CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1);
@@ -3055,6 +3661,7 @@ void run_ec_pubkey_parse_test(void) {
ecount = 0;
VG_UNDEF(&pubkey, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1);
+ CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp, &pubkey, pubkeyc, 65) == 1);
VG_CHECK(&pubkey, sizeof(pubkey));
CHECK(ecount == 0);
VG_UNDEF(&ge, sizeof(ge));
@@ -3177,7 +3784,7 @@ void run_eckey_edge_case_test(void) {
VG_CHECK(&pubkey, sizeof(pubkey));
CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
pubkey_negone = pubkey;
- /* Tweak of zero leaves the value changed. */
+ /* Tweak of zero leaves the value unchanged. */
memset(ctmp2, 0, 32);
CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1);
CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40);
@@ -3668,6 +4275,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_
#ifdef ENABLE_OPENSSL_TESTS
ECDSA_SIG *sig_openssl;
+ const BIGNUM *r = NULL, *s = NULL;
const unsigned char *sigptr;
unsigned char roundtrip_openssl[2048];
int len_openssl = 2048;
@@ -3719,15 +4327,16 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_
sigptr = sig;
parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL);
if (parsed_openssl) {
- valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256;
+ ECDSA_SIG_get0(sig_openssl, &r, &s);
+ valid_openssl = !BN_is_negative(r) && !BN_is_negative(s) && BN_num_bits(r) > 0 && BN_num_bits(r) <= 256 && BN_num_bits(s) > 0 && BN_num_bits(s) <= 256;
if (valid_openssl) {
unsigned char tmp[32] = {0};
- BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r));
+ BN_bn2bin(r, tmp + 32 - BN_num_bytes(r));
valid_openssl = memcmp(tmp, max_scalar, 32) < 0;
}
if (valid_openssl) {
unsigned char tmp[32] = {0};
- BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s));
+ BN_bn2bin(s, tmp + 32 - BN_num_bytes(s));
valid_openssl = memcmp(tmp, max_scalar, 32) < 0;
}
}
@@ -4431,8 +5040,9 @@ int main(int argc, char **argv) {
}
} else {
FILE *frand = fopen("/dev/urandom", "r");
- if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) {
+ if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) {
uint64_t t = time(NULL) * (uint64_t)1337;
+ fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n");
seed16[0] ^= t;
seed16[1] ^= t >> 8;
seed16[2] ^= t >> 16;
@@ -4442,7 +5052,9 @@ int main(int argc, char **argv) {
seed16[6] ^= t >> 48;
seed16[7] ^= t >> 56;
}
- fclose(frand);
+ if (frand) {
+ fclose(frand);
+ }
}
secp256k1_rand_seed(seed16);
@@ -4451,6 +5063,7 @@ int main(int argc, char **argv) {
/* initialize */
run_context_tests();
+ run_scratch_tests();
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
if (secp256k1_rand_bits(1)) {
secp256k1_rand256(run32);
@@ -4492,6 +5105,7 @@ int main(int argc, char **argv) {
run_ecmult_constants();
run_ecmult_gen_blind();
run_ecmult_const_tests();
+ run_ecmult_multi_tests();
run_ec_combine();
/* endomorphism tests */
diff --git a/src/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c
index b040bb0733..ab9779b02f 100644
--- a/src/secp256k1/src/tests_exhaustive.c
+++ b/src/secp256k1/src/tests_exhaustive.c
@@ -174,7 +174,7 @@ void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *gr
ge_equals_gej(&group[(i * r_log + j) % order], &tmp);
if (i > 0) {
- secp256k1_ecmult_const(&tmp, &group[i], &ng);
+ secp256k1_ecmult_const(&tmp, &group[i], &ng, 256);
ge_equals_gej(&group[(i * j) % order], &tmp);
}
}
@@ -182,6 +182,46 @@ void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *gr
}
}
+typedef struct {
+ secp256k1_scalar sc[2];
+ secp256k1_ge pt[2];
+} ecmult_multi_data;
+
+static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *cbdata) {
+ ecmult_multi_data *data = (ecmult_multi_data*) cbdata;
+ *sc = data->sc[idx];
+ *pt = data->pt[idx];
+ return 1;
+}
+
+void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group, int order) {
+ int i, j, k, x, y;
+ secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096);
+ for (i = 0; i < order; i++) {
+ for (j = 0; j < order; j++) {
+ for (k = 0; k < order; k++) {
+ for (x = 0; x < order; x++) {
+ for (y = 0; y < order; y++) {
+ secp256k1_gej tmp;
+ secp256k1_scalar g_sc;
+ ecmult_multi_data data;
+
+ secp256k1_scalar_set_int(&data.sc[0], i);
+ secp256k1_scalar_set_int(&data.sc[1], j);
+ secp256k1_scalar_set_int(&g_sc, k);
+ data.pt[0] = group[x];
+ data.pt[1] = group[y];
+
+ secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2);
+ ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp);
+ }
+ }
+ }
+ }
+ }
+ secp256k1_scratch_destroy(scratch);
+}
+
void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {
secp256k1_fe x;
unsigned char x_bin[32];
@@ -456,6 +496,7 @@ int main(void) {
#endif
test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER);
test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER);
+ test_exhaustive_ecmult_multi(ctx, group, EXHAUSTIVE_TEST_ORDER);
test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER);
test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER);
diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h
index b0441d8e30..e1f5b76452 100644
--- a/src/secp256k1/src/util.h
+++ b/src/secp256k1/src/util.h
@@ -36,7 +36,7 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
} while(0)
#endif
-#ifdef HAVE_BUILTIN_EXPECT
+#if SECP256K1_GNUC_PREREQ(3, 0)
#define EXPECT(x,c) __builtin_expect((x),(c))
#else
#define EXPECT(x,c) (x)
@@ -76,6 +76,14 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
return ret;
}
+static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void *ptr, size_t size) {
+ void *ret = realloc(ptr, size);
+ if (ret == NULL) {
+ secp256k1_callback_call(cb, "Out of memory");
+ }
+ return ret;
+}
+
/* Macro for restrict, when available and not in a VERIFY build. */
#if defined(SECP256K1_BUILD) && defined(VERIFY)
# define SECP256K1_RESTRICT
diff --git a/src/serialize.h b/src/serialize.h
index 2d0cfbbbf0..1dc27d84eb 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -89,6 +89,11 @@ template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj)
obj = htole32(obj);
s.write((char*)&obj, 4);
}
+template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj)
+{
+ obj = htobe32(obj);
+ s.write((char*)&obj, 4);
+}
template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj)
{
obj = htole64(obj);
@@ -118,6 +123,12 @@ template<typename Stream> inline uint32_t ser_readdata32(Stream &s)
s.read((char*)&obj, 4);
return le32toh(obj);
}
+template<typename Stream> inline uint32_t ser_readdata32be(Stream &s)
+{
+ uint32_t obj;
+ s.read((char*)&obj, 4);
+ return be32toh(obj);
+}
template<typename Stream> inline uint64_t ser_readdata64(Stream &s)
{
uint64_t obj;
@@ -659,7 +670,7 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&)
while (i < nSize)
{
unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T)));
- v.resize(i + blk);
+ v.resize_uninitialized(i + blk);
is.read((char*)&v[i], blk * sizeof(T));
i += blk;
}
@@ -677,8 +688,8 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, const V&)
nMid += 5000000 / sizeof(T);
if (nMid > nSize)
nMid = nSize;
- v.resize(nMid);
- for (; i < nMid; i++)
+ v.resize_uninitialized(nMid);
+ for (; i < nMid; ++i)
Unserialize(is, v[i]);
}
}
diff --git a/src/sync.cpp b/src/sync.cpp
index 23ca866e53..20258d8e9a 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -2,10 +2,16 @@
// 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 <sync.h>
+#include <tinyformat.h>
#include <logging.h>
#include <util/strencodings.h>
+#include <util/threadnames.h>
#include <stdio.h>
@@ -37,23 +43,30 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
//
struct CLockLocation {
- CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
- {
- mutexName = pszName;
- sourceFile = pszFile;
- sourceLine = nLine;
- fTry = fTryIn;
- }
+ CLockLocation(
+ const char* pszName,
+ const char* pszFile,
+ int nLine,
+ bool fTryIn,
+ const std::string& thread_name)
+ : fTry(fTryIn),
+ mutexName(pszName),
+ sourceFile(pszFile),
+ m_thread_name(thread_name),
+ sourceLine(nLine) {}
std::string ToString() const
{
- return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
+ return strprintf(
+ "%s %s:%s%s (in thread %s)",
+ mutexName, sourceFile, itostr(sourceLine), (fTry ? " (TRY)" : ""), m_thread_name);
}
private:
bool fTry;
std::string mutexName;
std::string sourceFile;
+ const std::string& m_thread_name;
int sourceLine;
};
@@ -105,7 +118,7 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
LogPrintf(" %s\n", i.second.ToString());
}
if (g_debug_lockorder_abort) {
- fprintf(stderr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
+ tfm::format(std::cerr, "Assertion failed: detected inconsistent lock order at %s:%i, details in debug log.\n", __FILE__, __LINE__);
abort();
}
throw std::logic_error("potential deadlock detected");
@@ -125,7 +138,7 @@ static void push_lock(void* c, const CLockLocation& locklocation)
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
if (lockdata.lockorders.count(p1))
continue;
- lockdata.lockorders[p1] = g_lockstack;
+ lockdata.lockorders.emplace(p1, g_lockstack);
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
lockdata.invlockorders.insert(p2);
@@ -141,7 +154,7 @@ static void pop_lock()
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
- push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry));
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry, util::ThreadGetInternalName()));
}
void LeaveCritical()
@@ -162,7 +175,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
for (const std::pair<void*, CLockLocation>& i : g_lockstack)
if (i.first == cs)
return;
- fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
+ tfm::format(std::cerr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
abort();
}
@@ -170,7 +183,7 @@ void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLi
{
for (const std::pair<void*, CLockLocation>& i : g_lockstack) {
if (i.first == cs) {
- fprintf(stderr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
+ tfm::format(std::cerr, "Assertion failed: lock %s held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
abort();
}
}
diff --git a/src/sync.h b/src/sync.h
index 3857eda56b..bdbdde1a2a 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -198,6 +198,16 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove
LeaveCritical(); \
}
+//! Run code while locking a mutex.
+//!
+//! Examples:
+//!
+//! WITH_LOCK(cs, shared_val = shared_val + 1);
+//!
+//! int val = WITH_LOCK(cs, return shared_val);
+//!
+#define WITH_LOCK(cs, code) [&] { LOCK(cs); code; }()
+
class CSemaphore
{
private:
@@ -294,4 +304,18 @@ public:
}
};
+// Utility class for indicating to compiler thread analysis that a mutex is
+// locked (when it couldn't be determined otherwise).
+struct SCOPED_LOCKABLE LockAssertion
+{
+ template <typename Mutex>
+ explicit LockAssertion(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
+ {
+#ifdef DEBUG_LOCKORDER
+ AssertLockHeld(mutex);
+#endif
+ }
+ ~LockAssertion() UNLOCK_FUNCTION() {}
+};
+
#endif // BITCOIN_SYNC_H
diff --git a/src/test/README.md b/src/test/README.md
index f2a4cb1818..0017e3de26 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -42,7 +42,7 @@ unit tests as possible).
The build system is setup to compile an executable called `test_bitcoin`
that runs all of the unit tests. The main source file is called
-test_bitcoin.cpp. To add a new unit test file to our test suite you need
+setup_common.cpp. To add a new unit test file to our test suite you need
to add the file to `src/Makefile.test.include`. The pattern is to create
one test file for each class or source file for which you want to create
unit tests. The file naming convention is `<source_filename>_tests.cpp`
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 22347fbc57..eeb54b4cf0 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <addrman.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <string>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 9eded4f5b2..e333763f27 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <util/memory.h>
#include <util/system.h>
-#include <support/allocators/secure.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <memory>
diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp
index 1ff040b077..378fe285d5 100644
--- a/src/test/amount_tests.cpp
+++ b/src/test/amount_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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 <amount.h>
#include <policy/feerate.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp
index 77b6008fd0..9ac87261b6 100644
--- a/src/test/arith_uint256_tests.cpp
+++ b/src/test/arith_uint256_tests.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,8 +11,7 @@
#include <uint256.h>
#include <arith_uint256.h>
#include <string>
-#include <version.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
BOOST_FIXTURE_TEST_SUITE(arith_uint256_tests, BasicTestingSetup)
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index 32af843bf6..b3bed2434c 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index f8f9b3c1a7..cb376cddb6 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -1,11 +1,11 @@
-// 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.
#include <test/data/base58_encode_decode.json.h>
#include <base58.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <util/strencodings.h>
#include <univalue.h>
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index 0abbb682a7..9ffffb0b7d 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -1,9 +1,9 @@
-// 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.
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp
index 6ecc9ac705..0ba492c24e 100644
--- a/src/test/bech32_tests.cpp
+++ b/src/test/bech32_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bech32.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index c9951f4b7e..662878750e 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -1,15 +1,16 @@
-// Copyright (c) 2013-2018 The Bitcoin Core developers
+// Copyright (c) 2013-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 <boost/test/unit_test.hpp>
+#include <clientversion.h>
#include <key.h>
#include <key_io.h>
-#include <uint256.h>
+#include <streams.h>
#include <util/system.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <string>
#include <vector>
diff --git a/src/test/blockchain_tests.cpp b/src/test/blockchain_tests.cpp
index b61152985f..ca75563ef0 100644
--- a/src/test/blockchain_tests.cpp
+++ b/src/test/blockchain_tests.cpp
@@ -2,8 +2,9 @@
#include <stdlib.h>
+#include <chain.h>
#include <rpc/blockchain.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
/* Equality between doubles is imprecise. Comparison should be done
* with a small threshold of tolerance, rather than exact equality.
diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp
index 607af8a32a..dac201a35f 100644
--- a/src/test/blockencodings_tests.cpp
+++ b/src/test/blockencodings_tests.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.
@@ -6,9 +6,9 @@
#include <consensus/merkle.h>
#include <chainparams.h>
#include <pow.h>
-#include <random.h>
+#include <streams.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -386,6 +386,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
BOOST_CHECK(0);
} catch(std::ios_base::failure &) {
// deserialize should fail
+ BOOST_CHECK(true); // Needed to suppress "Test case [...] did not check any assertions"
}
}
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
new file mode 100644
index 0000000000..cf87aa9303
--- /dev/null
+++ b/src/test/blockfilter_index_tests.cpp
@@ -0,0 +1,306 @@
+// 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.
+
+#include <blockfilter.h>
+#include <chainparams.h>
+#include <consensus/validation.h>
+#include <index/blockfilterindex.h>
+#include <miner.h>
+#include <pow.h>
+#include <test/setup_common.h>
+#include <script/standard.h>
+#include <util/time.h>
+#include <validation.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)
+
+static bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index,
+ BlockFilter& filter)
+{
+ CBlock block;
+ if (!ReadBlockFromDisk(block, block_index->GetBlockPos(), Params().GetConsensus())) {
+ return false;
+ }
+
+ CBlockUndo block_undo;
+ if (block_index->nHeight > 0 && !UndoReadFromDisk(block_undo, block_index)) {
+ return false;
+ }
+
+ filter = BlockFilter(filter_type, block, block_undo);
+ return true;
+}
+
+static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex* block_index,
+ uint256& last_header)
+{
+ BlockFilter expected_filter;
+ if (!ComputeFilter(filter_index.GetFilterType(), block_index, expected_filter)) {
+ BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
+ return false;
+ }
+
+ BlockFilter filter;
+ uint256 filter_header;
+ std::vector<BlockFilter> filters;
+ std::vector<uint256> filter_hashes;
+
+ BOOST_CHECK(filter_index.LookupFilter(block_index, filter));
+ BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));
+ BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
+ BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
+ filter_hashes));
+
+ BOOST_CHECK_EQUAL(filters.size(), 1);
+ BOOST_CHECK_EQUAL(filter_hashes.size(), 1);
+
+ BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());
+ BOOST_CHECK_EQUAL(filter_header, expected_filter.ComputeHeader(last_header));
+ BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());
+ BOOST_CHECK_EQUAL(filter_hashes[0], expected_filter.GetHash());
+
+ filters.clear();
+ filter_hashes.clear();
+ last_header = filter_header;
+ return true;
+}
+
+static CBlock CreateBlock(const CBlockIndex* prev,
+ const std::vector<CMutableTransaction>& txns,
+ const CScript& scriptPubKey)
+{
+ const CChainParams& chainparams = Params();
+ std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ CBlock& block = pblocktemplate->block;
+ block.hashPrevBlock = prev->GetBlockHash();
+ block.nTime = prev->nTime + 1;
+
+ // Replace mempool-selected txns with just coinbase plus passed-in txns:
+ block.vtx.resize(1);
+ for (const CMutableTransaction& tx : txns) {
+ block.vtx.push_back(MakeTransactionRef(tx));
+ }
+ // IncrementExtraNonce creates a valid coinbase and merkleRoot
+ unsigned int extraNonce = 0;
+ IncrementExtraNonce(&block, prev, extraNonce);
+
+ while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
+
+ return block;
+}
+
+static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script_pub_key,
+ size_t length, std::vector<std::shared_ptr<CBlock>>& chain)
+{
+ std::vector<CMutableTransaction> no_txns;
+
+ chain.resize(length);
+ for (auto& block : chain) {
+ block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
+ CBlockHeader header = block->GetBlockHeader();
+
+ CValidationState state;
+ if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
+{
+ BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);
+
+ uint256 last_header;
+
+ // Filter should not be found in the index before it is started.
+ {
+ LOCK(cs_main);
+
+ BlockFilter filter;
+ uint256 filter_header;
+ std::vector<BlockFilter> filters;
+ std::vector<uint256> filter_hashes;
+
+ for (const CBlockIndex* block_index = ::ChainActive().Genesis();
+ block_index != nullptr;
+ block_index = ::ChainActive().Next(block_index)) {
+ BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));
+ BOOST_CHECK(!filter_index.LookupFilterHeader(block_index, filter_header));
+ BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
+ BOOST_CHECK(!filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
+ filter_hashes));
+ }
+ }
+
+ // BlockUntilSyncedToCurrentChain should return false before index is started.
+ BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
+
+ filter_index.Start();
+
+ // Allow filter index to catch up with the block index.
+ constexpr int64_t timeout_ms = 10 * 1000;
+ int64_t time_start = GetTimeMillis();
+ while (!filter_index.BlockUntilSyncedToCurrentChain()) {
+ BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
+ MilliSleep(100);
+ }
+
+ // Check that filter index has all blocks that were in the chain before it started.
+ {
+ LOCK(cs_main);
+ const CBlockIndex* block_index;
+ for (block_index = ::ChainActive().Genesis();
+ block_index != nullptr;
+ block_index = ::ChainActive().Next(block_index)) {
+ CheckFilterLookups(filter_index, block_index, last_header);
+ }
+ }
+
+ // Create two forks.
+ const CBlockIndex* tip;
+ {
+ LOCK(cs_main);
+ tip = ::ChainActive().Tip();
+ }
+ CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
+ std::vector<std::shared_ptr<CBlock>> chainA, chainB;
+ BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainA));
+ BOOST_REQUIRE(BuildChain(tip, coinbase_script_pub_key, 10, chainB));
+
+ // Check that new blocks on chain A get indexed.
+ uint256 chainA_last_header = last_header;
+ for (size_t i = 0; i < 2; i++) {
+ const auto& block = chainA[i];
+ BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));
+
+ const CBlockIndex* block_index;
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(block->GetHash());
+ }
+
+ BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
+ CheckFilterLookups(filter_index, block_index, chainA_last_header);
+ }
+
+ // Reorg to chain B.
+ uint256 chainB_last_header = last_header;
+ for (size_t i = 0; i < 3; i++) {
+ const auto& block = chainB[i];
+ BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));
+
+ const CBlockIndex* block_index;
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(block->GetHash());
+ }
+
+ BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
+ CheckFilterLookups(filter_index, block_index, chainB_last_header);
+ }
+
+ // Check that filters for stale blocks on A can be retrieved.
+ chainA_last_header = last_header;
+ for (size_t i = 0; i < 2; i++) {
+ const auto& block = chainA[i];
+ const CBlockIndex* block_index;
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(block->GetHash());
+ }
+
+ BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
+ CheckFilterLookups(filter_index, block_index, chainA_last_header);
+ }
+
+ // Reorg back to chain A.
+ for (size_t i = 2; i < 4; i++) {
+ const auto& block = chainA[i];
+ BOOST_REQUIRE(ProcessNewBlock(Params(), block, true, nullptr));
+ }
+
+ // Check that chain A and B blocks can be retrieved.
+ chainA_last_header = last_header;
+ chainB_last_header = last_header;
+ for (size_t i = 0; i < 3; i++) {
+ const CBlockIndex* block_index;
+
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(chainA[i]->GetHash());
+ }
+ BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
+ CheckFilterLookups(filter_index, block_index, chainA_last_header);
+
+ {
+ LOCK(cs_main);
+ block_index = LookupBlockIndex(chainB[i]->GetHash());
+ }
+ BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
+ CheckFilterLookups(filter_index, block_index, chainB_last_header);
+ }
+
+ // Test lookups for a range of filters/hashes.
+ std::vector<BlockFilter> filters;
+ std::vector<uint256> filter_hashes;
+
+ {
+ LOCK(cs_main);
+ tip = ::ChainActive().Tip();
+ }
+ BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));
+ BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes));
+
+ BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1);
+ BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1);
+
+ filters.clear();
+ filter_hashes.clear();
+
+ filter_index.Interrupt();
+ filter_index.Stop();
+}
+
+BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
+{
+ BlockFilterIndex* filter_index;
+
+ filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
+ BOOST_CHECK(filter_index == nullptr);
+
+ BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+
+ filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
+ BOOST_CHECK(filter_index != nullptr);
+ BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);
+
+ // Initialize returns false if index already exists.
+ BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+
+ int iter_count = 0;
+ ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
+ BOOST_CHECK_EQUAL(iter_count, 1);
+
+ BOOST_CHECK(DestroyBlockFilterIndex(BlockFilterType::BASIC));
+
+ // Destroy returns false because index was already destroyed.
+ BOOST_CHECK(!DestroyBlockFilterIndex(BlockFilterType::BASIC));
+
+ filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
+ BOOST_CHECK(filter_index == nullptr);
+
+ // Reinitialize index.
+ BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+
+ DestroyAllBlockFilterIndexes();
+
+ filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
+ BOOST_CHECK(filter_index == nullptr);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp
index 625362f446..df0a041e0e 100644
--- a/src/test/blockfilter_tests.cpp
+++ b/src/test/blockfilter_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
#include <test/data/blockfilters.json.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <blockfilter.h>
#include <core_io.h>
@@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(gcsfilter_default_constructor)
BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
{
- CScript included_scripts[5], excluded_scripts[3];
+ CScript included_scripts[5], excluded_scripts[4];
// First two are outputs on a single transaction.
included_scripts[0] << std::vector<unsigned char>(0, 65) << OP_CHECKSIG;
@@ -73,14 +73,19 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
// This script is not related to the block at all.
excluded_scripts[1] << std::vector<unsigned char>(5, 33) << OP_CHECKSIG;
+ // OP_RETURN is non-standard since it's not followed by a data push, but is still excluded from
+ // filter.
+ excluded_scripts[2] << OP_RETURN << OP_4 << OP_ADD << OP_8 << OP_EQUAL;
+
CMutableTransaction tx_1;
tx_1.vout.emplace_back(100, included_scripts[0]);
tx_1.vout.emplace_back(200, included_scripts[1]);
+ tx_1.vout.emplace_back(0, excluded_scripts[0]);
CMutableTransaction tx_2;
tx_2.vout.emplace_back(300, included_scripts[2]);
- tx_2.vout.emplace_back(0, excluded_scripts[0]);
- tx_2.vout.emplace_back(400, excluded_scripts[2]); // Script is empty
+ tx_2.vout.emplace_back(0, excluded_scripts[2]);
+ tx_2.vout.emplace_back(400, excluded_scripts[3]); // Script is empty
CBlock block;
block.vtx.push_back(MakeTransactionRef(tx_1));
@@ -90,7 +95,7 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
block_undo.vtxundo.emplace_back();
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(500, included_scripts[3]), 1000, true);
block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(600, included_scripts[4]), 10000, false);
- block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[2]), 100000, false);
+ block_undo.vtxundo.back().vprevout.emplace_back(CTxOut(700, excluded_scripts[3]), 100000, false);
BlockFilter block_filter(BlockFilterType::BASIC, block, block_undo);
const GCSFilter& filter = block_filter.GetFilter();
@@ -112,6 +117,12 @@ BOOST_AUTO_TEST_CASE(blockfilter_basic_test)
BOOST_CHECK_EQUAL(block_filter.GetFilterType(), block_filter2.GetFilterType());
BOOST_CHECK_EQUAL(block_filter.GetBlockHash(), block_filter2.GetBlockHash());
BOOST_CHECK(block_filter.GetEncodedFilter() == block_filter2.GetEncodedFilter());
+
+ BlockFilter default_ctor_block_filter_1;
+ BlockFilter default_ctor_block_filter_2;
+ BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetFilterType(), default_ctor_block_filter_2.GetFilterType());
+ BOOST_CHECK_EQUAL(default_ctor_block_filter_1.GetBlockHash(), default_ctor_block_filter_2.GetBlockHash());
+ BOOST_CHECK(default_ctor_block_filter_1.GetEncodedFilter() == default_ctor_block_filter_2.GetEncodedFilter());
}
BOOST_AUTO_TEST_CASE(blockfilters_json_test)
@@ -168,4 +179,16 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test)
}
}
+BOOST_AUTO_TEST_CASE(blockfilter_type_names)
+{
+ BOOST_CHECK_EQUAL(BlockFilterTypeName(BlockFilterType::BASIC), "basic");
+ BOOST_CHECK_EQUAL(BlockFilterTypeName(static_cast<BlockFilterType>(255)), "");
+
+ BlockFilterType filter_type;
+ BOOST_CHECK(BlockFilterTypeByName("basic", filter_type));
+ BOOST_CHECK_EQUAL(filter_type, BlockFilterType::BASIC);
+
+ BOOST_CHECK(!BlockFilterTypeByName("unknown", filter_type));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index f58dd20efc..4421494007 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -15,7 +15,7 @@
#include <uint256.h>
#include <util/system.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <vector>
diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp
index 8572926193..8fd4e5d5d6 100644
--- a/src/test/bswap_tests.cpp
+++ b/src/test/bswap_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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 <compat/byteswap.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp
index 3469c6dfba..d796444419 100644
--- a/src/test/checkqueue_tests.cpp
+++ b/src/test/checkqueue_tests.cpp
@@ -1,12 +1,13 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <util/memory.h>
#include <util/system.h>
#include <util/time.h>
#include <validation.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <checkqueue.h>
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
@@ -17,8 +18,6 @@
#include <condition_variable>
#include <unordered_set>
-#include <memory>
-#include <random.h>
// BasicTestingSetup not sufficient because nScriptCheckThreads is not set
// otherwise.
@@ -167,7 +166,6 @@ static void Correct_Queue_range(std::vector<size_t> range)
BOOST_REQUIRE(control.Wait());
if (FakeCheckCheckCompletion::n_calls != i) {
BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);
- BOOST_TEST_MESSAGE("Failure on trial " << i << " expected, got " << FakeCheckCheckCompletion::n_calls);
}
}
tg.interrupt_all();
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index f6b97a6868..948591196c 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -1,16 +1,16 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-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 <attributes.h>
+#include <clientversion.h>
#include <coins.h>
-#include <consensus/validation.h>
#include <script/standard.h>
-#include <test/test_bitcoin.h>
+#include <streams.h>
+#include <test/setup_common.h>
#include <uint256.h>
#include <undo.h>
#include <util/strencodings.h>
-#include <validation.h>
#include <map>
#include <vector>
@@ -280,6 +280,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
{
SeedInsecureRand(/* deterministic */ true);
+ g_mock_deterministic_tests = true;
bool spent_a_duplicate_coinbase = false;
// A simple map to track what we expect the cache stack to represent.
@@ -474,6 +475,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Verify coverage.
BOOST_CHECK(spent_a_duplicate_coinbase);
+
+ g_mock_deterministic_tests = false;
}
BOOST_AUTO_TEST_CASE(ccoins_serialization)
@@ -485,7 +488,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
BOOST_CHECK_EQUAL(cc1.fCoinBase, false);
BOOST_CHECK_EQUAL(cc1.nHeight, 203998U);
BOOST_CHECK_EQUAL(cc1.out.nValue, CAmount{60000000000});
- BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
+ BOOST_CHECK_EQUAL(HexStr(cc1.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))))));
// Good example
CDataStream ss2(ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION);
@@ -494,7 +497,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
BOOST_CHECK_EQUAL(cc2.fCoinBase, true);
BOOST_CHECK_EQUAL(cc2.nHeight, 120891U);
BOOST_CHECK_EQUAL(cc2.out.nValue, 110397);
- BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
+ BOOST_CHECK_EQUAL(HexStr(cc2.out.scriptPubKey), HexStr(GetScriptForDestination(PKHash(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))))));
// Smallest possible example
CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION);
diff --git a/src/test/compilerbug_tests.cpp b/src/test/compilerbug_tests.cpp
new file mode 100644
index 0000000000..74e1eac3ea
--- /dev/null
+++ b/src/test/compilerbug_tests.cpp
@@ -0,0 +1,43 @@
+// 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 <test/setup_common.h>
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(compilerbug_tests, BasicTestingSetup)
+
+#if defined(__GNUC__)
+// This block will also be built under clang, which is fine (as it supports noinline)
+void __attribute__ ((noinline)) set_one(unsigned char* ptr)
+{
+ *ptr = 1;
+}
+
+int __attribute__ ((noinline)) check_zero(unsigned char const* in, unsigned int len)
+{
+ for (unsigned int i = 0; i < len; ++i) {
+ if (in[i] != 0) return 0;
+ }
+ return 1;
+}
+
+void set_one_on_stack() {
+ unsigned char buf[1];
+ set_one(buf);
+}
+
+BOOST_AUTO_TEST_CASE(gccbug_90348) {
+ // Test for GCC bug 90348. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90348
+ for (int i = 0; i <= 4; ++i) {
+ unsigned char in[4];
+ for (int j = 0; j < i; ++j) {
+ in[j] = 0;
+ set_one_on_stack(); // Apparently modifies in[0]
+ }
+ BOOST_CHECK(check_zero(in, i));
+ }
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp
index e686c05165..6cef8cd8a8 100644
--- a/src/test/compress_tests.cpp
+++ b/src/test/compress_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <compressor.h>
#include <util/system.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <stdint.h>
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index 86cb00a78f..4e2acca4c3 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -1,24 +1,24 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-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 <crypto/aes.h>
#include <crypto/chacha20.h>
+#include <crypto/poly1305.h>
+#include <crypto/hkdf_sha256_32.h>
+#include <crypto/hmac_sha256.h>
+#include <crypto/hmac_sha512.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
#include <crypto/sha512.h>
-#include <crypto/hmac_sha256.h>
-#include <crypto/hmac_sha512.h>
#include <random.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <vector>
#include <boost/test/unit_test.hpp>
-#include <openssl/aes.h>
-#include <openssl/evp.h>
BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup)
@@ -66,26 +66,6 @@ static void TestHMACSHA512(const std::string &hexkey, const std::string &hexin,
TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout));
}
-static void TestAES128(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
-{
- std::vector<unsigned char> key = ParseHex(hexkey);
- std::vector<unsigned char> in = ParseHex(hexin);
- std::vector<unsigned char> correctout = ParseHex(hexout);
- std::vector<unsigned char> buf, buf2;
-
- assert(key.size() == 16);
- assert(in.size() == 16);
- assert(correctout.size() == 16);
- AES128Encrypt enc(key.data());
- buf.resize(correctout.size());
- buf2.resize(correctout.size());
- enc.Encrypt(buf.data(), in.data());
- BOOST_CHECK_EQUAL(HexStr(buf), HexStr(correctout));
- AES128Decrypt dec(key.data());
- dec.Decrypt(buf2.data(), buf.data());
- BOOST_CHECK_EQUAL(HexStr(buf2), HexStr(in));
-}
-
static void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout)
{
std::vector<unsigned char> key = ParseHex(hexkey);
@@ -105,47 +85,6 @@ static void TestAES256(const std::string &hexkey, const std::string &hexin, cons
BOOST_CHECK(buf == in);
}
-static void TestAES128CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout)
-{
- std::vector<unsigned char> key = ParseHex(hexkey);
- std::vector<unsigned char> iv = ParseHex(hexiv);
- std::vector<unsigned char> in = ParseHex(hexin);
- std::vector<unsigned char> correctout = ParseHex(hexout);
- std::vector<unsigned char> realout(in.size() + AES_BLOCKSIZE);
-
- // Encrypt the plaintext and verify that it equals the cipher
- AES128CBCEncrypt enc(key.data(), iv.data(), pad);
- int size = enc.Encrypt(in.data(), in.size(), realout.data());
- realout.resize(size);
- BOOST_CHECK(realout.size() == correctout.size());
- BOOST_CHECK_MESSAGE(realout == correctout, HexStr(realout) + std::string(" != ") + hexout);
-
- // Decrypt the cipher and verify that it equals the plaintext
- std::vector<unsigned char> decrypted(correctout.size());
- AES128CBCDecrypt dec(key.data(), iv.data(), pad);
- size = dec.Decrypt(correctout.data(), correctout.size(), decrypted.data());
- decrypted.resize(size);
- BOOST_CHECK(decrypted.size() == in.size());
- BOOST_CHECK_MESSAGE(decrypted == in, HexStr(decrypted) + std::string(" != ") + hexin);
-
- // Encrypt and re-decrypt substrings of the plaintext and verify that they equal each-other
- for(std::vector<unsigned char>::iterator i(in.begin()); i != in.end(); ++i)
- {
- std::vector<unsigned char> sub(i, in.end());
- std::vector<unsigned char> subout(sub.size() + AES_BLOCKSIZE);
- int _size = enc.Encrypt(sub.data(), sub.size(), subout.data());
- if (_size != 0)
- {
- subout.resize(_size);
- std::vector<unsigned char> subdecrypted(subout.size());
- _size = dec.Decrypt(subout.data(), subout.size(), subdecrypted.data());
- subdecrypted.resize(_size);
- BOOST_CHECK(decrypted.size() == in.size());
- BOOST_CHECK_MESSAGE(subdecrypted == sub, HexStr(subdecrypted) + std::string(" != ") + HexStr(sub));
- }
- }
-}
-
static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout)
{
std::vector<unsigned char> key = ParseHex(hexkey);
@@ -187,17 +126,63 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b
}
}
-static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
+static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uint64_t nonce, uint64_t seek, const std::string& hexout)
{
std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> m = ParseHex(hex_message);
ChaCha20 rng(key.data(), key.size());
rng.SetIV(nonce);
rng.Seek(seek);
std::vector<unsigned char> out = ParseHex(hexout);
std::vector<unsigned char> outres;
outres.resize(out.size());
- rng.Output(outres.data(), outres.size());
+ assert(hex_message.empty() || m.size() == out.size());
+
+ // perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream
+ if (!hex_message.empty()) {
+ rng.Crypt(m.data(), outres.data(), outres.size());
+ } else {
+ rng.Keystream(outres.data(), outres.size());
+ }
BOOST_CHECK(out == outres);
+ if (!hex_message.empty()) {
+ // Manually XOR with the keystream and compare the output
+ rng.SetIV(nonce);
+ rng.Seek(seek);
+ std::vector<unsigned char> only_keystream(outres.size());
+ rng.Keystream(only_keystream.data(), only_keystream.size());
+ for (size_t i = 0; i != m.size(); i++) {
+ outres[i] = m[i] ^ only_keystream[i];
+ }
+ BOOST_CHECK(out == outres);
+ }
+}
+
+static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag)
+{
+ std::vector<unsigned char> key = ParseHex(hexkey);
+ std::vector<unsigned char> m = ParseHex(hexmessage);
+ std::vector<unsigned char> tag = ParseHex(hextag);
+ std::vector<unsigned char> tagres;
+ tagres.resize(POLY1305_TAGLEN);
+ poly1305_auth(tagres.data(), m.data(), m.size(), key.data());
+ BOOST_CHECK(tag == tagres);
+}
+
+static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) {
+ std::vector<unsigned char> initial_key_material = ParseHex(ikm_hex);
+ std::vector<unsigned char> salt = ParseHex(salt_hex);
+ std::vector<unsigned char> info = ParseHex(info_hex);
+
+
+ // our implementation only supports strings for the "info" and "salt", stringify them
+ std::string salt_stringified(reinterpret_cast<char*>(salt.data()), salt.size());
+ std::string info_stringified(reinterpret_cast<char*>(info.data()), info.size());
+
+ CHKDF_HMAC_SHA256_L32 hkdf32(initial_key_material.data(), initial_key_material.size(), salt_stringified);
+ unsigned char out[32];
+ hkdf32.Expand32(info_stringified, out);
+ BOOST_CHECK(HexStr(out, out + 32) == okm_check_hex);
}
static std::string LongTestString() {
@@ -428,14 +413,9 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
BOOST_AUTO_TEST_CASE(aes_testvectors) {
// AES test vectors from FIPS 197.
- TestAES128("000102030405060708090a0b0c0d0e0f", "00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a");
TestAES256("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "00112233445566778899aabbccddeeff", "8ea2b7ca516745bfeafc49904b496089");
// AES-ECB test vectors from NIST sp800-38a.
- TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97");
- TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf");
- TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688");
- TestAES128("2b7e151628aed2a6abf7158809cf4f3c", "f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4");
TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8");
TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "ae2d8a571e03ac9c9eb76fac45af8e51", "591ccb10d410ed26dc5ba74a31362870");
TestAES256("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", "30c81c46a35ce411e5fbc1191a0a52ef", "b6ed21b99ca6f4f9f153e7b1beafed1d");
@@ -443,27 +423,6 @@ BOOST_AUTO_TEST_CASE(aes_testvectors) {
}
BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
-
- // NIST AES CBC 128-bit encryption test-vectors
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090A0B0C0D0E0F", false, \
- "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d");
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "7649ABAC8119B246CEE98E9B12E9197D", false, \
- "ae2d8a571e03ac9c9eb76fac45af8e51", "5086cb9b507219ee95db113a917678b2");
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "5086cb9b507219ee95db113a917678b2", false, \
- "30c81c46a35ce411e5fbc1191a0a52ef", "73bed6b8e3c1743b7116e69e22229516");
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "73bed6b8e3c1743b7116e69e22229516", false, \
- "f69f2445df4f9b17ad2b417be66c3710", "3ff1caa1681fac09120eca307586e1a7");
-
- // The same vectors with padding enabled
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090A0B0C0D0E0F", true, \
- "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d8964e0b149c10b7b682e6e39aaeb731c");
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "7649ABAC8119B246CEE98E9B12E9197D", true, \
- "ae2d8a571e03ac9c9eb76fac45af8e51", "5086cb9b507219ee95db113a917678b255e21d7100b988ffec32feeafaf23538");
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "5086cb9b507219ee95db113a917678b2", true, \
- "30c81c46a35ce411e5fbc1191a0a52ef", "73bed6b8e3c1743b7116e69e22229516f6eccda327bf8e5ec43718b0039adceb");
- TestAES128CBC("2b7e151628aed2a6abf7158809cf4f3c", "73bed6b8e3c1743b7116e69e22229516", true, \
- "f69f2445df4f9b17ad2b417be66c3710", "3ff1caa1681fac09120eca307586e1a78cb82807230e1321d3fae00d18cc2012");
-
// NIST AES CBC 256-bit encryption test-vectors
TestAES256CBC("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", \
"000102030405060708090A0B0C0D0E0F", false, "6bc1bee22e409f96e93d7e117393172a", \
@@ -497,25 +456,37 @@ BOOST_AUTO_TEST_CASE(aes_cbc_testvectors) {
BOOST_AUTO_TEST_CASE(chacha20_testvector)
{
// Test vector from RFC 7539
- TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,
+
+ // test encryption
+ TestChaCha20("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756"
+ "c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e"
+ "20776f756c642062652069742e",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,
+ "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d"
+ "624e65152ab8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74"
+ "a35be6b40b8eedf2785e42874d"
+ );
+
+ // test keystream output
+ TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x4a000000UL, 1,
"224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cb"
"a40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a"
"832c89c167eacd901d7e2bf363");
// Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7
- TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0, 0,
+ TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0, 0,
"76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b"
"8f41518a11cc387b669b2ee6586");
- TestChaCha20("0000000000000000000000000000000000000000000000000000000000000001", 0, 0,
+ TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000001", 0, 0,
"4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d79"
"2b1c43fea817e9ad275ae546963");
- TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0,
+ TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 0x0100000000000000ULL, 0,
"de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b52770"
"62eb7a0433e445f41e3");
- TestChaCha20("0000000000000000000000000000000000000000000000000000000000000000", 1, 0,
+ TestChaCha20("", "0000000000000000000000000000000000000000000000000000000000000000", 1, 0,
"ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc4"
"97a0b466e7d6bbdb0041b2f586b");
- TestChaCha20("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0,
+ TestChaCha20("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 0x0706050403020100ULL, 0,
"f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3b"
"e59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc1"
"18be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5"
@@ -524,6 +495,96 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
"fab78c9");
}
+BOOST_AUTO_TEST_CASE(poly1305_testvector)
+{
+ // RFC 7539, section 2.5.2.
+ TestPoly1305("43727970746f6772617068696320466f72756d2052657365617263682047726f7570",
+ "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b",
+ "a8061dc1305136c6c22b8baf0c0127a9");
+
+ // RFC 7539, section A.3.
+ TestPoly1305("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000");
+
+ TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
+ "5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
+ "726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
+ "520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
+ "4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
+ "56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
+ "6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
+ "768696368206172652061646472657373656420746f",
+ "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e",
+ "36e5f6b5c5e06070f0efca96227a863e");
+
+ TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
+ "5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
+ "726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
+ "520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
+ "4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
+ "56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
+ "6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
+ "768696368206172652061646472657373656420746f",
+ "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000",
+ "f3477e7cd95417af89a6b8794c310cf0");
+
+ TestPoly1305("2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e6420676"
+ "96d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e"
+ "6420746865206d6f6d65207261746873206f757467726162652e",
+ "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
+ "4541669a7eaaee61e708dc7cbcc5eb62");
+
+ TestPoly1305("ffffffffffffffffffffffffffffffff",
+ "0200000000000000000000000000000000000000000000000000000000000000",
+ "03000000000000000000000000000000");
+
+ TestPoly1305("02000000000000000000000000000000",
+ "02000000000000000000000000000000ffffffffffffffffffffffffffffffff",
+ "03000000000000000000000000000000");
+
+ TestPoly1305("fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "05000000000000000000000000000000");
+
+ TestPoly1305("fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000");
+
+ TestPoly1305("fdffffffffffffffffffffffffffffff",
+ "0200000000000000000000000000000000000000000000000000000000000000",
+ "faffffffffffffffffffffffffffffff");
+
+ TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000",
+ "0100000000000000040000000000000000000000000000000000000000000000",
+ "14000000000000005500000000000000");
+
+ TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000",
+ "0100000000000000040000000000000000000000000000000000000000000000",
+ "13000000000000000000000000000000");
+}
+
+BOOST_AUTO_TEST_CASE(hkdf_hmac_sha256_l32_tests)
+{
+ // Use rfc5869 test vectors but truncated to 32 bytes (our implementation only support length 32)
+ TestHKDF_SHA256_32(
+ /* IKM */ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ /* salt */ "000102030405060708090a0b0c",
+ /* info */ "f0f1f2f3f4f5f6f7f8f9",
+ /* expected OKM */ "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf");
+ TestHKDF_SHA256_32(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c");
+ TestHKDF_SHA256_32(
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "",
+ "",
+ "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d");
+}
+
BOOST_AUTO_TEST_CASE(countbits_tests)
{
FastRandomContext ctx;
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index d8286520ec..d38ede691a 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <boost/test/unit_test.hpp>
#include <cuckoocache.h>
#include <script/sigcache.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <random.h>
#include <thread>
diff --git a/src/test/data/blockfilters.json b/src/test/data/blockfilters.json
index 134b788eed..8945296a07 100644
--- a/src/test/data/blockfilters.json
+++ b/src/test/data/blockfilters.json
@@ -3,9 +3,11 @@
[0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"],
[2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""],
[3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""],
+[15007,"0000000038c44c703bae0f98cdd6bf30922326340a5996cc692aaae8bacf47ad","0100000002394092aa378fe35d7e9ac79c869b975c4de4374cd75eb5484b0e1e00000000eb9b8670abd44ad6c55cee18e3020fb0c6519e7004b01a16e9164867531b67afc33bc94fffff001d123f10050101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e04c33bc94f0115062f503253482fffffffff0100f2052a01000000232103f268e9ae07e0f8cb2f6e901d87c510d650b97230c0365b021df8f467363cafb1ac00000000",[],"18b5c2b0146d2d09d24fb00ff5b52bd0742f36c9e65527abdb9de30c027a4748","013c3710","07384b01311867949e0c046607c66b7a766d338474bb67f66c8ae9dbd454b20e","Tx has non-standard OP_RETURN output followed by opcodes"],
[49291,"0000000018b07dca1b28b4b5a119f6d6e71698ce1ed96f143f54179ce177a19c","02000000abfaf47274223ca2fea22797e44498240e482cb4c2f2baea088962f800000000604b5b52c32305b15d7542071d8b04e750a547500005d4010727694b6e72a776e55d0d51ffff001d211806480201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038bc0000102062f503253482fffffffff01a078072a01000000232102971dd6034ed0cf52450b608d196c07d6345184fcb14deb277a6b82d526a6163dac0000000001000000081cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff000000009300493046022100866859c21f306538152e83f115bcfbf59ab4bb34887a88c03483a5dff9895f96022100a6dfd83caa609bf0516debc2bf65c3df91813a4842650a1858b3f61cfa8af249014730440220296d4b818bb037d0f83f9f7111665f49532dfdcbec1e6b784526e9ac4046eaa602204acf3a5cb2695e8404d80bf49ab04828bcbe6fc31d25a2844ced7a8d24afbdff01ffffffff1cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff020000009400483045022100e87899175991aa008176cb553c6f2badbb5b741f328c9845fcab89f8b18cae2302200acce689896dc82933015e7230e5230d5cff8a1ffe82d334d60162ac2c5b0c9601493046022100994ad29d1e7b03e41731a4316e5f4992f0d9b6e2efc40a1ccd2c949b461175c502210099b69fdc2db00fbba214f16e286f6a49e2d8a0d5ffc6409d87796add475478d601ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272010000009500493046022100a27400ba52fd842ce07398a1de102f710a10c5599545e6c95798934352c2e4df022100f6383b0b14c9f64b6718139f55b6b9494374755b86bae7d63f5d3e583b57255a01493046022100fdf543292f34e1eeb1703b264965339ec4a450ec47585009c606b3edbc5b617b022100a5fbb1c8de8aaaa582988cdb23622838e38de90bebcaab3928d949aa502a65d401ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272020000009400493046022100ac626ac3051f875145b4fe4cfe089ea895aac73f65ab837b1ac30f5d875874fa022100bc03e79fa4b7eb707fb735b95ff6613ca33adeaf3a0607cdcead4cfd3b51729801483045022100b720b04a5c5e2f61b7df0fcf334ab6fea167b7aaede5695d3f7c6973496adbf1022043328c4cc1cdc3e5db7bb895ccc37133e960b2fd3ece98350f774596badb387201ffffffff23a8733e349c97d6cd90f520fdd084ba15ce0a395aad03cd51370602bb9e5db3010000004a00483045022100e8556b72c5e9c0da7371913a45861a61c5df434dfd962de7b23848e1a28c86ca02205d41ceda00136267281be0974be132ac4cda1459fe2090ce455619d8b91045e901ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a6000000006a473044022040a1c631554b8b210fbdf2a73f191b2851afb51d5171fb53502a3a040a38d2c0022040d11cf6e7b41fe1b66c3d08f6ada1aee07a047cb77f242b8ecc63812c832c9a012102bcfad931b502761e452962a5976c79158a0f6d307ad31b739611dac6a297c256ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a601000000930048304502205b109df098f7e932fbf71a45869c3f80323974a826ee2770789eae178a21bfc8022100c0e75615e53ee4b6e32b9bb5faa36ac539e9c05fa2ae6b6de5d09c08455c8b9601483045022009fb7d27375c47bea23b24818634df6a54ecf72d52e0c1268fb2a2c84f1885de022100e0ed4f15d62e7f537da0d0f1863498f9c7c0c0a4e00e4679588c8d1a9eb20bb801ffffffffa563c3722b7b39481836d5edfc1461f97335d5d1e9a23ade13680d0e2c1c371f030000006c493046022100ecc38ae2b1565643dc3c0dad5e961a5f0ea09cab28d024f92fa05c922924157e022100ebc166edf6fbe4004c72bfe8cf40130263f98ddff728c8e67b113dbd621906a601210211a4ed241174708c07206601b44a4c1c29e5ad8b1f731c50ca7e1d4b2a06dc1fffffffff02d0223a00000000001976a91445db0b779c0b9fa207f12a8218c94fc77aff504588ac80f0fa02000000000000000000",["5221033423007d8f263819a2e42becaaf5b06f34cb09919e06304349d950668209eaed21021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","522102a7ae1e0971fc1689bd66d2a7296da3a1662fd21a53c9e38979e0f090a375c12d21022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","512103b9d1d0e2b4355ec3cdef7c11a5c0beff9e8b8d8372ab4b4e0aaf30e80173001951ae","76a9149144761ebaccd5b4bbdc2a35453585b5637b2f8588ac","522103f1848b40621c5d48471d9784c8174ca060555891ace6d2b03c58eece946b1a9121020ee5d32b54d429c152fdc7b1db84f2074b0564d35400d89d11870f9273ec140c52ae","76a914f4fa1cc7de742d135ea82c17adf0bb9cf5f4fb8388ac"],"ed47705334f4643892ca46396eb3f4196a5e30880589e4009ef38eae895d4a13","0afbc2920af1b027f31f87b592276eb4c32094bb4d3697021b4c6380","b6d98692cec5145f67585f3434ec3c2b3030182e1cb3ec58b855c5c164dfaaa3","Tx pays to empty output script"],
-[180480,"00000000fd3ceb2404ff07a785c7fdcc76619edc8ed61bd25134eaa22084366a","020000006058aa080a655aa991a444bd7d1f2defd9a3bbe68aabb69030cf3b4e00000000d2e826bfd7ef0beaa891a7eedbc92cd6a544a6cb61c7bdaa436762eb2123ef9790f5f552ffff001d0002c90f0501000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0300c102024608062f503253482fffffffff01c0c6072a01000000232102e769e60137a4df6b0df8ebd387cca44c4c57ae74cc0114a8e8317c8f3bfd85e9ac00000000010000000381a0802911a01ffb025c4dea0bc77963e8c1bb46313b71164c53f72f37fe5248010000000151ffffffffc904b267833d215e2128bd9575242232ac2bc311550c7fc1f0ef6f264b40d14c010000000151ffffffffdf0915666649dba81886519c531649b7b02180b4af67d6885e871299e9d5f775000000000151ffffffff0180817dcb00000000232103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba4ac0000000001000000018da38b434fba82d66052af74fc5e4e94301b114d9bc03f819dc876398404c8b4010000006c493046022100fe738b7580dc5fb5168e51fc61b5aed211125eb71068031009a22d9bbad752c5022100be5086baa384d40bcab0fa586e4f728397388d86e18b66cc417dc4f7fa4f9878012103f233299455134caa2687bdf15cb0becdfb03bd0ff2ff38e65ec6b7834295c34fffffffff022ebc1400000000001976a9147779b7fba1c1e06b717069b80ca170e8b04458a488ac9879c40f000000001976a9142a0307cd925dbb66b534c4db33003dd18c57015788ac0000000001000000026139a62e3422a602de36c873a225c1d3ca5aeee598539ceecb9f0dc8d1ad0f83010000006b483045022100ad9f32b4a0a2ddc19b5a74eba78123e57616f1b3cfd72ce68c03ea35a3dda1f002200dbd22aa6da17213df5e70dfc3b2611d40f70c98ed9626aa5e2cde9d97461f0a012103ddb295d2f1e8319187738fb4b230fdd9aa29d0e01647f69f6d770b9ab24eea90ffffffff983c82c87cf020040d671956525014d5c2b28c6d948c85e1a522362c0059eeae010000006b4830450221009ca544274c786d30a5d5d25e17759201ea16d3aedddf0b9e9721246f7ef6b32e02202cfa5564b6e87dfd9fd98957820e4d4e6238baeb0f65fe305d91506bb13f5f4f012103c99113deac0d5d044e3ac0346abc02501542af8c8d3759f1382c72ff84e704f7ffffffff02c0c62d00000000001976a914ae19d27efe12f5a886dc79af37ad6805db6f922d88ac70ce2000000000001976a9143b8d051d37a07ea1042067e93efe63dbf73920b988ac000000000100000002be566e8cd9933f0c75c4a82c027f7d0c544d5c101d0607ef6ae5d07b98e7f1dc000000006b483045022036a8cdfd5ea7ebc06c2bfb6e4f942bbf9a1caeded41680d11a3a9f5d8284abad022100cacb92a5be3f39e8bc14db1710910ef7b395fa1e18f45d41c28d914fcdde33be012102bf59abf110b5131fae0a3ce1ec379329b4c896a6ae5d443edb68529cc2bc7816ffffffff96cf67645b76ceb23fe922874847456a15feee1655082ff32d25a6bf2c0dfc90000000006a47304402203471ca2001784a5ac0abab583581f2613523da47ec5f53df833c117b5abd81500220618a2847723d57324f2984678db556dbca1a72230fc7e39df04c2239942ba942012102925c9794fd7bb9f8b29e207d5fc491b1150135a21f505041858889fa4edf436fffffffff026c840f00000000001976a914797fb8777d7991d8284d88bfd421ce520f0f843188ac00ca9a3b000000001976a9146d10f3f592699265d10b106eda37c3ce793f7a8588ac00000000",["","","","76a9142903b138c24be9e070b3e73ec495d77a204615e788ac","76a91433a1941fd9a37b9821d376f5a51bd4b52fa50e2888ac","76a914e4374e8155d0865742ca12b8d4d14d41b57d682f88ac","76a914001fa7459a6cfc64bdc178ba7e7a21603bb2568f88ac","76a914f6039952bc2b307aeec5371bfb96b66078ec17f688ac"],"b109139671dbedc2b6fcd499a5480a7461ae458af8ff9411d819aa64ba6995d1","0db414c859a07e8205876354a210a75042d0463404913d61a8e068e58a3ae2aa080026","a0af77e0a7ed20ea78d2def3200cc24f08217dcd51755c7c7feb0e2ba8316c2d","Tx spends from empty output script"],
-[926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"da49977ba1ee0d620a2c4f8f646b03cd0d230f5c6c994722e3ba884889f0be1a","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","4cd9dd007a325199102f1fc0b7d77ca25ee3c84d46018c4353ecfcb56c0d3e7a","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"],
-[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"e9d729b72d533c29abe5276d5cf6c152f3723f10efe000b1e0c9ca5265a8beb6","010c0b40","e6137ae5a8424c40da1e5023c16975cc97b09300b4c050e6b1c713add3836c40","Coinbase tx has unparseable output script"],
-[1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"a4a4d6c6034da8aa06f01fe71f1fffbd79e032006b07f6c7a2c60a66aa310c01","0385acb4f0fe889ef0","3588f34fbbc11640f9ed40b2a66a4e096215d50389691309c1dac74d4268aa81","Includes witness data"]
+[180480,"00000000fd3ceb2404ff07a785c7fdcc76619edc8ed61bd25134eaa22084366a","020000006058aa080a655aa991a444bd7d1f2defd9a3bbe68aabb69030cf3b4e00000000d2e826bfd7ef0beaa891a7eedbc92cd6a544a6cb61c7bdaa436762eb2123ef9790f5f552ffff001d0002c90f0501000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0300c102024608062f503253482fffffffff01c0c6072a01000000232102e769e60137a4df6b0df8ebd387cca44c4c57ae74cc0114a8e8317c8f3bfd85e9ac00000000010000000381a0802911a01ffb025c4dea0bc77963e8c1bb46313b71164c53f72f37fe5248010000000151ffffffffc904b267833d215e2128bd9575242232ac2bc311550c7fc1f0ef6f264b40d14c010000000151ffffffffdf0915666649dba81886519c531649b7b02180b4af67d6885e871299e9d5f775000000000151ffffffff0180817dcb00000000232103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba4ac0000000001000000018da38b434fba82d66052af74fc5e4e94301b114d9bc03f819dc876398404c8b4010000006c493046022100fe738b7580dc5fb5168e51fc61b5aed211125eb71068031009a22d9bbad752c5022100be5086baa384d40bcab0fa586e4f728397388d86e18b66cc417dc4f7fa4f9878012103f233299455134caa2687bdf15cb0becdfb03bd0ff2ff38e65ec6b7834295c34fffffffff022ebc1400000000001976a9147779b7fba1c1e06b717069b80ca170e8b04458a488ac9879c40f000000001976a9142a0307cd925dbb66b534c4db33003dd18c57015788ac0000000001000000026139a62e3422a602de36c873a225c1d3ca5aeee598539ceecb9f0dc8d1ad0f83010000006b483045022100ad9f32b4a0a2ddc19b5a74eba78123e57616f1b3cfd72ce68c03ea35a3dda1f002200dbd22aa6da17213df5e70dfc3b2611d40f70c98ed9626aa5e2cde9d97461f0a012103ddb295d2f1e8319187738fb4b230fdd9aa29d0e01647f69f6d770b9ab24eea90ffffffff983c82c87cf020040d671956525014d5c2b28c6d948c85e1a522362c0059eeae010000006b4830450221009ca544274c786d30a5d5d25e17759201ea16d3aedddf0b9e9721246f7ef6b32e02202cfa5564b6e87dfd9fd98957820e4d4e6238baeb0f65fe305d91506bb13f5f4f012103c99113deac0d5d044e3ac0346abc02501542af8c8d3759f1382c72ff84e704f7ffffffff02c0c62d00000000001976a914ae19d27efe12f5a886dc79af37ad6805db6f922d88ac70ce2000000000001976a9143b8d051d37a07ea1042067e93efe63dbf73920b988ac000000000100000002be566e8cd9933f0c75c4a82c027f7d0c544d5c101d0607ef6ae5d07b98e7f1dc000000006b483045022036a8cdfd5ea7ebc06c2bfb6e4f942bbf9a1caeded41680d11a3a9f5d8284abad022100cacb92a5be3f39e8bc14db1710910ef7b395fa1e18f45d41c28d914fcdde33be012102bf59abf110b5131fae0a3ce1ec379329b4c896a6ae5d443edb68529cc2bc7816ffffffff96cf67645b76ceb23fe922874847456a15feee1655082ff32d25a6bf2c0dfc90000000006a47304402203471ca2001784a5ac0abab583581f2613523da47ec5f53df833c117b5abd81500220618a2847723d57324f2984678db556dbca1a72230fc7e39df04c2239942ba942012102925c9794fd7bb9f8b29e207d5fc491b1150135a21f505041858889fa4edf436fffffffff026c840f00000000001976a914797fb8777d7991d8284d88bfd421ce520f0f843188ac00ca9a3b000000001976a9146d10f3f592699265d10b106eda37c3ce793f7a8588ac00000000",["","","","76a9142903b138c24be9e070b3e73ec495d77a204615e788ac","76a91433a1941fd9a37b9821d376f5a51bd4b52fa50e2888ac","76a914e4374e8155d0865742ca12b8d4d14d41b57d682f88ac","76a914001fa7459a6cfc64bdc178ba7e7a21603bb2568f88ac","76a914f6039952bc2b307aeec5371bfb96b66078ec17f688ac"],"d34ef98386f413769502808d4bac5f20f8dfd5bffc9eedafaa71de0eb1f01489","0db414c859a07e8205876354a210a75042d0463404913d61a8e068e58a3ae2aa080026","c582d51c0ca365e3fcf36c51cb646d7f83a67e867cb4743fd2128e3e022b700c","Tx spends from empty output script"],
+[926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"8f13b9a9c85611635b47906c3053ac53cfcec7211455d4cb0d63dc9acc13d472","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","546c574a0472144bcaf9b6aeabf26372ad87c7af7d1ee0dbfae5e099abeae49c","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"],
+[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"fe4d230dbb0f4fec9bed23a5283e08baf996e3f32b93f52c7de1f641ddfd04ad","010c0b40","0965a544743bbfa36f254446e75630c09404b3d164a261892372977538928ed5","Coinbase tx has unparseable output script"],
+[1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"31d66d516a9eda7de865df29f6ef6cb8e4bf9309e5dac899968a9a62a5df61e3","0385acb4f0fe889ef0","4e6d564c2a2452065c205dd7eb2791124e0c4e0dbb064c410c24968572589dec","Includes witness data"],
+[1414221,"0000000000000027b2b3b3381f114f674f481544ff2be37ae3788d7e078383b1","000000204ea88307a7959d8207968f152bedca5a93aefab253f1fb2cfb032a400000000070cebb14ec6dbc27a9dfd066d9849a4d3bac5f674665f73a5fe1de01a022a0c851fda85bf05f4c19a779d1450102000000010000000000000000000000000000000000000000000000000000000000000000ffffffff18034d94154d696e6572476174653030310d000000f238f401ffffffff01c817a804000000000000000000",[],"5e5e12d90693c8e936f01847859404c67482439681928353ca1296982042864e","00","021e8882ef5a0ed932edeebbecfeda1d7ce528ec7b3daa27641acf1189d7b5dc","Empty data"]
]
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index 94e8c95345..efcadd51fc 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <dbwrapper.h>
#include <uint256.h>
-#include <random.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
+#include <util/memory.h>
#include <memory>
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = SetDataDir(std::string("dbwrapper").append(obfuscate ? "_true" : "_false"));
+ fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'k';
uint256 in = InsecureRand256();
@@ -47,7 +47,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = SetDataDir(std::string("dbwrapper_batch").append(obfuscate ? "_true" : "_false"));
+ fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_batch_obfuscate_true" : "dbwrapper_batch_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
char key = 'i';
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
{
// Perform tests both obfuscated and non-obfuscated.
for (const bool obfuscate : {false, true}) {
- fs::path ph = SetDataDir(std::string("dbwrapper_iterator").append(obfuscate ? "_true" : "_false"));
+ fs::path ph = GetDataDir() / (obfuscate ? "dbwrapper_iterator_obfuscate_true" : "dbwrapper_iterator_obfuscate_false");
CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate);
// The two keys are intentionally chosen for ordering
@@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = SetDataDir("existing_data_no_obfuscate");
+ fs::path ph = GetDataDir() / "existing_data_no_obfuscate";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate)
BOOST_AUTO_TEST_CASE(existing_data_reindex)
{
// We're going to share this fs::path between two wrappers
- fs::path ph = SetDataDir("existing_data_reindex");
+ fs::path ph = GetDataDir() / "existing_data_reindex";
create_directories(ph);
// Set up a non-obfuscated wrapper to write some initial data.
@@ -199,7 +199,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex)
BOOST_AUTO_TEST_CASE(iterator_ordering)
{
- fs::path ph = SetDataDir("iterator_ordering");
+ fs::path ph = GetDataDir() / "iterator_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<256; ++x) {
uint8_t key = x;
@@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(iterator_string_ordering)
{
char buf[10];
- fs::path ph = SetDataDir("iterator_string_ordering");
+ fs::path ph = GetDataDir() / "iterator_string_ordering";
CDBWrapper dbw(ph, (1 << 20), true, false, false);
for (int x=0x00; x<10; ++x) {
for (int y = 0; y < 10; y++) {
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index e5d62a3ab2..93883d1d98 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.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.
@@ -9,13 +9,14 @@
#include <keystore.h>
#include <net.h>
#include <net_processing.h>
-#include <pow.h>
#include <script/sign.h>
#include <serialize.h>
+#include <util/memory.h>
#include <util/system.h>
+#include <util/time.h>
#include <validation.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <stdint.h>
@@ -90,8 +91,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// This test requires that we have a chain with non-zero work.
{
LOCK(cs_main);
- BOOST_CHECK(chainActive.Tip() != nullptr);
- BOOST_CHECK(chainActive.Tip()->nChainWork > 0);
+ BOOST_CHECK(::ChainActive().Tip() != nullptr);
+ BOOST_CHECK(::ChainActive().Tip()->nChainWork > 0);
}
// Test starts here
@@ -381,7 +382,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vin[0].scriptSig << OP_1;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
+ tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
AddOrphanTx(MakeTransactionRef(tx), i);
}
@@ -397,7 +398,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vin[0].prevout.hash = txPrev->GetHash();
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
+ tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL));
AddOrphanTx(MakeTransactionRef(tx), i);
@@ -411,7 +412,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
CMutableTransaction tx;
tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT;
- tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
+ tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
tx.vin.resize(2777);
for (unsigned int j = 0; j < tx.vin.size(); j++)
{
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index ff2b8d4fc9..f5bda7d5e6 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
@@ -6,7 +6,7 @@
#include <string>
#include <script/sign.h>
#include <script/standard.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
#include <script/descriptor.h>
#include <util/strencodings.h>
@@ -154,8 +154,8 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
// Test whether the observed key path is present in the 'paths' variable (which contains expected, unobserved paths),
// and then remove it from that set.
for (const auto& origin : script_provider.origins) {
- BOOST_CHECK_MESSAGE(paths.count(origin.second.path), "Unexpected key path: " + prv);
- left_paths.erase(origin.second.path);
+ BOOST_CHECK_MESSAGE(paths.count(origin.second.second.path), "Unexpected key path: " + prv);
+ left_paths.erase(origin.second.second.path);
}
}
}
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index 079a09f8f9..740d805cce 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -2,8 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <clientversion.h>
#include <flatfile.h>
-#include <test/test_bitcoin.h>
+#include <streams.h>
+#include <test/setup_common.h>
+#include <util/system.h>
#include <boost/test/unit_test.hpp>
@@ -11,7 +14,7 @@ BOOST_FIXTURE_TEST_SUITE(flatfile_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(flatfile_filename)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFilePos pos(456, 789);
@@ -24,7 +27,7 @@ BOOST_AUTO_TEST_CASE(flatfile_filename)
BOOST_AUTO_TEST_CASE(flatfile_open)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFileSeq seq(data_dir, "a", 16 * 1024);
std::string line1("A purely peer-to-peer version of electronic cash would allow online "
@@ -85,7 +88,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
BOOST_AUTO_TEST_CASE(flatfile_allocate)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
@@ -105,7 +108,7 @@ BOOST_AUTO_TEST_CASE(flatfile_allocate)
BOOST_AUTO_TEST_CASE(flatfile_flush)
{
- auto data_dir = SetDataDir("flatfile_test");
+ const auto data_dir = GetDataDir();
FlatFileSeq seq(data_dir, "a", 100);
bool out_of_space;
diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp
index 93aee10bb7..6d5a6641f0 100644
--- a/src/test/fs_tests.cpp
+++ b/src/test/fs_tests.cpp
@@ -1,9 +1,10 @@
-// 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.
//
#include <fs.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
+#include <util/system.h>
#include <boost/test/unit_test.hpp>
@@ -11,7 +12,7 @@ BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(fsbridge_fstream)
{
- fs::path tmpfolder = SetDataDir("fsbridge_fstream");
+ fs::path tmpfolder = GetDataDir();
// tmpfile1 should be the same as tmpfile2
fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃";
fs::path tmpfile2 = tmpfolder / L"fs_tests_₿_🏃";
diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp
index 859fba0bdc..9364ac4a32 100644
--- a/src/test/fuzz/deserialize.cpp
+++ b/src/test/fuzz/deserialize.cpp
@@ -1,7 +1,8 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <addrdb.h>
#include <addrman.h>
#include <blockencodings.h>
#include <chain.h>
@@ -11,8 +12,6 @@
#include <net.h>
#include <primitives/block.h>
#include <protocol.h>
-#include <pubkey.h>
-#include <script/script.h>
#include <streams.h>
#include <undo.h>
#include <version.h>
@@ -20,8 +19,6 @@
#include <stdint.h>
#include <unistd.h>
-#include <algorithm>
-#include <memory>
#include <vector>
#include <test/fuzz/fuzz.h>
diff --git a/src/test/fuzz/fuzz.h b/src/test/fuzz/fuzz.h
index ad62a5faf0..4e009d9b54 100644
--- a/src/test/fuzz/fuzz.h
+++ b/src/test/fuzz/fuzz.h
@@ -5,13 +5,10 @@
#ifndef BITCOIN_TEST_FUZZ_FUZZ_H
#define BITCOIN_TEST_FUZZ_FUZZ_H
-#include <functional>
#include <stdint.h>
#include <vector>
-const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
-
void test_one_input(std::vector<uint8_t> buffer);
#endif // BITCOIN_TEST_FUZZ_FUZZ_H
diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp
index 2c0bfa360c..9b90d66755 100644
--- a/src/test/fuzz/script_flags.cpp
+++ b/src/test/fuzz/script_flags.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <script/interpreter.h>
-#include <script/script.h>
#include <streams.h>
#include <version.h>
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index 8048238028..8a42344642 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <util/strencodings.h>
#include <util/system.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <string>
#include <vector>
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index e8e5040855..d91fcb0034 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -1,13 +1,12 @@
-// Copyright (c) 2013-2018 The Bitcoin Core developers
+// Copyright (c) 2013-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 <clientversion.h>
#include <crypto/siphash.h>
#include <hash.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
-
-#include <vector>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp
index bf295042de..e924f27d1b 100644
--- a/src/test/key_io_tests.cpp
+++ b/src/test/key_io_tests.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.
@@ -9,7 +9,7 @@
#include <key_io.h>
#include <script/script.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/key_properties.cpp b/src/test/key_properties.cpp
index c564b4eab8..abcfc4547b 100644
--- a/src/test/key_properties.cpp
+++ b/src/test/key_properties.cpp
@@ -1,15 +1,11 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
#include <key.h>
-#include <base58.h>
-#include <script/script.h>
#include <uint256.h>
#include <util/system.h>
-#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
-#include <string>
+#include <test/setup_common.h>
#include <vector>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index a768b4bcbd..3e99dcaa40 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -1,15 +1,14 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <key.h>
#include <key_io.h>
-#include <script/script.h>
#include <uint256.h>
#include <util/system.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <string>
#include <vector>
@@ -68,10 +67,10 @@ BOOST_AUTO_TEST_CASE(key_test1)
BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
- BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(pubkey1.GetID()));
- BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(pubkey2.GetID()));
- BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(pubkey1C.GetID()));
- BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(pubkey2C.GetID()));
+ BOOST_CHECK(DecodeDestination(addr1) == CTxDestination(PKHash(pubkey1)));
+ BOOST_CHECK(DecodeDestination(addr2) == CTxDestination(PKHash(pubkey2)));
+ BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C)));
+ BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C)));
for (int n=0; n<16; n++)
{
@@ -188,4 +187,36 @@ BOOST_AUTO_TEST_CASE(key_signature_tests)
BOOST_CHECK(found_small);
}
+BOOST_AUTO_TEST_CASE(key_key_negation)
+{
+ // create a dummy hash for signature comparison
+ unsigned char rnd[8];
+ std::string str = "Bitcoin key verification\n";
+ GetRandBytes(rnd, sizeof(rnd));
+ uint256 hash;
+ CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin());
+
+ // import the static test key
+ CKey key = DecodeSecret(strSecret1C);
+
+ // create a signature
+ std::vector<unsigned char> vch_sig;
+ std::vector<unsigned char> vch_sig_cmp;
+ key.Sign(hash, vch_sig);
+
+ // negate the key twice
+ BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
+ key.Negate();
+ // after the first negation, the signature must be different
+ key.Sign(hash, vch_sig_cmp);
+ BOOST_CHECK(vch_sig_cmp != vch_sig);
+ BOOST_CHECK(key.GetPubKey().data()[0] == 0x02);
+ key.Negate();
+ // after the second negation, we should have the original key and thus the
+ // same signature
+ key.Sign(hash, vch_sig_cmp);
+ BOOST_CHECK(vch_sig_cmp == vch_sig);
+ BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
index 0788f75b04..00b36f51fb 100644
--- a/src/test/limitedmap_tests.cpp
+++ b/src/test/limitedmap_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <limitedmap.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/main.cpp b/src/test/main.cpp
new file mode 100644
index 0000000000..ff3f36b561
--- /dev/null
+++ b/src/test/main.cpp
@@ -0,0 +1,7 @@
+// 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.
+
+#define BOOST_TEST_MODULE Bitcoin Core Test Suite
+
+#include <boost/test/unit_test.hpp>
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 23ca9d89ae..c6a3de2285 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -1,15 +1,15 @@
-// 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.
#include <policy/policy.h>
#include <txmempool.h>
#include <util/system.h>
+#include <util/time.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
-#include <list>
#include <vector>
BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index 4cdf0f003e..1684258c9f 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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 <consensus/merkle.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp
index 4978593285..eac43471c7 100644
--- a/src/test/merkleblock_tests.cpp
+++ b/src/test/merkleblock_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <merkleblock.h>
#include <uint256.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 5ba1df2ec2..4bd40687a6 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.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.
@@ -7,18 +7,17 @@
#include <consensus/consensus.h>
#include <consensus/merkle.h>
#include <consensus/tx_verify.h>
-#include <consensus/validation.h>
-#include <validation.h>
#include <miner.h>
#include <policy/policy.h>
-#include <pubkey.h>
#include <script/standard.h>
#include <txmempool.h>
#include <uint256.h>
-#include <util/system.h>
#include <util/strencodings.h>
+#include <util/system.h>
+#include <util/time.h>
+#include <validation.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <memory>
@@ -82,11 +81,11 @@ struct {
{2, 0xbbbeb305}, {2, 0xfe1c810a},
};
-static CBlockIndex CreateBlockIndex(int nHeight)
+static CBlockIndex CreateBlockIndex(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
CBlockIndex index;
index.nHeight = nHeight;
- index.pprev = chainActive.Tip();
+ index.pprev = ::ChainActive().Tip();
return index;
}
@@ -231,17 +230,17 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
{
LOCK(cs_main);
pblock->nVersion = 1;
- pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
+ pblock->nTime = ::ChainActive().Tip()->GetMedianTimePast()+1;
CMutableTransaction txCoinbase(*pblock->vtx[0]);
txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
- txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
+ txCoinbase.vin[0].scriptSig.push_back(::ChainActive().Height());
txCoinbase.vout.resize(1); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
txCoinbase.vout[0].scriptPubKey = CScript();
pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
if (txFirst.size() == 0)
- baseheight = chainActive.Height();
+ baseheight = ::ChainActive().Height();
if (txFirst.size() < 4)
txFirst.push_back(pblock->vtx[0]);
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
@@ -367,29 +366,29 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
mempool.clear();
// subsidy changing
- int nHeight = chainActive.Height();
+ int nHeight = ::ChainActive().Height();
// Create an actual 209999-long block chain (without valid blocks).
- while (chainActive.Tip()->nHeight < 209999) {
- CBlockIndex* prev = chainActive.Tip();
+ while (::ChainActive().Tip()->nHeight < 209999) {
+ CBlockIndex* prev = ::ChainActive().Tip();
CBlockIndex* next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
- chainActive.SetTip(next);
+ ::ChainActive().SetTip(next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
- while (chainActive.Tip()->nHeight < 210000) {
- CBlockIndex* prev = chainActive.Tip();
+ while (::ChainActive().Tip()->nHeight < 210000) {
+ CBlockIndex* prev = ::ChainActive().Tip();
CBlockIndex* next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256());
pcoinsTip->SetBestBlock(next->GetBlockHash());
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
- chainActive.SetTip(next);
+ ::ChainActive().SetTip(next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
@@ -399,7 +398,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY-LOWFEE;
script = CScript() << OP_0;
- tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script));
+ tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
hash = tx.GetHash();
mempool.addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
tx.vin[0].prevout.hash = hash;
@@ -412,16 +411,16 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
mempool.clear();
// Delete the dummy blocks again.
- while (chainActive.Tip()->nHeight > nHeight) {
- CBlockIndex* del = chainActive.Tip();
- chainActive.SetTip(del->pprev);
+ while (::ChainActive().Tip()->nHeight > nHeight) {
+ CBlockIndex* del = ::ChainActive().Tip();
+ ::ChainActive().SetTip(del->pprev);
pcoinsTip->SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del;
}
// non-final txs in mempool
- SetMockTime(chainActive.Tip()->GetMedianTimePast()+1);
+ SetMockTime(::ChainActive().Tip()->GetMedianTimePast()+1);
int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST;
// height map
std::vector<int> prevheights;
@@ -433,7 +432,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = txFirst[0]->GetHash(); // only 1 transaction
tx.vin[0].prevout.n = 0;
tx.vin[0].scriptSig = CScript() << OP_1;
- tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; // txFirst[0] is the 2nd block
+ tx.vin[0].nSequence = ::ChainActive().Tip()->nHeight + 1; // txFirst[0] is the 2nd block
prevheights[0] = baseheight + 1;
tx.vout.resize(1);
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
@@ -443,11 +442,11 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
mempool.addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
- BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Sequence locks pass on 2nd block
+ BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 2))); // Sequence locks pass on 2nd block
// relative time locked
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
- tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast()+1-chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block
+ tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((::ChainActive().Tip()->GetMedianTimePast()+1-::ChainActive()[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); // txFirst[1] is the 3rd block
prevheights[0] = baseheight + 2;
hash = tx.GetHash();
mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx));
@@ -455,36 +454,36 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
- chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
- BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later
+ ::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
+ BOOST_CHECK(SequenceLocks(CTransaction(tx), flags, &prevheights, CreateBlockIndex(::ChainActive().Tip()->nHeight + 1))); // Sequence locks pass 512 seconds later
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
- chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP
+ ::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime -= 512; //undo tricked MTP
// absolute height locked
tx.vin[0].prevout.hash = txFirst[2]->GetHash();
tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1;
prevheights[0] = baseheight + 3;
- tx.nLockTime = chainActive.Tip()->nHeight + 1;
+ tx.nLockTime = ::ChainActive().Tip()->nHeight + 1;
hash = tx.GetHash();
mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx));
BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass
- BOOST_CHECK(IsFinalTx(CTransaction(tx), chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); // Locktime passes on 2nd block
+ BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block
// absolute time locked
tx.vin[0].prevout.hash = txFirst[3]->GetHash();
- tx.nLockTime = chainActive.Tip()->GetMedianTimePast();
+ tx.nLockTime = ::ChainActive().Tip()->GetMedianTimePast();
prevheights.resize(1);
prevheights[0] = baseheight + 4;
hash = tx.GetHash();
mempool.addUnchecked(entry.Time(GetTime()).FromTx(tx));
BOOST_CHECK(!CheckFinalTx(CTransaction(tx), flags)); // Locktime fails
BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass
- BOOST_CHECK(IsFinalTx(CTransaction(tx), chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later
+ BOOST_CHECK(IsFinalTx(CTransaction(tx), ::ChainActive().Tip()->nHeight + 2, ::ChainActive().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later
// mempool-dependent transactions (not added)
tx.vin[0].prevout.hash = hash;
- prevheights[0] = chainActive.Tip()->nHeight + 1;
+ prevheights[0] = ::ChainActive().Tip()->nHeight + 1;
tx.nLockTime = 0;
tx.vin[0].nSequence = 0;
BOOST_CHECK(CheckFinalTx(CTransaction(tx), flags)); // Locktime passes
@@ -505,14 +504,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3U);
// However if we advance height by 1 and time by 512, all of them should be mined
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
- chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
- chainActive.Tip()->nHeight++;
- SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1);
+ ::ChainActive().Tip()->GetAncestor(::ChainActive().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
+ ::ChainActive().Tip()->nHeight++;
+ SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1);
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
- chainActive.Tip()->nHeight--;
+ ::ChainActive().Tip()->nHeight--;
SetMockTime(0);
mempool.clear();
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 8afe4b8a59..11e79937be 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.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.
@@ -9,9 +9,9 @@
#include <script/script_error.h>
#include <script/interpreter.h>
#include <script/sign.h>
-#include <script/ismine.h>
+#include <tinyformat.h>
#include <uint256.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index b4ae8e9765..fed65afdbf 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -1,16 +1,19 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <addrdb.h>
#include <addrman.h>
-#include <test/test_bitcoin.h>
+#include <clientversion.h>
+#include <test/setup_common.h>
#include <string>
#include <boost/test/unit_test.hpp>
-#include <hash.h>
#include <serialize.h>
#include <streams.h>
#include <net.h>
#include <netbase.h>
#include <chainparams.h>
+#include <util/memory.h>
#include <util/system.h>
#include <memory>
@@ -89,7 +92,6 @@ BOOST_AUTO_TEST_CASE(cnode_listen_port)
BOOST_AUTO_TEST_CASE(caddrdb_read)
{
- SetDataDir("caddrdb_read");
CAddrManUncorrupted addrmanUncorrupted;
addrmanUncorrupted.MakeDeterministic();
@@ -135,7 +137,6 @@ BOOST_AUTO_TEST_CASE(caddrdb_read)
BOOST_AUTO_TEST_CASE(caddrdb_read_corrupted)
{
- SetDataDir("caddrdb_read_corrupted");
CAddrManCorrupted addrmanCorrupted;
addrmanCorrupted.MakeDeterministic();
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 0d557cff13..86c0cecbf1 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <netbase.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <util/strencodings.h>
#include <string>
@@ -59,6 +59,7 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
BOOST_CHECK(ResolveIP("FC00::").IsRFC4193());
BOOST_CHECK(ResolveIP("2001::2").IsRFC4380());
BOOST_CHECK(ResolveIP("2001:10::").IsRFC4843());
+ BOOST_CHECK(ResolveIP("2001:20::").IsRFC7343());
BOOST_CHECK(ResolveIP("FE80::").IsRFC4862());
BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052());
BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index 5020192804..c5513ae9fa 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -9,7 +9,7 @@
#include <uint256.h>
#include <arith_uint256.h>
#include <version.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <vector>
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 7b274a1658..016a4f471b 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.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.
@@ -7,8 +7,9 @@
#include <txmempool.h>
#include <uint256.h>
#include <util/system.h>
+#include <util/time.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index 26cdc9bc5c..1123d4202c 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -1,13 +1,12 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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 <chain.h>
#include <chainparams.h>
#include <pow.h>
-#include <random.h>
#include <util/system.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index 7341389208..fc1f946bba 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -9,7 +9,7 @@
#include <serialize.h>
#include <streams.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -183,6 +183,26 @@ public:
pre_vector = pre_vector_alt;
}
+ void resize_uninitialized(realtype values) {
+ size_t r = values.size();
+ size_t s = real_vector.size() / 2;
+ if (real_vector.capacity() < s + r) {
+ real_vector.reserve(s + r);
+ }
+ real_vector.resize(s);
+ pre_vector.resize_uninitialized(s);
+ for (auto v : values) {
+ real_vector.push_back(v);
+ }
+ auto p = pre_vector.size();
+ pre_vector.resize_uninitialized(p + r);
+ for (auto v : values) {
+ pre_vector[p] = v;
+ ++p;
+ }
+ test();
+ }
+
~prevector_tester() {
BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
}
@@ -260,6 +280,14 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt)
if (InsecureRandBits(5) == 18) {
test.move();
}
+ if (InsecureRandBits(5) == 19) {
+ unsigned int num = 1 + (InsecureRandBits(4));
+ std::vector<int> values(num);
+ for (auto &v : values) {
+ v = InsecureRand32();
+ }
+ test.resize_uninitialized(values);
+ }
}
}
}
diff --git a/src/test/raii_event_tests.cpp b/src/test/raii_event_tests.cpp
index bdb411d53f..41ca8029e5 100644
--- a/src/test/raii_event_tests.cpp
+++ b/src/test/raii_event_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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.
@@ -12,9 +12,7 @@
#include <support/events.h>
-#include <test/test_bitcoin.h>
-
-#include <vector>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 8194070aba..e6fbe2355d 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -1,10 +1,10 @@
-// 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.
#include <random.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
index 91c76fda88..69db9dcf4e 100644
--- a/src/test/reverselock_tests.cpp
+++ b/src/test/reverselock_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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 <reverselock.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index ff48398925..5ae0812243 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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.
@@ -9,10 +9,8 @@
#include <core_io.h>
#include <init.h>
#include <interfaces/chain.h>
-#include <key_io.h>
-#include <netbase.h>
-
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
+#include <util/time.h>
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
@@ -31,10 +29,9 @@ UniValue CallRPC(std::string args)
request.strMethod = strMethod;
request.params = RPCConvertValues(strMethod, vArgs);
request.fHelp = false;
- BOOST_CHECK(tableRPC[strMethod]);
- rpcfn_type method = tableRPC[strMethod]->actor;
+ if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
try {
- UniValue result = (*method)(request);
+ UniValue result = tableRPC.execute(request);
return result;
}
catch (const UniValue& objError) {
diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp
index 8085a21928..891aa8e5c3 100644
--- a/src/test/sanity_tests.cpp
+++ b/src/test/sanity_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <compat/sanity.h>
#include <key.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 100d65b779..42242b962b 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <scheduler.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/thread.hpp>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index 3a2a11ef98..735b67c06e 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -1,18 +1,17 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <consensus/tx_verify.h>
-#include <core_io.h>
#include <key.h>
#include <keystore.h>
#include <validation.h>
#include <policy/policy.h>
#include <script/script.h>
#include <script/script_error.h>
+#include <policy/settings.h>
#include <script/sign.h>
-#include <script/ismine.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <vector>
@@ -68,14 +67,14 @@ BOOST_AUTO_TEST_CASE(sign)
// different keys, straight/P2SH, pubkey/pubkeyhash
CScript standardScripts[4];
standardScripts[0] << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
- standardScripts[1] = GetScriptForDestination(key[1].GetPubKey().GetID());
+ standardScripts[1] = GetScriptForDestination(PKHash(key[1].GetPubKey()));
standardScripts[2] << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
- standardScripts[3] = GetScriptForDestination(key[2].GetPubKey().GetID());
+ standardScripts[3] = GetScriptForDestination(PKHash(key[2].GetPubKey()));
CScript evalScripts[4];
for (int i = 0; i < 4; i++)
{
BOOST_CHECK(keystore.AddCScript(standardScripts[i]));
- evalScripts[i] = GetScriptForDestination(CScriptID(standardScripts[i]));
+ evalScripts[i] = GetScriptForDestination(ScriptHash(standardScripts[i]));
}
CMutableTransaction txFrom; // Funding transaction:
@@ -98,7 +97,6 @@ BOOST_AUTO_TEST_CASE(sign)
txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
- BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
}
for (int i = 0; i < 8; i++)
{
@@ -130,7 +128,7 @@ BOOST_AUTO_TEST_CASE(norecurse)
CScript invalidAsScript;
invalidAsScript << OP_INVALIDOPCODE << OP_INVALIDOPCODE;
- CScript p2sh = GetScriptForDestination(CScriptID(invalidAsScript));
+ CScript p2sh = GetScriptForDestination(ScriptHash(invalidAsScript));
CScript scriptSig;
scriptSig << Serialize(invalidAsScript);
@@ -141,7 +139,7 @@ BOOST_AUTO_TEST_CASE(norecurse)
// Try to recur, and verification should succeed because
// the inner HASH160 <> EQUAL should only check the hash:
- CScript p2sh2 = GetScriptForDestination(CScriptID(p2sh));
+ CScript p2sh2 = GetScriptForDestination(ScriptHash(p2sh));
CScript scriptSig2;
scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh);
@@ -164,7 +162,7 @@ BOOST_AUTO_TEST_CASE(set)
}
CScript inner[4];
- inner[0] = GetScriptForDestination(key[0].GetPubKey().GetID());
+ inner[0] = GetScriptForDestination(PKHash(key[0].GetPubKey()));
inner[1] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
inner[2] = GetScriptForMultisig(1, std::vector<CPubKey>(keys.begin(), keys.begin()+2));
inner[3] = GetScriptForMultisig(2, std::vector<CPubKey>(keys.begin(), keys.begin()+3));
@@ -172,7 +170,7 @@ BOOST_AUTO_TEST_CASE(set)
CScript outer[4];
for (int i = 0; i < 4; i++)
{
- outer[i] = GetScriptForDestination(CScriptID(inner[i]));
+ outer[i] = GetScriptForDestination(ScriptHash(inner[i]));
BOOST_CHECK(keystore.AddCScript(inner[i]));
}
@@ -195,7 +193,6 @@ BOOST_AUTO_TEST_CASE(set)
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1*CENT;
txTo[i].vout[0].scriptPubKey = inner[i];
- BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
}
for (int i = 0; i < 4; i++)
{
@@ -252,7 +249,7 @@ BOOST_AUTO_TEST_CASE(switchover)
CScript scriptSig;
scriptSig << Serialize(notValid);
- CScript fund = GetScriptForDestination(CScriptID(notValid));
+ CScript fund = GetScriptForDestination(ScriptHash(notValid));
// Validation should succeed under old rules (hash is correct):
@@ -283,11 +280,11 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txFrom.vout.resize(7);
// First three are standard:
- CScript pay1 = GetScriptForDestination(key[0].GetPubKey().GetID());
+ CScript pay1 = GetScriptForDestination(PKHash(key[0].GetPubKey()));
BOOST_CHECK(keystore.AddCScript(pay1));
CScript pay1of3 = GetScriptForMultisig(1, keys);
- txFrom.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(pay1)); // P2SH (OP_CHECKSIG)
+ txFrom.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(pay1)); // P2SH (OP_CHECKSIG)
txFrom.vout[0].nValue = 1000;
txFrom.vout[1].scriptPubKey = pay1; // ordinary OP_CHECKSIG
txFrom.vout[1].nValue = 2000;
@@ -302,7 +299,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
oneAndTwo << OP_2 << ToByteVector(key[3].GetPubKey()) << ToByteVector(key[4].GetPubKey()) << ToByteVector(key[5].GetPubKey());
oneAndTwo << OP_3 << OP_CHECKMULTISIG;
BOOST_CHECK(keystore.AddCScript(oneAndTwo));
- txFrom.vout[3].scriptPubKey = GetScriptForDestination(CScriptID(oneAndTwo));
+ txFrom.vout[3].scriptPubKey = GetScriptForDestination(ScriptHash(oneAndTwo));
txFrom.vout[3].nValue = 4000;
// vout[4] is max sigops:
@@ -311,24 +308,24 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
fifteenSigops << ToByteVector(key[i%3].GetPubKey());
fifteenSigops << OP_15 << OP_CHECKMULTISIG;
BOOST_CHECK(keystore.AddCScript(fifteenSigops));
- txFrom.vout[4].scriptPubKey = GetScriptForDestination(CScriptID(fifteenSigops));
+ txFrom.vout[4].scriptPubKey = GetScriptForDestination(ScriptHash(fifteenSigops));
txFrom.vout[4].nValue = 5000;
// vout[5/6] are non-standard because they exceed MAX_P2SH_SIGOPS
CScript sixteenSigops; sixteenSigops << OP_16 << OP_CHECKMULTISIG;
BOOST_CHECK(keystore.AddCScript(sixteenSigops));
- txFrom.vout[5].scriptPubKey = GetScriptForDestination(CScriptID(sixteenSigops));
+ txFrom.vout[5].scriptPubKey = GetScriptForDestination(ScriptHash(sixteenSigops));
txFrom.vout[5].nValue = 5000;
CScript twentySigops; twentySigops << OP_CHECKMULTISIG;
BOOST_CHECK(keystore.AddCScript(twentySigops));
- txFrom.vout[6].scriptPubKey = GetScriptForDestination(CScriptID(twentySigops));
+ txFrom.vout[6].scriptPubKey = GetScriptForDestination(ScriptHash(twentySigops));
txFrom.vout[6].nValue = 6000;
AddCoins(coins, CTransaction(txFrom), 0);
CMutableTransaction txTo;
txTo.vout.resize(1);
- txTo.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());
+ txTo.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey()));
txTo.vin.resize(5);
for (int i = 0; i < 5; i++)
@@ -351,7 +348,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CMutableTransaction txToNonStd1;
txToNonStd1.vout.resize(1);
- txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());
+ txToNonStd1.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey()));
txToNonStd1.vout[0].nValue = 1000;
txToNonStd1.vin.resize(1);
txToNonStd1.vin[0].prevout.n = 5;
@@ -363,7 +360,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
CMutableTransaction txToNonStd2;
txToNonStd2.vout.resize(1);
- txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(key[1].GetPubKey().GetID());
+ txToNonStd2.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[1].GetPubKey()));
txToNonStd2.vout[0].nValue = 1000;
txToNonStd2.vin.resize(1);
txToNonStd2.vin[0].prevout.n = 6;
diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp
index bde82018c7..046b220e3f 100644
--- a/src/test/script_standard_tests.cpp
+++ b/src/test/script_standard_tests.cpp
@@ -1,14 +1,12 @@
-// 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.
#include <key.h>
#include <keystore.h>
-#include <script/ismine.h>
#include <script/script.h>
-#include <script/script_error.h>
#include <script/standard.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -179,23 +177,23 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
s.clear();
s << ToByteVector(pubkey) << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<CKeyID>(&address) &&
- *boost::get<CKeyID>(&address) == pubkey.GetID());
+ BOOST_CHECK(boost::get<PKHash>(&address) &&
+ *boost::get<PKHash>(&address) == PKHash(pubkey));
// TX_PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
- BOOST_CHECK(boost::get<CKeyID>(&address) &&
- *boost::get<CKeyID>(&address) == pubkey.GetID());
+ BOOST_CHECK(boost::get<PKHash>(&address) &&
+ *boost::get<PKHash>(&address) == PKHash(pubkey));
// TX_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<CScriptID>(&address) &&
- *boost::get<CScriptID>(&address) == CScriptID(redeemScript));
+ BOOST_CHECK(boost::get<ScriptHash>(&address) &&
+ *boost::get<ScriptHash>(&address) == ScriptHash(redeemScript));
// TX_MULTISIG
s.clear();
@@ -255,8 +253,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
- *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+ BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
+ *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
// TX_PUBKEYHASH
s.clear();
@@ -265,8 +263,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
- *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
+ BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
+ *boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
// TX_SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
@@ -276,8 +274,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
- BOOST_CHECK(boost::get<CScriptID>(&addresses[0]) &&
- *boost::get<CScriptID>(&addresses[0]) == CScriptID(redeemScript));
+ BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) &&
+ *boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
// TX_MULTISIG
s.clear();
@@ -289,10 +287,10 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
BOOST_CHECK_EQUAL(addresses.size(), 2U);
BOOST_CHECK_EQUAL(nRequired, 2);
- BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
- *boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
- BOOST_CHECK(boost::get<CKeyID>(&addresses[1]) &&
- *boost::get<CKeyID>(&addresses[1]) == pubkeys[1].GetID());
+ 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]));
// TX_NULL_DATA
s.clear();
@@ -311,17 +309,17 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
CScript expected, result;
- // CKeyID
+ // PKHash
expected.clear();
expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
- result = GetScriptForDestination(pubkeys[0].GetID());
+ result = GetScriptForDestination(PKHash(pubkeys[0]));
BOOST_CHECK(result == expected);
// CScriptID
CScript redeemScript(result);
expected.clear();
expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
- result = GetScriptForDestination(CScriptID(redeemScript));
+ result = GetScriptForDestination(ScriptHash(redeemScript));
BOOST_CHECK(result == expected);
// CNoDestination
@@ -372,364 +370,4 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
BOOST_CHECK(result == expected);
}
-BOOST_AUTO_TEST_CASE(script_standard_IsMine)
-{
- CKey keys[2];
- CPubKey pubkeys[2];
- for (int i = 0; i < 2; i++) {
- keys[i].MakeNewKey(true);
- pubkeys[i] = keys[i].GetPubKey();
- }
-
- CKey uncompressedKey;
- uncompressedKey.MakeNewKey(false);
- CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
-
- CScript scriptPubKey;
- isminetype result;
-
- // P2PK compressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2PK uncompressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2PKH compressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForDestination(pubkeys[0].GetID());
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2PKH uncompressed
- {
- CBasicKeyStore keystore;
- scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID());
-
- // Keystore does not have key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2SH
- {
- CBasicKeyStore keystore;
-
- CScript redeemScript = GetScriptForDestination(pubkeys[0].GetID());
- scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
-
- // Keystore does not have redeemScript or key
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has redeemScript but no key
- BOOST_CHECK(keystore.AddCScript(redeemScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has redeemScript and key
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // (P2PKH inside) P2SH inside P2SH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript redeemscript_inner = GetScriptForDestination(pubkeys[0].GetID());
- CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner));
- scriptPubKey = GetScriptForDestination(CScriptID(redeemscript));
-
- BOOST_CHECK(keystore.AddCScript(redeemscript));
- BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // (P2PKH inside) P2SH inside P2WSH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript redeemscript = GetScriptForDestination(pubkeys[0].GetID());
- CScript witnessscript = GetScriptForDestination(CScriptID(redeemscript));
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
-
- BOOST_CHECK(keystore.AddCScript(witnessscript));
- BOOST_CHECK(keystore.AddCScript(redeemscript));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2WPKH inside P2WSH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID()));
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
-
- BOOST_CHECK(keystore.AddCScript(witnessscript));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // (P2PKH inside) P2WSH inside P2WSH (invalid)
- {
- CBasicKeyStore keystore;
-
- CScript witnessscript_inner = GetScriptForDestination(pubkeys[0].GetID());
- CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
-
- BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
- BOOST_CHECK(keystore.AddCScript(witnessscript));
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- BOOST_CHECK(keystore.AddKey(keys[0]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2WPKH compressed
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID()));
-
- // Keystore implicitly has key and P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2WPKH uncompressed
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
-
- scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey.GetID()));
-
- // Keystore has key, but no P2SH redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has key and P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // scriptPubKey multisig
- {
- CBasicKeyStore keystore;
-
- scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
-
- // Keystore does not have any keys
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has 1/2 keys
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has 2/2 keys
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has 2/2 keys and the script
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2SH multisig
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
- scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
-
- // Keystore has no redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has redeemScript
- BOOST_CHECK(keystore.AddCScript(redeemScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2WSH multisig with compressed keys
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
-
- // Keystore has keys, but no witnessScript or P2SH redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys and witnessScript, but no P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(witnessScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys, witnessScript, P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // P2WSH multisig with uncompressed key
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(uncompressedKey));
- BOOST_CHECK(keystore.AddKey(keys[1]));
-
- CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
- scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
-
- // Keystore has keys, but no witnessScript or P2SH redeemScript
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys and witnessScript, but no P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(witnessScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys, witnessScript, P2SH redeemScript
- BOOST_CHECK(keystore.AddCScript(scriptPubKey));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // P2WSH multisig wrapped in P2SH
- {
- CBasicKeyStore keystore;
-
- CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
- CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
- scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
-
- // Keystore has no witnessScript, P2SH redeemScript, or keys
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has witnessScript and P2SH redeemScript, but no keys
- BOOST_CHECK(keystore.AddCScript(redeemScript));
- BOOST_CHECK(keystore.AddCScript(witnessScript));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
-
- // Keystore has keys, witnessScript, P2SH redeemScript
- BOOST_CHECK(keystore.AddKey(keys[0]));
- BOOST_CHECK(keystore.AddKey(keys[1]));
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
- }
-
- // OP_RETURN
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // witness unspendable
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // witness unknown
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-
- // Nonstandard
- {
- CBasicKeyStore keystore;
- BOOST_CHECK(keystore.AddKey(keys[0]));
-
- scriptPubKey.clear();
- scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
-
- result = IsMine(keystore, scriptPubKey);
- BOOST_CHECK_EQUAL(result, ISMINE_NO);
- }
-}
-
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 87c3e74df0..ae903df0ad 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.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.
@@ -12,14 +12,14 @@
#include <script/sign.h>
#include <util/system.h>
#include <util/strencodings.h>
-#include <test/test_bitcoin.h>
-#include <rpc/server.h>
+#include <test/setup_common.h>
+#include <rpc/util.h>
+#include <streams.h>
#if defined(HAVE_CONSENSUS_LIB)
#include <script/bitcoinconsensus.h>
#endif
-#include <fstream>
#include <stdint.h>
#include <string>
#include <vector>
@@ -1211,7 +1211,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_CHECK(keystore.AddKey(key));
}
- CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
+ CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(PKHash(keys[0].GetPubKey())));
CMutableTransaction txTo = BuildSpendingTransaction(CScript(), CScriptWitness(), CTransaction(txFrom));
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
SignatureData scriptSig;
@@ -1237,7 +1237,7 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
// P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
BOOST_CHECK(keystore.AddCScript(pkSingle));
- scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
+ scriptPubKey = GetScriptForDestination(ScriptHash(pkSingle));
BOOST_CHECK(SignSignature(keystore, CTransaction(txFrom), txTo, 0, SIGHASH_ALL));
scriptSig = DataFromTransaction(txTo, 0, txFrom.vout[0]);
combined = CombineSignatures(txFrom.vout[0], txTo, scriptSig, empty);
diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h
index e763b64275..2c89a18331 100644
--- a/src/test/scriptnum10.h
+++ b/src/test/scriptnum10.h
@@ -6,7 +6,6 @@
#ifndef BITCOIN_TEST_SCRIPTNUM10_H
#define BITCOIN_TEST_SCRIPTNUM10_H
-#include <algorithm>
#include <limits>
#include <stdexcept>
#include <stdint.h>
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index f9b407ce3e..e7916f5000 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <test/scriptnum10.h>
#include <script/script.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
#include <limits.h>
diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp
index 002f61f6a2..8a8620938e 100644
--- a/src/test/serialize_tests.cpp
+++ b/src/test/serialize_tests.cpp
@@ -1,11 +1,12 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <serialize.h>
#include <streams.h>
#include <hash.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
+#include <util/strencodings.h>
#include <stdint.h>
diff --git a/src/test/test_bitcoin.cpp b/src/test/setup_common.cpp
index 0c3fb7c398..e3ba9cddb0 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/setup_common.cpp
@@ -1,8 +1,8 @@
-// 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.
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <banman.h>
#include <chainparams.h>
@@ -10,16 +10,22 @@
#include <consensus/params.h>
#include <consensus/validation.h>
#include <crypto/sha256.h>
+#include <init.h>
#include <miner.h>
-#include <net_processing.h>
+#include <net.h>
#include <noui.h>
#include <pow.h>
#include <rpc/register.h>
#include <rpc/server.h>
#include <script/sigcache.h>
#include <streams.h>
-#include <ui_interface.h>
+#include <txdb.h>
+#include <util/memory.h>
+#include <util/strencodings.h>
+#include <util/time.h>
+#include <util/validation.h>
#include <validation.h>
+#include <validationinterface.h>
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
@@ -32,8 +38,15 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)
}
BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
- : m_path_root(fs::temp_directory_path() / "test_bitcoin" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
+ : m_path_root(fs::temp_directory_path() / "test_common_" PACKAGE_NAME / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
{
+ fs::create_directories(m_path_root);
+ gArgs.ForceSetArg("-datadir", m_path_root.string());
+ ClearDatadirCache();
+ SelectParams(chainName);
+ gArgs.ForceSetArg("-printtoconsole", "0");
+ InitLogging();
+ LogInstance().StartLogging();
SHA256AutoDetect();
ECC_Start();
SetupEnvironment();
@@ -41,61 +54,52 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
InitSignatureCache();
InitScriptExecutionCache();
fCheckBlockIndex = true;
- // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
- // TODO: fix the code to support SegWit blocks.
- gArgs.ForceSetArg("-vbparams", strprintf("segwit:0:%d", (int64_t)Consensus::BIP9Deployment::NO_TIMEOUT));
- SelectParams(chainName);
- noui_connect();
+ static bool noui_connected = false;
+ if (!noui_connected) {
+ noui_connect();
+ noui_connected = true;
+ }
}
BasicTestingSetup::~BasicTestingSetup()
{
+ LogInstance().DisconnectTestLogger();
fs::remove_all(m_path_root);
ECC_Stop();
}
-fs::path BasicTestingSetup::SetDataDir(const std::string& name)
-{
- fs::path ret = m_path_root / name;
- fs::create_directories(ret);
- gArgs.ForceSetArg("-datadir", ret.string());
- return ret;
-}
-
TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName)
{
- SetDataDir("tempdir");
const CChainParams& chainparams = Params();
- // Ideally we'd move all the RPC tests to the functional testing framework
- // instead of unit tests, but for now we need these here.
-
- RegisterAllCoreRPCCommands(tableRPC);
- ClearDatadirCache();
-
- // We have to run a scheduler thread to prevent ActivateBestChain
- // from blocking due to queue overrun.
- threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
- GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
-
- mempool.setSanityCheck(1.0);
- pblocktree.reset(new CBlockTreeDB(1 << 20, true));
- pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
- pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
- if (!LoadGenesisBlock(chainparams)) {
- throw std::runtime_error("LoadGenesisBlock failed.");
- }
- {
- CValidationState state;
- if (!ActivateBestChain(state, chainparams)) {
- throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
- }
- }
- nScriptCheckThreads = 3;
- for (int i=0; i < nScriptCheckThreads-1; i++)
- threadGroup.create_thread(&ThreadScriptCheck);
-
- g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
- g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
+ // Ideally we'd move all the RPC tests to the functional testing framework
+ // instead of unit tests, but for now we need these here.
+
+ RegisterAllCoreRPCCommands(tableRPC);
+
+ // We have to run a scheduler thread to prevent ActivateBestChain
+ // from blocking due to queue overrun.
+ threadGroup.create_thread(std::bind(&CScheduler::serviceQueue, &scheduler));
+ GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
+
+ mempool.setSanityCheck(1.0);
+ pblocktree.reset(new CBlockTreeDB(1 << 20, true));
+ pcoinsdbview.reset(new CCoinsViewDB(1 << 23, true));
+ pcoinsTip.reset(new CCoinsViewCache(pcoinsdbview.get()));
+ if (!LoadGenesisBlock(chainparams)) {
+ throw std::runtime_error("LoadGenesisBlock failed.");
+ }
+
+ CValidationState state;
+ if (!ActivateBestChain(state, chainparams)) {
+ throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
+ }
+
+ nScriptCheckThreads = 3;
+ for (int i = 0; i < nScriptCheckThreads - 1; i++)
+ threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
+
+ g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
+ g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
}
TestingSetup::~TestingSetup()
@@ -114,6 +118,11 @@ TestingSetup::~TestingSetup()
TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
+ // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests.
+ // TODO: fix the code to support SegWit blocks.
+ gArgs.ForceSetArg("-vbparams", strprintf("segwit:0:%d", (int64_t)Consensus::BIP9Deployment::NO_TIMEOUT));
+ SelectParams(CBaseChainParams::REGTEST);
+
// Generate a 100-block chain:
coinbaseKey.MakeNewKey(true);
CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
@@ -144,7 +153,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
{
LOCK(cs_main);
unsigned int extraNonce = 0;
- IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+ IncrementExtraNonce(&block, ::ChainActive().Tip(), extraNonce);
}
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
diff --git a/src/test/test_bitcoin.h b/src/test/setup_common.h
index 4a06845683..6c9494898c 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/setup_common.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2015-2018 The Bitcoin Core developers
+// Copyright (c) 2015-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_TEST_TEST_BITCOIN_H
-#define BITCOIN_TEST_TEST_BITCOIN_H
+#ifndef BITCOIN_TEST_SETUP_COMMON_H
+#define BITCOIN_TEST_SETUP_COMMON_H
#include <chainparamsbase.h>
#include <fs.h>
@@ -11,10 +11,8 @@
#include <pubkey.h>
#include <random.h>
#include <scheduler.h>
-#include <txdb.h>
#include <txmempool.h>
-#include <memory>
#include <type_traits>
#include <boost/thread.hpp>
@@ -54,27 +52,20 @@ static inline bool InsecureRandBool() { return g_insecure_rand_ctx.randbool(); }
static constexpr CAmount CENT{1000000};
/** Basic testing setup.
- * This just configures logging and chain parameters.
+ * This just configures logging, data dir and chain parameters.
*/
struct BasicTestingSetup {
ECCVerifyHandle globalVerifyHandle;
explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
~BasicTestingSetup();
-
- fs::path SetDataDir(const std::string& name);
-
private:
const fs::path m_path_root;
};
/** Testing setup that configures a complete environment.
- * Included are data directory, coins database, script check threads setup.
+ * Included are coins database, script check threads setup.
*/
-class CConnman;
-class CNode;
-
-class PeerLogicValidation;
struct TestingSetup : public BasicTestingSetup {
boost::thread_group threadGroup;
CScheduler scheduler;
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 04d5462acb..15f8db899b 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2013-2018 The Bitcoin Core developers
+// Copyright (c) 2013-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 <consensus/tx_verify.h>
+#include <consensus/tx_check.h>
#include <consensus/validation.h>
#include <test/data/sighash.json.h>
#include <hash.h>
@@ -10,7 +10,7 @@
#include <script/script.h>
#include <serialize.h>
#include <streams.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <version.h>
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
index 6a0349cd4e..a32f2cda92 100644
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -1,15 +1,15 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <consensus/consensus.h>
#include <consensus/tx_verify.h>
-#include <consensus/validation.h>
#include <pubkey.h>
#include <key.h>
#include <script/script.h>
#include <script/standard.h>
#include <uint256.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <vector>
@@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U);
BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U);
- CScript p2sh = GetScriptForDestination(CScriptID(s1));
+ CScript p2sh = GetScriptForDestination(ScriptHash(s1));
CScript scriptSig;
scriptSig << OP_0 << Serialize(s1);
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U);
@@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(GetSigOpCount)
BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U);
BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U);
- p2sh = GetScriptForDestination(CScriptID(s2));
+ p2sh = GetScriptForDestination(ScriptHash(s2));
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U);
BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U);
CScript scriptSig2;
@@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
// Multisig nested in P2SH
{
CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
- CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
+ CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript);
BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig, CScriptWitness());
@@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
{
CScript p2pk = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
CScript scriptSig = GetScriptForWitness(p2pk);
- CScript scriptPubKey = GetScriptForDestination(CScriptID(scriptSig));
+ CScript scriptPubKey = GetScriptForDestination(ScriptHash(scriptSig));
scriptSig = CScript() << ToByteVector(scriptSig);
CScriptWitness scriptWitness;
scriptWitness.stack.push_back(std::vector<unsigned char>(0));
@@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(GetTxSigOpCost)
{
CScript witnessScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY;
CScript redeemScript = GetScriptForWitness(witnessScript);
- CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
+ CScript scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
CScript scriptSig = CScript() << ToByteVector(redeemScript);
CScriptWitness scriptWitness;
scriptWitness.stack.push_back(std::vector<unsigned char>(0));
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 5c46976ace..3d39dfdb75 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-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 <chain.h>
#include <util/system.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <vector>
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
// Pick a random element in vBlocksMain.
int r = InsecureRandRange(vBlocksMain.size());
int64_t test_time = vBlocksMain[r].nTime;
- CBlockIndex *ret = chain.FindEarliestAtLeast(test_time);
+ CBlockIndex* ret = chain.FindEarliestAtLeast(test_time, 0);
BOOST_CHECK(ret->nTimeMax >= test_time);
BOOST_CHECK((ret->pprev==nullptr) || ret->pprev->nTimeMax < test_time);
BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);
@@ -158,22 +158,34 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)
CChain chain;
chain.SetTip(&blocks.back());
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50)->nHeight, 0);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100)->nHeight, 0);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(150)->nHeight, 3);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(200)->nHeight, 3);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(250)->nHeight, 6);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(300)->nHeight, 6);
- BOOST_CHECK(!chain.FindEarliestAtLeast(350));
-
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0)->nHeight, 0);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-1)->nHeight, 0);
-
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::min())->nHeight, 0);
- BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-int64_t(std::numeric_limits<unsigned int>::max()) - 1)->nHeight, 0);
- BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::max()));
- BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::max()));
- BOOST_CHECK(!chain.FindEarliestAtLeast(int64_t(std::numeric_limits<unsigned int>::max()) + 1));
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50, 0)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100, 0)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(150, 0)->nHeight, 3);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(200, 0)->nHeight, 3);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(250, 0)->nHeight, 6);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(300, 0)->nHeight, 6);
+ BOOST_CHECK(!chain.FindEarliestAtLeast(350, 0));
+
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 0)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-1, 0)->nHeight, 0);
+
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::min(), 0)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-int64_t(std::numeric_limits<unsigned int>::max()) - 1, 0)->nHeight, 0);
+ BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::max(), 0));
+ BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::max(), 0));
+ BOOST_CHECK(!chain.FindEarliestAtLeast(int64_t(std::numeric_limits<unsigned int>::max()) + 1, 0));
+
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, -1)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 0)->nHeight, 0);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 3)->nHeight, 3);
+ BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 8)->nHeight, 8);
+ BOOST_CHECK(!chain.FindEarliestAtLeast(0, 9));
+
+ CBlockIndex* ret1 = chain.FindEarliestAtLeast(100, 2);
+ BOOST_CHECK(ret1->nTimeMax >= 100 && ret1->nHeight == 2);
+ BOOST_CHECK(!chain.FindEarliestAtLeast(300, 9));
+ CBlockIndex* ret2 = chain.FindEarliestAtLeast(200, 4);
+ BOOST_CHECK(ret2->nTimeMax >= 200 && ret2->nHeight == 4);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index a1940eb80e..b812cef801 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -1,10 +1,9 @@
-// Copyright (c) 2012-2018 The Bitcoin Core developers
+// Copyright (c) 2012-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 <streams.h>
-#include <support/allocators/zeroafterfree.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp
index df0380546e..c1399d2dbe 100644
--- a/src/test/sync_tests.cpp
+++ b/src/test/sync_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2012-2017 The Bitcoin Core developers
+// Copyright (c) 2012-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 <sync.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp
deleted file mode 100644
index 46b63b93b4..0000000000
--- a/src/test/test_bitcoin_main.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2011-2018 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#define BOOST_TEST_MODULE Bitcoin Test Suite
-
-#include <banman.h>
-#include <net.h>
-
-#include <memory>
-
-#include <boost/test/unit_test.hpp>
-
-std::unique_ptr<CConnman> g_connman;
-std::unique_ptr<BanMan> g_banman;
-
-[[noreturn]] void Shutdown(void* parg)
-{
- std::exit(EXIT_SUCCESS);
-}
-
-[[noreturn]] void StartShutdown()
-{
- std::exit(EXIT_SUCCESS);
-}
-
-bool ShutdownRequested()
-{
- return false;
-}
diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp
index 474a67497f..b4c0e6a0f4 100644
--- a/src/test/timedata_tests.cpp
+++ b/src/test/timedata_tests.cpp
@@ -1,9 +1,9 @@
-// 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.
//
#include <timedata.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
diff --git a/src/test/torcontrol_tests.cpp b/src/test/torcontrol_tests.cpp
index c7ceb2f1e9..d846062d9b 100644
--- a/src/test/torcontrol_tests.cpp
+++ b/src/test/torcontrol_tests.cpp
@@ -2,8 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
-#include <test/test_bitcoin.h>
-#include <torcontrol.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -20,7 +19,6 @@ BOOST_FIXTURE_TEST_SUITE(torcontrol_tests, BasicTestingSetup)
static void CheckSplitTorReplyLine(std::string input, std::string command, std::string args)
{
- BOOST_TEST_MESSAGE(std::string("CheckSplitTorReplyLine(") + input + ")");
auto ret = SplitTorReplyLine(input);
BOOST_CHECK_EQUAL(ret.first, command);
BOOST_CHECK_EQUAL(ret.second, args);
@@ -61,7 +59,6 @@ BOOST_AUTO_TEST_CASE(util_SplitTorReplyLine)
static void CheckParseTorReplyMapping(std::string input, std::map<std::string,std::string> expected)
{
- BOOST_TEST_MESSAGE(std::string("CheckParseTorReplyMapping(") + input + ")");
auto ret = ParseTorReplyMapping(input);
BOOST_CHECK_EQUAL(ret.size(), expected.size());
auto r_it = ret.begin();
@@ -173,7 +170,6 @@ BOOST_AUTO_TEST_CASE(util_ParseTorReplyMapping)
// Special handling for null case
// (needed because string comparison reads the null as end-of-string)
- BOOST_TEST_MESSAGE(std::string("CheckParseTorReplyMapping(Null=\"\\0\")"));
auto ret = ParseTorReplyMapping("Null=\"\\0\"");
BOOST_CHECK_EQUAL(ret.size(), 1U);
auto r_it = ret.begin();
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 39cff3f463..f77b77a972 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,24 +1,26 @@
-// 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.
#include <test/data/tx_invalid.json.h>
#include <test/data/tx_valid.json.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <clientversion.h>
#include <checkqueue.h>
-#include <consensus/tx_verify.h>
+#include <consensus/tx_check.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <key.h>
#include <keystore.h>
#include <validation.h>
#include <policy/policy.h>
+#include <policy/settings.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/script_error.h>
#include <script/standard.h>
+#include <streams.h>
#include <util/strencodings.h>
#include <map>
@@ -310,9 +312,9 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
dummyTransactions[1].vout.resize(2);
dummyTransactions[1].vout[0].nValue = 21*CENT;
- dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
+ dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey()));
dummyTransactions[1].vout[1].nValue = 22*CENT;
- dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
+ dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey()));
AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0);
return dummyTransactions;
@@ -561,8 +563,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
// P2SH pay-to-compressed-pubkey.
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1)), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2)), output2, input2);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1)), output1, input1);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2)), output2, input2);
ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1);
CheckWithFlag(output1, input1, 0, true);
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
@@ -586,8 +588,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
// P2SH witness pay-to-compressed-pubkey (v0).
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1))), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2))), output2, input2);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey1))), output1, input1);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey2))), output2, input2);
ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1));
CheckWithFlag(output1, input1, 0, true);
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
@@ -611,8 +613,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
// P2SH pay-to-uncompressed-pubkey.
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey1L)), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptPubkey2L)), output2, input2);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey1L)), output1, input1);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptPubkey2L)), output2, input2);
ReplaceRedeemScript(input2.vin[0].scriptSig, scriptPubkey1L);
CheckWithFlag(output1, input1, 0, true);
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
@@ -628,8 +630,8 @@ BOOST_AUTO_TEST_CASE(test_witness)
CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false);
// Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1).
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false);
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey1L))), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptPubkey2L))), output2, input2, false);
// Normal 2-of-2 multisig
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);
@@ -641,10 +643,10 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
// P2SH 2-of-2 multisig
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(scriptMulti)), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(scriptMulti)), output1, input1, false);
CheckWithFlag(output1, input1, 0, true);
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, false);
- CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(scriptMulti)), output2, input2, false);
+ CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(scriptMulti)), output2, input2, false);
CheckWithFlag(output2, input2, 0, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, false);
BOOST_CHECK(*output1 == *output2);
@@ -665,10 +667,10 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
// P2SH witness 2-of-2 multisig
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptMulti))), output1, input1, false);
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
- CreateCreditAndSpend(keystore2, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptMulti))), output2, input2, false);
+ CreateCreditAndSpend(keystore2, GetScriptForDestination(ScriptHash(GetScriptForWitness(scriptMulti))), output2, input2, false);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH, true);
CheckWithFlag(output2, input2, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, false);
BOOST_CHECK(*output1 == *output2);
@@ -694,7 +696,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
t.vout[0].nValue = 90*CENT;
CKey key;
key.MakeNewKey(true);
- t.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
+ t.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
std::string reason;
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index d667c26c3c..d794d09d30 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -1,14 +1,13 @@
-// 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.
#include <chainparams.h>
#include <index/txindex.h>
#include <script/standard.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <util/system.h>
#include <util/time.h>
-#include <validation.h>
#include <boost/test/unit_test.hpp>
@@ -56,7 +55,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
// Check that new transactions in new blocks make it into the index.
for (int i = 0; i < 10; i++) {
- CScript coinbase_script_pub_key = GetScriptForDestination(coinbaseKey.GetPubKey().GetID());
+ CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
std::vector<CMutableTransaction> no_txns;
const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key);
const CTransaction& txn = *block.vtx[0];
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
index c2777cd6d1..2356e0ccdc 100644
--- a/src/test/txvalidation_tests.cpp
+++ b/src/test/txvalidation_tests.cpp
@@ -1,14 +1,12 @@
-// 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.
#include <validation.h>
-#include <txmempool.h>
-#include <amount.h>
#include <consensus/validation.h>
#include <primitives/transaction.h>
#include <script/script.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
@@ -52,10 +50,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
// Check that the validation state reflects the unsuccessful attempt.
BOOST_CHECK(state.IsInvalid());
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
-
- int nDoS;
- BOOST_CHECK_EQUAL(state.IsInvalid(nDoS), true);
- BOOST_CHECK_EQUAL(nDoS, 100);
+ BOOST_CHECK(state.GetReason() == ValidationInvalidReason::CONSENSUS);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 4d04aae7e9..45c97fa2aa 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -1,21 +1,15 @@
-// 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.
#include <consensus/validation.h>
#include <key.h>
#include <validation.h>
-#include <miner.h>
-#include <pubkey.h>
#include <txmempool.h>
-#include <random.h>
#include <script/standard.h>
#include <script/sign.h>
-#include <test/test_bitcoin.h>
-#include <util/time.h>
-#include <core_io.h>
+#include <test/setup_common.h>
#include <keystore.h>
-#include <policy/policy.h>
#include <boost/test/unit_test.hpp>
@@ -66,18 +60,27 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// Test 1: block with both of those transactions should be rejected.
block = CreateAndProcessBlock(spends, scriptPubKey);
- BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ {
+ LOCK(cs_main);
+ BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
+ }
// Test 2: ... and should be rejected if spend1 is in the memory pool
BOOST_CHECK(ToMemPool(spends[0]));
block = CreateAndProcessBlock(spends, scriptPubKey);
- BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ {
+ LOCK(cs_main);
+ BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
+ }
mempool.clear();
// Test 3: ... and should be rejected if spend2 is in the memory pool
BOOST_CHECK(ToMemPool(spends[1]));
block = CreateAndProcessBlock(spends, scriptPubKey);
- BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ {
+ LOCK(cs_main);
+ BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() != block.GetHash());
+ }
mempool.clear();
// Final sanity test: first spend in mempool, second in block, that's OK:
@@ -85,7 +88,10 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
oneSpend.push_back(spends[0]);
BOOST_CHECK(ToMemPool(spends[1]));
block = CreateAndProcessBlock(oneSpend, scriptPubKey);
- BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
+ {
+ LOCK(cs_main);
+ BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash());
+ }
// spends[1] should have been removed from the mempool when the
// block with spends[0] is accepted:
BOOST_CHECK_EQUAL(mempool.size(), 0U);
@@ -151,8 +157,8 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
}
CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
- CScript p2sh_scriptPubKey = GetScriptForDestination(CScriptID(p2pk_scriptPubKey));
- CScript p2pkh_scriptPubKey = GetScriptForDestination(coinbaseKey.GetPubKey().GetID());
+ CScript p2sh_scriptPubKey = GetScriptForDestination(ScriptHash(p2pk_scriptPubKey));
+ CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
CScript p2wpkh_scriptPubKey = GetScriptForWitness(p2pkh_scriptPubKey);
CBasicKeyStore keystore;
@@ -220,7 +226,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
block = CreateAndProcessBlock({spend_tx}, p2pk_scriptPubKey);
LOCK(cs_main);
- BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
+ BOOST_CHECK(::ChainActive().Tip()->GetBlockHash() == block.GetHash());
BOOST_CHECK(pcoinsTip->GetBestBlock() == block.GetHash());
// Test P2SH: construct a transaction that is valid without P2SH, and
diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp
index cca5e20296..33a118c2bb 100644
--- a/src/test/uint256_tests.cpp
+++ b/src/test/uint256_tests.cpp
@@ -1,19 +1,17 @@
-// 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.
+
#include <arith_uint256.h>
+#include <streams.h>
#include <uint256.h>
#include <version.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/test/unit_test.hpp>
-#include <stdint.h>
#include <sstream>
#include <iomanip>
-#include <limits>
-#include <cmath>
#include <string>
-#include <stdio.h>
BOOST_FIXTURE_TEST_SUITE(uint256_tests, BasicTestingSetup)
diff --git a/src/test/util.cpp b/src/test/util.cpp
new file mode 100644
index 0000000000..a2ea648324
--- /dev/null
+++ b/src/test/util.cpp
@@ -0,0 +1,87 @@
+// 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 <test/util.h>
+
+#include <chainparams.h>
+#include <consensus/merkle.h>
+#include <key_io.h>
+#include <miner.h>
+#include <outputtype.h>
+#include <pow.h>
+#include <script/standard.h>
+#include <validation.h>
+#include <validationinterface.h>
+#ifdef ENABLE_WALLET
+#include <wallet/wallet.h>
+#endif
+
+const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj";
+
+#ifdef ENABLE_WALLET
+std::string getnewaddress(CWallet& w)
+{
+ constexpr auto output_type = OutputType::BECH32;
+
+ CPubKey new_key;
+ if (!w.GetKeyFromPool(new_key)) assert(false);
+
+ w.LearnRelatedScripts(new_key, output_type);
+ const auto dest = GetDestinationForKey(new_key, output_type);
+
+ w.SetAddressBook(dest, /* label */ "", "receive");
+
+ return EncodeDestination(dest);
+}
+
+void importaddress(CWallet& wallet, const std::string& address)
+{
+ LOCK(wallet.cs_wallet);
+ const auto dest = DecodeDestination(address);
+ assert(IsValidDestination(dest));
+ const auto script = GetScriptForDestination(dest);
+ wallet.MarkDirty();
+ assert(!wallet.HaveWatchOnly(script));
+ if (!wallet.AddWatchOnly(script, 0 /* nCreateTime */)) assert(false);
+ wallet.SetAddressBook(dest, /* label */ "", "receive");
+}
+#endif // ENABLE_WALLET
+
+CTxIn generatetoaddress(const std::string& address)
+{
+ const auto dest = DecodeDestination(address);
+ assert(IsValidDestination(dest));
+ const auto coinbase_script = GetScriptForDestination(dest);
+
+ return MineBlock(coinbase_script);
+}
+
+CTxIn MineBlock(const CScript& coinbase_scriptPubKey)
+{
+ auto block = PrepareBlock(coinbase_scriptPubKey);
+
+ while (!CheckProofOfWork(block->GetHash(), block->nBits, Params().GetConsensus())) {
+ ++block->nNonce;
+ assert(block->nNonce);
+ }
+
+ bool processed{ProcessNewBlock(Params(), block, true, nullptr)};
+ assert(processed);
+
+ return CTxIn{block->vtx[0]->GetHash(), 0};
+}
+
+std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey)
+{
+ auto block = std::make_shared<CBlock>(
+ BlockAssembler{Params()}
+ .CreateNewBlock(coinbase_scriptPubKey)
+ ->block);
+
+ LOCK(cs_main);
+ block->nTime = ::ChainActive().Tip()->GetMedianTimePast() + 1;
+ block->hashMerkleRoot = BlockMerkleRoot(*block);
+
+ return block;
+}
diff --git a/src/test/util.h b/src/test/util.h
new file mode 100644
index 0000000000..f90cb0d623
--- /dev/null
+++ b/src/test/util.h
@@ -0,0 +1,70 @@
+// 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_TEST_UTIL_H
+#define BITCOIN_TEST_UTIL_H
+
+#include <memory>
+#include <string>
+
+class CBlock;
+class CScript;
+class CTxIn;
+class CWallet;
+
+// Constants //
+
+extern const std::string ADDRESS_BCRT1_UNSPENDABLE;
+
+// Lower-level utils //
+
+/** Returns the generated coin */
+CTxIn MineBlock(const CScript& coinbase_scriptPubKey);
+/** Prepare a block to be mined */
+std::shared_ptr<CBlock> PrepareBlock(const CScript& coinbase_scriptPubKey);
+
+
+// RPC-like //
+
+/** Import the address to the wallet */
+void importaddress(CWallet& wallet, const std::string& address);
+/** Returns a new address from the wallet */
+std::string getnewaddress(CWallet& w);
+/** Returns the generated coin */
+CTxIn generatetoaddress(const std::string& address);
+
+/**
+ * Increment a string. Useful to enumerate all fixed length strings with
+ * characters in [min_char, max_char].
+ */
+template <typename CharType, size_t StringLength>
+bool NextString(CharType (&string)[StringLength], CharType min_char, CharType max_char)
+{
+ for (CharType& elem : string) {
+ bool has_next = elem != max_char;
+ elem = elem < min_char || elem >= max_char ? min_char : CharType(elem + 1);
+ if (has_next) return true;
+ }
+ return false;
+}
+
+/**
+ * Iterate over string values and call function for each string without
+ * successive duplicate characters.
+ */
+template <typename CharType, size_t StringLength, typename Fn>
+void ForEachNoDup(CharType (&string)[StringLength], CharType min_char, CharType max_char, Fn&& fn) {
+ for (bool has_next = true; has_next; has_next = NextString(string, min_char, max_char)) {
+ int prev = -1;
+ bool skip_string = false;
+ for (CharType c : string) {
+ if (c == prev) skip_string = true;
+ if (skip_string || c < min_char || c > max_char) break;
+ prev = c;
+ }
+ if (!skip_string) fn();
+ }
+}
+
+#endif // BITCOIN_TEST_UTIL_H
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index e17ae7103b..9960573b33 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1,17 +1,19 @@
-// 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.
#include <util/system.h>
#include <clientversion.h>
-#include <primitives/transaction.h>
#include <sync.h>
+#include <test/util.h>
#include <util/strencodings.h>
#include <util/moneystr.h>
-#include <test/test_bitcoin.h>
+#include <util/time.h>
+#include <test/setup_common.h>
#include <stdint.h>
+#include <thread>
#include <vector>
#ifndef WIN32
#include <signal.h>
@@ -36,8 +38,10 @@ BOOST_AUTO_TEST_CASE(util_criticalsection)
do {
TRY_LOCK(cs, lockTest);
- if (lockTest)
+ if (lockTest) {
+ BOOST_CHECK(true); // Needed to suppress "Test case [...] did not check any assertions"
break;
+ }
BOOST_ERROR("break was swallowed!");
} while(0);
@@ -78,80 +82,40 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
BOOST_CHECK_EQUAL(
- HexStr(ParseHex_expected, ParseHex_expected + 5, true),
- "04 67 8a fd b0");
-
- BOOST_CHECK_EQUAL(
HexStr(ParseHex_expected + sizeof(ParseHex_expected),
ParseHex_expected + sizeof(ParseHex_expected)),
"");
BOOST_CHECK_EQUAL(
- HexStr(ParseHex_expected + sizeof(ParseHex_expected),
- ParseHex_expected + sizeof(ParseHex_expected), true),
- "");
-
- BOOST_CHECK_EQUAL(
HexStr(ParseHex_expected, ParseHex_expected),
"");
- BOOST_CHECK_EQUAL(
- HexStr(ParseHex_expected, ParseHex_expected, true),
- "");
-
std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
BOOST_CHECK_EQUAL(
- HexStr(ParseHex_vec, true),
- "04 67 8a fd b0");
-
- BOOST_CHECK_EQUAL(
HexStr(ParseHex_vec.rbegin(), ParseHex_vec.rend()),
"b0fd8a6704"
);
BOOST_CHECK_EQUAL(
- HexStr(ParseHex_vec.rbegin(), ParseHex_vec.rend(), true),
- "b0 fd 8a 67 04"
- );
-
- BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected),
std::reverse_iterator<const uint8_t *>(ParseHex_expected)),
""
);
BOOST_CHECK_EQUAL(
- HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected),
- std::reverse_iterator<const uint8_t *>(ParseHex_expected), true),
- ""
- );
-
- BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 1),
std::reverse_iterator<const uint8_t *>(ParseHex_expected)),
"04"
);
BOOST_CHECK_EQUAL(
- HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 1),
- std::reverse_iterator<const uint8_t *>(ParseHex_expected), true),
- "04"
- );
-
- BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 5),
std::reverse_iterator<const uint8_t *>(ParseHex_expected)),
"b0fd8a6704"
);
BOOST_CHECK_EQUAL(
- HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 5),
- std::reverse_iterator<const uint8_t *>(ParseHex_expected), true),
- "b0 fd 8a 67 04"
- );
-
- BOOST_CHECK_EQUAL(
HexStr(std::reverse_iterator<const uint8_t *>(ParseHex_expected + 65),
std::reverse_iterator<const uint8_t *>(ParseHex_expected)),
"5f1df16b2b704c8a578d0bbaf74d385cde12c11ee50455f3c438ef4c3fbcf649b6de611feae06279a60939e028a8d65c10b73071a6f16719274855feb0fd8a6704"
@@ -196,6 +160,9 @@ struct TestArgsManager : public ArgsManager
AddArg(args[i], "", false, OptionsCategory::OPTIONS);
}
}
+ using ArgsManager::ReadConfigStream;
+ using ArgsManager::cs_args;
+ using ArgsManager::m_network;
};
BOOST_AUTO_TEST_CASE(util_ParseParameters)
@@ -613,6 +580,306 @@ BOOST_AUTO_TEST_CASE(util_GetChainName)
BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error);
}
+// Test different ways settings can be merged, and verify results. This test can
+// be used to confirm that updates to settings code don't change behavior
+// unintentionally.
+//
+// The test covers:
+//
+// - Combining different setting actions. Possible actions are: configuring a
+// setting, negating a setting (adding "-no" prefix), and configuring/negating
+// settings in a network section (adding "main." or "test." prefixes).
+//
+// - Combining settings from command line arguments and a config file.
+//
+// - Combining SoftSet and ForceSet calls.
+//
+// - Testing "main" and "test" network values to make sure settings from network
+// sections are applied and to check for mainnet-specific behaviors like
+// inheriting settings from the default section.
+//
+// - Testing network-specific settings like "-wallet", that may be ignored
+// outside a network section, and non-network specific settings like "-server"
+// that aren't sensitive to the network.
+//
+struct ArgsMergeTestingSetup : public BasicTestingSetup {
+ //! Max number of actions to sequence together. Can decrease this when
+ //! debugging to make test results easier to understand.
+ static constexpr int MAX_ACTIONS = 3;
+
+ enum Action { NONE, SET, NEGATE, SECTION_SET, SECTION_NEGATE };
+ using ActionList = Action[MAX_ACTIONS];
+
+ //! Enumerate all possible test configurations.
+ template <typename Fn>
+ void ForEachMergeSetup(Fn&& fn)
+ {
+ ActionList arg_actions = {};
+ ForEachNoDup(arg_actions, SET, SECTION_NEGATE, [&] {
+ ActionList conf_actions = {};
+ ForEachNoDup(conf_actions, SET, SECTION_NEGATE, [&] {
+ for (bool soft_set : {false, true}) {
+ for (bool force_set : {false, true}) {
+ for (const std::string& section : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
+ for (const std::string& network : {CBaseChainParams::MAIN, CBaseChainParams::TESTNET}) {
+ for (bool net_specific : {false, true}) {
+ fn(arg_actions, conf_actions, soft_set, force_set, section, network, net_specific);
+ }
+ }
+ }
+ }
+ }
+ });
+ });
+ }
+
+ //! Translate actions into a list of <key>=<value> setting strings.
+ std::vector<std::string> GetValues(const ActionList& actions,
+ const std::string& section,
+ const std::string& name,
+ const std::string& value_prefix)
+ {
+ std::vector<std::string> values;
+ int suffix = 0;
+ for (Action action : actions) {
+ if (action == NONE) break;
+ std::string prefix;
+ if (action == SECTION_SET || action == SECTION_NEGATE) prefix = section + ".";
+ if (action == SET || action == SECTION_SET) {
+ for (int i = 0; i < 2; ++i) {
+ values.push_back(prefix + name + "=" + value_prefix + std::to_string(++suffix));
+ }
+ }
+ if (action == NEGATE || action == SECTION_NEGATE) {
+ values.push_back(prefix + "no" + name + "=1");
+ }
+ }
+ return values;
+ }
+};
+
+// Regression test covering different ways config settings can be merged. The
+// test parses and merges settings, representing the results as strings that get
+// compared against an expected hash. To debug, the result strings can be dumped
+// to a file (see comments below).
+BOOST_FIXTURE_TEST_CASE(util_ArgsMerge, ArgsMergeTestingSetup)
+{
+ CHash256 out_sha;
+ FILE* out_file = nullptr;
+ if (const char* out_path = getenv("ARGS_MERGE_TEST_OUT")) {
+ out_file = fsbridge::fopen(out_path, "w");
+ if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
+ }
+
+ ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions, bool soft_set, bool force_set,
+ const std::string& section, const std::string& network, bool net_specific) {
+ TestArgsManager parser;
+ LOCK(parser.cs_args);
+
+ std::string desc = "net=";
+ desc += network;
+ parser.m_network = network;
+
+ const std::string& name = net_specific ? "wallet" : "server";
+ const std::string key = "-" + name;
+ parser.AddArg(key, name, false, OptionsCategory::OPTIONS);
+ if (net_specific) parser.SetNetworkOnlyArg(key);
+
+ auto args = GetValues(arg_actions, section, name, "a");
+ std::vector<const char*> argv = {"ignored"};
+ for (auto& arg : args) {
+ arg.insert(0, "-");
+ desc += " ";
+ desc += arg;
+ argv.push_back(arg.c_str());
+ }
+ std::string error;
+ BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ std::string conf;
+ for (auto& conf_val : GetValues(conf_actions, section, name, "c")) {
+ desc += " ";
+ desc += conf_val;
+ conf += conf_val;
+ conf += "\n";
+ }
+ std::istringstream conf_stream(conf);
+ BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ if (soft_set) {
+ desc += " soft";
+ parser.SoftSetArg(key, "soft1");
+ parser.SoftSetArg(key, "soft2");
+ }
+
+ if (force_set) {
+ desc += " force";
+ parser.ForceSetArg(key, "force1");
+ parser.ForceSetArg(key, "force2");
+ }
+
+ desc += " || ";
+
+ if (!parser.IsArgSet(key)) {
+ desc += "unset";
+ BOOST_CHECK(!parser.IsArgNegated(key));
+ BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "default");
+ BOOST_CHECK(parser.GetArgs(key).empty());
+ } else if (parser.IsArgNegated(key)) {
+ desc += "negated";
+ BOOST_CHECK_EQUAL(parser.GetArg(key, "default"), "0");
+ BOOST_CHECK(parser.GetArgs(key).empty());
+ } else {
+ desc += parser.GetArg(key, "default");
+ desc += " |";
+ for (const auto& arg : parser.GetArgs(key)) {
+ desc += " ";
+ desc += arg;
+ }
+ }
+
+ std::set<std::string> ignored = parser.GetUnsuitableSectionOnlyArgs();
+ if (!ignored.empty()) {
+ desc += " | ignored";
+ for (const auto& arg : ignored) {
+ desc += " ";
+ desc += arg;
+ }
+ }
+
+ desc += "\n";
+
+ out_sha.Write((const unsigned char*)desc.data(), desc.size());
+ if (out_file) {
+ BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
+ }
+ });
+
+ if (out_file) {
+ if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
+ out_file = nullptr;
+ }
+
+ unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
+ out_sha.Finalize(out_sha_bytes);
+ std::string out_sha_hex = HexStr(std::begin(out_sha_bytes), std::end(out_sha_bytes));
+
+ // If check below fails, should manually dump the results with:
+ //
+ // ARGS_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ArgsMerge
+ //
+ // And verify diff against previous results to make sure the changes are expected.
+ //
+ // Results file is formatted like:
+ //
+ // <input> || <IsArgSet/IsArgNegated/GetArg output> | <GetArgs output> | <GetUnsuitable output>
+ BOOST_CHECK_EQUAL(out_sha_hex, "b835eef5977d69114eb039a976201f8c7121f34fe2b7ea2b73cafb516e5c9dc8");
+}
+
+// Similar test as above, but for ArgsManager::GetChainName function.
+struct ChainMergeTestingSetup : public BasicTestingSetup {
+ static constexpr int MAX_ACTIONS = 2;
+
+ enum Action { NONE, ENABLE_TEST, DISABLE_TEST, NEGATE_TEST, ENABLE_REG, DISABLE_REG, NEGATE_REG };
+ using ActionList = Action[MAX_ACTIONS];
+
+ //! Enumerate all possible test configurations.
+ template <typename Fn>
+ void ForEachMergeSetup(Fn&& fn)
+ {
+ ActionList arg_actions = {};
+ ForEachNoDup(arg_actions, ENABLE_TEST, NEGATE_REG, [&] {
+ ActionList conf_actions = {};
+ ForEachNoDup(conf_actions, ENABLE_TEST, NEGATE_REG, [&] { fn(arg_actions, conf_actions); });
+ });
+ }
+};
+
+BOOST_FIXTURE_TEST_CASE(util_ChainMerge, ChainMergeTestingSetup)
+{
+ CHash256 out_sha;
+ FILE* out_file = nullptr;
+ if (const char* out_path = getenv("CHAIN_MERGE_TEST_OUT")) {
+ out_file = fsbridge::fopen(out_path, "w");
+ if (!out_file) throw std::system_error(errno, std::generic_category(), "fopen failed");
+ }
+
+ ForEachMergeSetup([&](const ActionList& arg_actions, const ActionList& conf_actions) {
+ TestArgsManager parser;
+ LOCK(parser.cs_args);
+ parser.AddArg("-regtest", "regtest", false, OptionsCategory::OPTIONS);
+ parser.AddArg("-testnet", "testnet", false, OptionsCategory::OPTIONS);
+
+ auto arg = [](Action action) { return action == ENABLE_TEST ? "-testnet=1" :
+ action == DISABLE_TEST ? "-testnet=0" :
+ action == NEGATE_TEST ? "-notestnet=1" :
+ action == ENABLE_REG ? "-regtest=1" :
+ action == DISABLE_REG ? "-regtest=0" :
+ action == NEGATE_REG ? "-noregtest=1" : nullptr; };
+
+ std::string desc;
+ std::vector<const char*> argv = {"ignored"};
+ for (Action action : arg_actions) {
+ const char* argstr = arg(action);
+ if (!argstr) break;
+ argv.push_back(argstr);
+ desc += " ";
+ desc += argv.back();
+ }
+ std::string error;
+ BOOST_CHECK(parser.ParseParameters(argv.size(), argv.data(), error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ std::string conf;
+ for (Action action : conf_actions) {
+ const char* argstr = arg(action);
+ if (!argstr) break;
+ desc += " ";
+ desc += argstr + 1;
+ conf += argstr + 1;
+ }
+ std::istringstream conf_stream(conf);
+ BOOST_CHECK(parser.ReadConfigStream(conf_stream, "filepath", error));
+ BOOST_CHECK_EQUAL(error, "");
+
+ desc += " || ";
+ try {
+ desc += parser.GetChainName();
+ } catch (const std::runtime_error& e) {
+ desc += "error: ";
+ desc += e.what();
+ }
+ desc += "\n";
+
+ out_sha.Write((const unsigned char*)desc.data(), desc.size());
+ if (out_file) {
+ BOOST_REQUIRE(fwrite(desc.data(), 1, desc.size(), out_file) == desc.size());
+ }
+ });
+
+ if (out_file) {
+ if (fclose(out_file)) throw std::system_error(errno, std::generic_category(), "fclose failed");
+ out_file = nullptr;
+ }
+
+ unsigned char out_sha_bytes[CSHA256::OUTPUT_SIZE];
+ out_sha.Finalize(out_sha_bytes);
+ std::string out_sha_hex = HexStr(std::begin(out_sha_bytes), std::end(out_sha_bytes));
+
+ // If check below fails, should manually dump the results with:
+ //
+ // CHAIN_MERGE_TEST_OUT=results.txt ./test_bitcoin --run_test=util_tests/util_ChainMerge
+ //
+ // And verify diff against previous results to make sure the changes are expected.
+ //
+ // Results file is formatted like:
+ //
+ // <input> || <output>
+ BOOST_CHECK_EQUAL(out_sha_hex, "b284f4b4a15dd6bf8c06213a69a004b1960388e1d9917173927db52ac220927f");
+}
+
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
@@ -802,6 +1069,27 @@ BOOST_AUTO_TEST_CASE(gettime)
BOOST_CHECK((GetTime() & ~0xFFFFFFFFLL) == 0);
}
+BOOST_AUTO_TEST_CASE(util_time_GetTime)
+{
+ SetMockTime(111);
+ // Check that mock time does not change after a sleep
+ for (const auto& num_sleep : {0, 1}) {
+ MilliSleep(num_sleep);
+ BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
+ BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
+ BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
+ BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count());
+ }
+
+ SetMockTime(0);
+ // Check that system time changes after a sleep
+ const auto ms_0 = GetTime<std::chrono::milliseconds>();
+ const auto us_0 = GetTime<std::chrono::microseconds>();
+ MilliSleep(1);
+ BOOST_CHECK(ms_0 < GetTime<std::chrono::milliseconds>());
+ BOOST_CHECK(us_0 < GetTime<std::chrono::microseconds>());
+}
+
BOOST_AUTO_TEST_CASE(test_IsDigit)
{
BOOST_CHECK_EQUAL(IsDigit('0'), true);
@@ -1111,7 +1399,7 @@ static void TestOtherProcess(fs::path dirname, std::string lockname, int fd)
BOOST_AUTO_TEST_CASE(test_LockDirectory)
{
- fs::path dirname = SetDataDir("test_LockDirectory") / fs::unique_path();
+ fs::path dirname = GetDataDir() / "lock_dir";
const std::string lockname = ".lock";
#ifndef WIN32
// Revert SIGCHLD to default, otherwise boost.test will catch and fail on
@@ -1200,7 +1488,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_AUTO_TEST_CASE(test_DirIsWritable)
{
// Should be able to write to the data dir.
- fs::path tmpdirname = SetDataDir("test_DirIsWritable");
+ fs::path tmpdirname = GetDataDir();
BOOST_CHECK_EQUAL(DirIsWritable(tmpdirname), true);
// Should not be able to write to a non-existent dir.
diff --git a/src/test/util_threadnames_tests.cpp b/src/test/util_threadnames_tests.cpp
new file mode 100644
index 0000000000..71c0168ca3
--- /dev/null
+++ b/src/test/util_threadnames_tests.cpp
@@ -0,0 +1,73 @@
+// Copyright (c) 2018 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 <util/threadnames.h>
+#include <test/setup_common.h>
+
+#include <thread>
+#include <vector>
+#include <set>
+#include <mutex>
+
+#if defined(HAVE_CONFIG_H)
+#include <config/bitcoin-config.h>
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(util_threadnames_tests, BasicTestingSetup)
+
+const std::string TEST_THREAD_NAME_BASE = "test_thread.";
+
+/**
+ * Run a bunch of threads to all call util::ThreadRename.
+ *
+ * @return the set of name each thread has after attempted renaming.
+ */
+std::set<std::string> RenameEnMasse(int num_threads)
+{
+ std::vector<std::thread> threads;
+ std::set<std::string> names;
+ std::mutex lock;
+
+ auto RenameThisThread = [&](int i) {
+ util::ThreadRename(TEST_THREAD_NAME_BASE + std::to_string(i));
+ std::lock_guard<std::mutex> guard(lock);
+ names.insert(util::ThreadGetInternalName());
+ };
+
+ for (int i = 0; i < num_threads; ++i) {
+ threads.push_back(std::thread(RenameThisThread, i));
+ }
+
+ for (std::thread& thread : threads) thread.join();
+
+ return names;
+}
+
+/**
+ * Rename a bunch of threads with the same basename (expect_multiple=true), ensuring suffixes are
+ * applied properly.
+ */
+BOOST_AUTO_TEST_CASE(util_threadnames_test_rename_threaded)
+{
+ BOOST_CHECK_EQUAL(util::ThreadGetInternalName(), "");
+
+#if !defined(HAVE_THREAD_LOCAL)
+ // This test doesn't apply to platforms where we don't have thread_local.
+ return;
+#endif
+
+ std::set<std::string> names = RenameEnMasse(100);
+
+ BOOST_CHECK_EQUAL(names.size(), 100);
+
+ // Names "test_thread.[n]" should exist for n = [0, 99]
+ for (int i = 0; i < 100; ++i) {
+ BOOST_CHECK(names.find(TEST_THREAD_NAME_BASE + std::to_string(i)) != names.end());
+ }
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 44432cd0a1..6a9813442b 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
@@ -10,10 +10,13 @@
#include <miner.h>
#include <pow.h>
#include <random.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
+#include <util/time.h>
#include <validation.h>
#include <validationinterface.h>
+#include <thread>
+
struct RegtestingSetup : public TestingSetup {
RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {}
};
@@ -144,7 +147,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
const CBlockIndex* initial_tip = nullptr;
{
LOCK(cs_main);
- initial_tip = chainActive.Tip();
+ initial_tip = ::ChainActive().Tip();
}
TestSubscriber sub(initial_tip->GetBlockHash());
RegisterValidationInterface(&sub);
@@ -181,7 +184,8 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
UnregisterValidationInterface(&sub);
- BOOST_CHECK_EQUAL(sub.m_expected_tip, chainActive.Tip()->GetBlockHash());
+ LOCK(cs_main);
+ BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/main_tests.cpp b/src/test/validation_tests.cpp
index 5b3f2bc578..101025d31e 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/validation_tests.cpp
@@ -1,17 +1,17 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-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 <chainparams.h>
-#include <validation.h>
#include <net.h>
+#include <validation.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>
-BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)
+BOOST_FIXTURE_TEST_SUITE(validation_tests, TestingSetup)
static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
{
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index ca3196454a..0ca3a17974 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-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 <chain.h>
#include <versionbits.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <chainparams.h>
#include <validation.h>
#include <consensus/params.h>
@@ -271,12 +271,12 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Before MedianTimePast of the chain has crossed nStartTime, the bit
// should not be set.
CBlockIndex *lastBlock = nullptr;
- lastBlock = firstChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
- // Mine 2011 more blocks at the old time, and check that CBV isn't setting the bit yet.
- for (int i=1; i<2012; i++) {
- lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ // Mine more blocks (4 less than the adjustment period) at the old time, and check that CBV isn't setting the bit yet.
+ for (uint32_t i = 1; i < mainnetParams.nMinerConfirmationWindow - 4; i++) {
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
// This works because VERSIONBITS_LAST_OLD_BLOCK_VERSION happens
// to be 4, and the bit we're testing happens to be bit 28.
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
@@ -284,13 +284,13 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Now mine 5 more blocks at the start time -- MTP should not have passed yet, so
// CBV should still not yet set the bit.
nTime = nStartTime;
- for (int i=2012; i<=2016; i++) {
- lastBlock = firstChain.Mine(2016+i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ for (uint32_t i = mainnetParams.nMinerConfirmationWindow - 4; i <= mainnetParams.nMinerConfirmationWindow; i++) {
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow + i, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
}
// Advance to the next period and transition to STARTED,
- lastBlock = firstChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = firstChain.Mine(mainnetParams.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
// so ComputeBlockVersion should now set the bit,
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// and should also be using the VERSIONBITS_TOP_BITS.
@@ -298,8 +298,8 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Check that ComputeBlockVersion will set the bit until nTimeout
nTime += 600;
- int blocksToMine = 4032; // test blocks for up to 2 time periods
- int nHeight = 6048;
+ uint32_t blocksToMine = mainnetParams.nMinerConfirmationWindow * 2; // test blocks for up to 2 time periods
+ uint32_t nHeight = mainnetParams.nMinerConfirmationWindow * 3;
// These blocks are all before nTimeout is reached.
while (nTime < nTimeout && blocksToMine > 0) {
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
@@ -313,7 +313,7 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
nTime = nTimeout;
// FAILED is only triggered at the end of a period, so CBV should be setting
// the bit until the period transition.
- for (int i=0; i<2015; i++) {
+ for (uint32_t i = 0; i < mainnetParams.nMinerConfirmationWindow - 1; i++) {
lastBlock = firstChain.Mine(nHeight+1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
nHeight += 1;
@@ -329,20 +329,20 @@ BOOST_AUTO_TEST_CASE(versionbits_computeblockversion)
// Mine one period worth of blocks, and check that the bit will be on for the
// next period.
- lastBlock = secondChain.Mine(2016, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Mine another period worth of blocks, signaling the new bit.
- lastBlock = secondChain.Mine(4032, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
+ lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow * 2, nTime, VERSIONBITS_TOP_BITS | (1<<bit)).Tip();
// After one period of setting the bit on each block, it should have locked in.
// We keep setting the bit for one more period though, until activation.
BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
// Now check that we keep mining the block until the end of this period, and
// then stop at the beginning of the next period.
- lastBlock = secondChain.Mine(6047, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
- BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit)) != 0);
- lastBlock = secondChain.Mine(6048, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ lastBlock = secondChain.Mine((mainnetParams.nMinerConfirmationWindow * 3) - 1, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
+ BOOST_CHECK((ComputeBlockVersion(lastBlock, mainnetParams) & (1 << bit)) != 0);
+ lastBlock = secondChain.Mine(mainnetParams.nMinerConfirmationWindow * 3, nTime, VERSIONBITS_LAST_OLD_BLOCK_VERSION).Tip();
BOOST_CHECK_EQUAL(ComputeBlockVersion(lastBlock, mainnetParams) & (1<<bit), 0);
// Finally, verify that after a soft fork has activated, CBV no longer uses
diff --git a/src/threadsafety.h b/src/threadsafety.h
index 33acddc65c..47e6b2ea38 100644
--- a/src/threadsafety.h
+++ b/src/threadsafety.h
@@ -54,15 +54,4 @@
#define ASSERT_EXCLUSIVE_LOCK(...)
#endif // __GNUC__
-// Utility class for indicating to compiler thread analysis that a mutex is
-// locked (when it couldn't be determined otherwise).
-struct SCOPED_LOCKABLE LockAnnotation
-{
- template <typename Mutex>
- explicit LockAnnotation(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
- {
- }
- ~LockAnnotation() UNLOCK_FUNCTION() {}
-};
-
#endif // BITCOIN_THREADSAFETY_H
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 9c022c9ad1..b43639d729 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -12,7 +12,6 @@
#include <sync.h>
#include <ui_interface.h>
#include <util/system.h>
-#include <util/strencodings.h>
#include <warnings.h>
diff --git a/src/tinyformat.h b/src/tinyformat.h
index 14b7cd3026..182f518a0b 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -1063,6 +1063,7 @@ std::string format(const std::string &fmt, const Args&... args)
} // namespace tinyformat
+/** Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for details) */
#define strprintf tfm::format
#endif // TINYFORMAT_H_INCLUDED
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 550e23b222..a1c730ba08 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <chainparams.h>
#include <torcontrol.h>
#include <util/strencodings.h>
#include <netbase.h>
@@ -412,7 +413,7 @@ public:
TorController(struct event_base* base, const std::string& target);
~TorController();
- /** Get name fo file to store private key in */
+ /** Get name of file to store private key in */
fs::path GetPrivateKeyFile();
/** Reconnect, after getting disconnected */
@@ -500,7 +501,7 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
}
return;
}
- service = LookupNumeric(std::string(service_id+".onion").c_str(), GetListenPort());
+ service = LookupNumeric(std::string(service_id+".onion").c_str(), Params().GetDefaultPort());
LogPrintf("tor: Got service ID %s, advertising service %s\n", service_id, service.ToString());
if (WriteBinaryFile(GetPrivateKeyFile(), private_key)) {
LogPrint(BCLog::TOR, "tor: Cached service private key to %s\n", GetPrivateKeyFile().string());
@@ -534,9 +535,8 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
if (private_key.empty()) // No private key, generate one
private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214
// Request hidden service, redirect port.
- // Note that the 'virtual' port doesn't have to be the same as our internal port, but this is just a convenient
- // choice. TODO; refactor the shutdown sequence some day.
- _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, GetListenPort(), GetListenPort()),
+ // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
+ _conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, Params().GetDefaultPort(), GetListenPort()),
std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2));
} else {
LogPrintf("tor: Authentication failed\n");
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 8447352c54..73fe2a8ee4 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,8 +5,6 @@
#include <txdb.h>
-#include <chainparams.h>
-#include <hash.h>
#include <random.h>
#include <pow.h>
#include <shutdown.h>
@@ -255,6 +253,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
// Load mapBlockIndex
while (pcursor->Valid()) {
boost::this_thread::interruption_point();
+ if (ShutdownRequested()) return false;
std::pair<char, uint256> key;
if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
CDiskBlockIndex diskindex;
diff --git a/src/txdb.h b/src/txdb.h
index d5a4bfaeb1..c4ece11503 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -37,6 +37,8 @@ static const int64_t nMaxBlockDBCache = 2;
// Unlike for the UTXO database, for the txindex scenario the leveldb cache make
// a meaningful difference: https://github.com/bitcoin/bitcoin/pull/8273#issuecomment-229601991
static const int64_t nMaxTxIndexCache = 1024;
+//! Max memory allocated to all block filter index caches combined in MiB.
+static const int64_t max_filter_index_cache = 1024;
//! Max memory allocated to coin DB specific cache (MiB)
static const int64_t nMaxCoinsDBCache = 8;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 68f47d5cce..cac7beb6a1 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -11,9 +11,8 @@
#include <validation.h>
#include <policy/policy.h>
#include <policy/fees.h>
+#include <policy/settings.h>
#include <reverse_iterator.h>
-#include <streams.h>
-#include <timedata.h>
#include <util/system.h>
#include <util/moneystr.h>
#include <util/time.h>
@@ -600,7 +599,7 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
CAmount txfee = 0;
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee);
assert(fCheckResult);
- UpdateCoins(tx, mempoolDuplicate, 1000000);
+ UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max());
}
void CTxMemPool::check(const CCoinsViewCache *pcoins) const
@@ -764,7 +763,7 @@ std::vector<CTxMemPool::indexed_transaction_set::const_iterator> CTxMemPool::Get
return iters;
}
-void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
+void CTxMemPool::queryHashes(std::vector<uint256>& vtxid) const
{
LOCK(cs);
auto iters = GetSortedDepthAndScore();
@@ -1090,4 +1089,16 @@ void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors,
}
}
+bool CTxMemPool::IsLoaded() const
+{
+ LOCK(cs);
+ return m_is_loaded;
+}
+
+void CTxMemPool::SetIsLoaded(bool loaded)
+{
+ LOCK(cs);
+ m_is_loaded = loaded;
+}
+
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 f7afaec8fc..ce0b762336 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -184,7 +184,7 @@ private:
const LockPoints& lp;
};
-// extracts a transaction hash from CTxMempoolEntry or CTransactionRef
+// extracts a transaction hash from CTxMemPoolEntry or CTransactionRef
struct mempoolentry_txid
{
typedef uint256 result_type;
@@ -455,6 +455,8 @@ private:
void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool m_is_loaded GUARDED_BY(cs){false};
+
public:
static const int ROLLING_FEE_HALFLIFE = 60 * 60 * 12; // public only for testing
@@ -494,7 +496,7 @@ public:
* By design, it is guaranteed that:
*
* 1. Locking both `cs_main` and `mempool.cs` will give a view of mempool
- * that is consistent with current chain tip (`chainActive` and
+ * that is consistent with current chain tip (`::ChainActive()` and
* `pcoinsTip`) and is fully populated. Fully populated means that if the
* current active chain is missing transactions that were present in a
* previously active chain, all the missing transactions will have been
@@ -588,7 +590,7 @@ public:
void clear();
void _clear() EXCLUSIVE_LOCKS_REQUIRED(cs); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
- void queryHashes(std::vector<uint256>& vtxid);
+ void queryHashes(std::vector<uint256>& vtxid) const;
bool isSpent(const COutPoint& outpoint) const;
unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n);
@@ -672,6 +674,12 @@ public:
*/
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) const;
+ /** @returns true if the mempool is fully loaded */
+ bool IsLoaded() const;
+
+ /** Sets the current loaded state */
+ void SetIsLoaded(bool loaded);
+
unsigned long size() const
{
LOCK(cs);
diff --git a/src/ui_interface.cpp b/src/ui_interface.cpp
index 16ab24686b..d310637145 100644
--- a/src/ui_interface.cpp
+++ b/src/ui_interface.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <ui_interface.h>
-#include <util/system.h>
#include <boost/signals2/last_value.hpp>
#include <boost/signals2/signal.hpp>
@@ -22,16 +21,13 @@ struct UISignals {
boost::signals2::signal<CClientUIInterface::NotifyBlockTipSig> NotifyBlockTip;
boost::signals2::signal<CClientUIInterface::NotifyHeaderTipSig> NotifyHeaderTip;
boost::signals2::signal<CClientUIInterface::BannedListChangedSig> BannedListChanged;
-} g_ui_signals;
+};
+static UISignals g_ui_signals;
#define ADD_SIGNALS_IMPL_WRAPPER(signal_name) \
boost::signals2::connection CClientUIInterface::signal_name##_connect(std::function<signal_name##Sig> fn) \
{ \
return g_ui_signals.signal_name.connect(fn); \
- } \
- void CClientUIInterface::signal_name##_disconnect(std::function<signal_name##Sig> fn) \
- { \
- return g_ui_signals.signal_name.disconnect(&fn); \
}
ADD_SIGNALS_IMPL_WRAPPER(ThreadSafeMessageBox);
@@ -69,13 +65,3 @@ void InitWarning(const std::string& str)
{
uiInterface.ThreadSafeMessageBox(str, "", CClientUIInterface::MSG_WARNING);
}
-
-std::string AmountHighWarn(const std::string& optname)
-{
- return strprintf(_("%s is set very high!"), optname);
-}
-
-std::string AmountErrMsg(const char* const optname, const std::string& strValue)
-{
- return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue);
-}
diff --git a/src/ui_interface.h b/src/ui_interface.h
index f1aebce3bb..5e0380dc45 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -69,6 +69,9 @@ public:
/** Force blocking, modal message box dialog (not just OS notification) */
MODAL = 0x10000000U,
+ /** Do not prepend error/warning prefix */
+ MSG_NOPREFIX = 0x20000000U,
+
/** Do not print contents of message to debug log */
SECURE = 0x40000000U,
@@ -81,8 +84,7 @@ public:
#define ADD_SIGNALS_DECL_WRAPPER(signal_name, rtype, ...) \
rtype signal_name(__VA_ARGS__); \
using signal_name##Sig = rtype(__VA_ARGS__); \
- boost::signals2::connection signal_name##_connect(std::function<signal_name##Sig> fn); \
- void signal_name##_disconnect(std::function<signal_name##Sig> fn);
+ boost::signals2::connection signal_name##_connect(std::function<signal_name##Sig> fn);
/** Show message box. */
ADD_SIGNALS_DECL_WRAPPER(ThreadSafeMessageBox, bool, const std::string& message, const std::string& caption, unsigned int style);
@@ -129,10 +131,6 @@ void InitWarning(const std::string& str);
/** Show error message **/
bool InitError(const std::string& str);
-std::string AmountHighWarn(const std::string& optname);
-
-std::string AmountErrMsg(const char* const optname, const std::string& strValue);
-
extern CClientUIInterface uiInterface;
#endif // BITCOIN_UI_INTERFACE_H
diff --git a/src/util/error.cpp b/src/util/error.cpp
new file mode 100644
index 0000000000..9331a92ad7
--- /dev/null
+++ b/src/util/error.cpp
@@ -0,0 +1,45 @@
+// Copyright (c) 2010-2018 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 <util/error.h>
+
+#include <util/system.h>
+
+std::string TransactionErrorString(const TransactionError err)
+{
+ switch (err) {
+ case TransactionError::OK:
+ return "No error";
+ case TransactionError::MISSING_INPUTS:
+ return "Missing inputs";
+ case TransactionError::ALREADY_IN_CHAIN:
+ return "Transaction already in block chain";
+ case TransactionError::P2P_DISABLED:
+ return "Peer-to-peer functionality missing or disabled";
+ case TransactionError::MEMPOOL_REJECTED:
+ return "Transaction rejected by AcceptToMemoryPool";
+ case TransactionError::MEMPOOL_ERROR:
+ return "AcceptToMemoryPool failed";
+ case TransactionError::INVALID_PSBT:
+ return "PSBT is not sane";
+ case TransactionError::PSBT_MISMATCH:
+ return "PSBTs not compatible (different transactions)";
+ case TransactionError::SIGHASH_MISMATCH:
+ return "Specified sighash value does not match existing value";
+ case TransactionError::MAX_FEE_EXCEEDED:
+ return "Fee exceeds maximum configured by -maxtxfee";
+ // no default case, so the compiler can warn about missing cases
+ }
+ assert(false);
+}
+
+std::string AmountHighWarn(const std::string& optname)
+{
+ return strprintf(_("%s is set very high!"), optname);
+}
+
+std::string AmountErrMsg(const char* const optname, const std::string& strValue)
+{
+ return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue);
+}
diff --git a/src/util/error.h b/src/util/error.h
new file mode 100644
index 0000000000..0fd474b962
--- /dev/null
+++ b/src/util/error.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2010-2018 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_ERROR_H
+#define BITCOIN_UTIL_ERROR_H
+
+/**
+ * util/error.h is a common place for definitions of simple error types and
+ * string functions. Types and functions defined here should not require any
+ * outside dependencies.
+ *
+ * Error types defined here can be used in different parts of the bitcoin
+ * codebase, to avoid the need to write boilerplate code catching and
+ * translating errors passed across wallet/node/rpc/gui code boundaries.
+ */
+
+#include <string>
+
+enum class TransactionError {
+ OK, //!< No error
+ MISSING_INPUTS,
+ ALREADY_IN_CHAIN,
+ P2P_DISABLED,
+ MEMPOOL_REJECTED,
+ MEMPOOL_ERROR,
+ INVALID_PSBT,
+ PSBT_MISMATCH,
+ SIGHASH_MISMATCH,
+ MAX_FEE_EXCEEDED,
+};
+
+std::string TransactionErrorString(const TransactionError error);
+
+std::string AmountHighWarn(const std::string& optname);
+
+std::string AmountErrMsg(const char* const optname, const std::string& strValue);
+
+#endif // BITCOIN_UTIL_ERROR_H
diff --git a/src/util/fees.cpp b/src/util/fees.cpp
new file mode 100644
index 0000000000..cf16d5e44f
--- /dev/null
+++ b/src/util/fees.cpp
@@ -0,0 +1,41 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 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 <policy/fees.h>
+
+#include <string>
+
+std::string StringForFeeReason(FeeReason reason) {
+ static const std::map<FeeReason, std::string> fee_reason_strings = {
+ {FeeReason::NONE, "None"},
+ {FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
+ {FeeReason::FULL_ESTIMATE, "Target 85% Threshold"},
+ {FeeReason::DOUBLE_ESTIMATE, "Double Target 95% Threshold"},
+ {FeeReason::CONSERVATIVE, "Conservative Double Target longer horizon"},
+ {FeeReason::MEMPOOL_MIN, "Mempool Min Fee"},
+ {FeeReason::PAYTXFEE, "PayTxFee set"},
+ {FeeReason::FALLBACK, "Fallback fee"},
+ {FeeReason::REQUIRED, "Minimum Required Fee"},
+ };
+ auto reason_string = fee_reason_strings.find(reason);
+
+ if (reason_string == fee_reason_strings.end()) return "Unknown";
+
+ return reason_string->second;
+}
+
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
+ static const std::map<std::string, FeeEstimateMode> fee_modes = {
+ {"UNSET", FeeEstimateMode::UNSET},
+ {"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
+ {"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
+ };
+ auto mode = fee_modes.find(mode_string);
+
+ if (mode == fee_modes.end()) return false;
+
+ fee_estimate_mode = mode->second;
+ return true;
+}
diff --git a/src/util/fees.h b/src/util/fees.h
new file mode 100644
index 0000000000..fc355ce9c2
--- /dev/null
+++ b/src/util/fees.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 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
+#define BITCOIN_UTIL_FEES_H
+
+#include <string>
+
+enum class FeeEstimateMode;
+enum class FeeReason;
+
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
+std::string StringForFeeReason(FeeReason reason);
+
+#endif // BITCOIN_UTIL_FEES_H
diff --git a/src/util/rbf.cpp b/src/util/rbf.cpp
new file mode 100644
index 0000000000..d520a9606d
--- /dev/null
+++ b/src/util/rbf.cpp
@@ -0,0 +1,17 @@
+// Copyright (c) 2016-2018 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 <util/rbf.h>
+
+#include <primitives/transaction.h>
+
+bool SignalsOptInRBF(const CTransaction &tx)
+{
+ for (const CTxIn &txin : tx.vin) {
+ if (txin.nSequence <= MAX_BIP125_RBF_SEQUENCE) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/util/rbf.h b/src/util/rbf.h
new file mode 100644
index 0000000000..d3ef110628
--- /dev/null
+++ b/src/util/rbf.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2016-2018 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_RBF_H
+#define BITCOIN_UTIL_RBF_H
+
+#include <cstdint>
+
+class CTransaction;
+
+static const uint32_t MAX_BIP125_RBF_SEQUENCE = 0xfffffffd;
+
+// Check whether the sequence numbers on this transaction are signaling
+// opt-in to replace-by-fee, according to BIP 125
+bool SignalsOptInRBF(const CTransaction &tx);
+
+#endif // BITCOIN_UTIL_RBF_H
diff --git a/src/util/strencodings.h b/src/util/strencodings.h
index cf77044094..7c4364a082 100644
--- a/src/util/strencodings.h
+++ b/src/util/strencodings.h
@@ -12,6 +12,7 @@
#include <attributes.h>
#include <cstdint>
+#include <iterator>
#include <string>
#include <vector>
@@ -121,28 +122,25 @@ NODISCARD bool ParseUInt64(const std::string& str, uint64_t *out);
NODISCARD bool ParseDouble(const std::string& str, double *out);
template<typename T>
-std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
+std::string HexStr(const T itbegin, const T itend)
{
std::string rv;
static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- rv.reserve((itend-itbegin)*3);
+ rv.reserve(std::distance(itbegin, itend) * 2);
for(T it = itbegin; it < itend; ++it)
{
unsigned char val = (unsigned char)(*it);
- if(fSpaces && it != itbegin)
- rv.push_back(' ');
rv.push_back(hexmap[val>>4]);
rv.push_back(hexmap[val&15]);
}
-
return rv;
}
template<typename T>
-inline std::string HexStr(const T& vch, bool fSpaces=false)
+inline std::string HexStr(const T& vch)
{
- return HexStr(vch.begin(), vch.end(), fSpaces);
+ return HexStr(vch.begin(), vch.end());
}
/**
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 9594dd81bf..87ff6e62ba 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -1,13 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <util/system.h>
#include <chainparamsbase.h>
-#include <random.h>
-#include <serialize.h>
#include <util/strencodings.h>
#include <stdarg.h>
@@ -60,10 +58,6 @@
#include <shlobj.h>
#endif
-#ifdef HAVE_SYS_PRCTL_H
-#include <sys/prctl.h>
-#endif
-
#ifdef HAVE_MALLOPT_ARENA_MAX
#include <malloc.h>
#endif
@@ -679,7 +673,7 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
{
std::string message = FormatException(pex, pszThread);
LogPrintf("\n\n************************\n%s\n", message);
- fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
+ tfm::format(std::cerr, "\n\n************************\n%s\n", message.c_str());
}
fs::path GetDefaultDataDir()
@@ -711,19 +705,16 @@ fs::path GetDefaultDataDir()
static fs::path g_blocks_path_cache_net_specific;
static fs::path pathCached;
static fs::path pathCachedNetSpecific;
-static CCriticalSection csPathCached;
+static RecursiveMutex csPathCached;
const fs::path &GetBlocksDir()
{
-
LOCK(csPathCached);
-
fs::path &path = g_blocks_path_cache_net_specific;
- // This can be called during exceptions by LogPrintf(), so we cache the
- // value so we don't have to do memory allocations after that.
- if (!path.empty())
- return path;
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
if (gArgs.IsArgSet("-blocksdir")) {
path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
@@ -743,15 +734,12 @@ const fs::path &GetBlocksDir()
const fs::path &GetDataDir(bool fNetSpecific)
{
-
LOCK(csPathCached);
-
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
- // This can be called during exceptions by LogPrintf(), so we cache the
- // value so we don't have to do memory allocations after that.
- if (!path.empty())
- return path;
+ // Cache the path to avoid calling fs::create_directories on every call of
+ // this function
+ if (!path.empty()) return path;
if (gArgs.IsArgSet("-datadir")) {
path = fs::system_complete(gArgs.GetArg("-datadir", ""));
@@ -939,7 +927,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
}
}
for (const std::string& to_include : includeconf) {
- fprintf(stderr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str());
+ tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str());
}
}
}
@@ -1089,11 +1077,12 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
fcntl(fileno(file), F_PREALLOCATE, &fst);
}
ftruncate(fileno(file), fst.fst_length);
-#elif defined(__linux__)
+#else
+ #if defined(__linux__)
// Version using posix_fallocate
off_t nEndPos = (off_t)offset + length;
- posix_fallocate(fileno(file), 0, nEndPos);
-#else
+ if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
+ #endif
// Fallback version
// TODO: just write one byte per block
static const char buf[65536] = {};
@@ -1137,22 +1126,6 @@ void runCommand(const std::string& strCommand)
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
}
-void RenameThread(const char* name)
-{
-#if defined(PR_SET_NAME)
- // Only the first 15 characters are used (16 - NUL terminator)
- ::prctl(PR_SET_NAME, name, 0, 0, 0);
-#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
- pthread_set_name_np(pthread_self(), name);
-
-#elif defined(MAC_OSX)
- pthread_setname_np(name);
-#else
- // Prevent warnings for unused parameters...
- (void)name;
-#endif
-}
-
void SetupEnvironment()
{
#ifdef HAVE_MALLOPT_ARENA_MAX
diff --git a/src/util/system.h b/src/util/system.h
index 54eb88e261..15d7b1b402 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -22,15 +22,14 @@
#include <sync.h>
#include <tinyformat.h>
#include <util/memory.h>
+#include <util/threadnames.h>
#include <util/time.h>
-#include <atomic>
#include <exception>
#include <map>
#include <set>
#include <stdint.h>
#include <string>
-#include <unordered_set>
#include <utility>
#include <vector>
@@ -84,6 +83,7 @@ fs::path GetDefaultDataDir();
// The blocks directory is always net specific.
const fs::path &GetBlocksDir();
const fs::path &GetDataDir(bool fNetSpecific = true);
+/** Tests only */
void ClearDatadirCache();
fs::path GetConfigFile(const std::string& confPath);
#ifdef WIN32
@@ -325,15 +325,12 @@ std::string HelpMessageOpt(const std::string& option, const std::string& message
*/
int GetNumCores();
-void RenameThread(const char* name);
-
/**
* .. and a wrapper that just calls func once
*/
template <typename Callable> void TraceThread(const char* name, Callable func)
{
- std::string s = strprintf("bitcoin-%s", name);
- RenameThread(s.c_str());
+ util::ThreadRename(name);
try
{
LogPrintf("%s thread start\n", name);
diff --git a/src/util/threadnames.cpp b/src/util/threadnames.cpp
new file mode 100644
index 0000000000..b221b0c975
--- /dev/null
+++ b/src/util/threadnames.cpp
@@ -0,0 +1,62 @@
+// Copyright (c) 2018 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 <atomic>
+#include <thread>
+
+#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
+#include <pthread.h>
+#include <pthread_np.h>
+#endif
+
+#include <util/threadnames.h>
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h> // For prctl, PR_SET_NAME, PR_GET_NAME
+#endif
+
+//! Set the thread's name at the process level. Does not affect the
+//! internal name.
+static void SetThreadName(const char* name)
+{
+#if defined(PR_SET_NAME)
+ // Only the first 15 characters are used (16 - NUL terminator)
+ ::prctl(PR_SET_NAME, name, 0, 0, 0);
+#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
+ pthread_set_name_np(pthread_self(), name);
+#elif defined(MAC_OSX)
+ pthread_setname_np(name);
+#else
+ // Prevent warnings for unused parameters...
+ (void)name;
+#endif
+}
+
+// If we have thread_local, just keep thread ID and name in a thread_local
+// global.
+#if defined(HAVE_THREAD_LOCAL)
+
+static thread_local std::string g_thread_name;
+const std::string& util::ThreadGetInternalName() { return g_thread_name; }
+//! Set the in-memory internal name for this thread. Does not affect the process
+//! name.
+static void SetInternalName(std::string name) { g_thread_name = std::move(name); }
+
+// Without thread_local available, don't handle internal name at all.
+#else
+
+static const std::string empty_string;
+const std::string& util::ThreadGetInternalName() { return empty_string; }
+static void SetInternalName(std::string name) { }
+#endif
+
+void util::ThreadRename(std::string&& name)
+{
+ SetThreadName(("bitcoin-" + name).c_str());
+ SetInternalName(std::move(name));
+}
diff --git a/src/util/threadnames.h b/src/util/threadnames.h
new file mode 100644
index 0000000000..aaf07b9bf8
--- /dev/null
+++ b/src/util/threadnames.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2018 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_THREADNAMES_H
+#define BITCOIN_UTIL_THREADNAMES_H
+
+#include <string>
+
+namespace util {
+//! Rename a thread both in terms of an internal (in-memory) name as well
+//! as its system thread name.
+void ThreadRename(std::string&&);
+
+//! Get the thread's internal (in-memory) name; used e.g. for identification in
+//! logging.
+const std::string& ThreadGetInternalName();
+
+} // namespace util
+
+#endif // BITCOIN_UTIL_THREADNAMES_H
diff --git a/src/util/time.cpp b/src/util/time.cpp
index c0ede98701..2b202ae95f 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -27,6 +27,20 @@ int64_t GetTime()
return now;
}
+template <typename T>
+T GetTime()
+{
+ const std::chrono::seconds mocktime{nMockTime.load(std::memory_order_relaxed)};
+
+ return std::chrono::duration_cast<T>(
+ mocktime.count() ?
+ mocktime :
+ std::chrono::microseconds{GetTimeMicros()});
+}
+template std::chrono::seconds GetTime();
+template std::chrono::milliseconds GetTime();
+template std::chrono::microseconds GetTime();
+
void SetMockTime(int64_t nMockTimeIn)
{
nMockTime.store(nMockTimeIn, std::memory_order_relaxed);
diff --git a/src/util/time.h b/src/util/time.h
index 68de1c156e..e4f9996777 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -8,27 +8,34 @@
#include <stdint.h>
#include <string>
+#include <chrono>
/**
- * GetTimeMicros() and GetTimeMillis() both return the system time, but in
- * different units. GetTime() returns the system time in seconds, but also
- * supports mocktime, where the time can be specified by the user, eg for
- * testing (eg with the setmocktime rpc, or -mocktime argument).
- *
- * TODO: Rework these functions to be type-safe (so that we don't inadvertently
- * compare numbers with different units, or compare a mocktime to system time).
+ * DEPRECATED
+ * Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
*/
-
int64_t GetTime();
+
+/** Returns the system time (not mockable) */
int64_t GetTimeMillis();
+/** Returns the system time (not mockable) */
int64_t GetTimeMicros();
+/** Returns the system time (not mockable) */
int64_t GetSystemTimeInSeconds(); // Like GetTime(), but not mockable
+
+/** For testing. Set e.g. with the setmocktime rpc, or -mocktime argument */
void SetMockTime(int64_t nMockTimeIn);
+/** For testing */
int64_t GetMockTime();
+
void MilliSleep(int64_t n);
+/** Return system time (or mocked time, if set) */
+template <typename T>
+T GetTime();
+
/**
- * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date,Time}
+ * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date}
* helper functions if possible.
*/
std::string FormatISO8601DateTime(int64_t nTime);
diff --git a/src/util/url.cpp b/src/util/url.cpp
new file mode 100644
index 0000000000..49eacbf2d0
--- /dev/null
+++ b/src/util/url.cpp
@@ -0,0 +1,21 @@
+// Copyright (c) 2015-2018 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 <util/url.h>
+
+#include <event2/http.h>
+#include <stdlib.h>
+#include <string>
+
+std::string urlDecode(const std::string &urlEncoded) {
+ std::string res;
+ if (!urlEncoded.empty()) {
+ char *decoded = evhttp_uridecode(urlEncoded.c_str(), false, nullptr);
+ if (decoded) {
+ res = std::string(decoded);
+ free(decoded);
+ }
+ }
+ return res;
+}
diff --git a/src/util/url.h b/src/util/url.h
new file mode 100644
index 0000000000..3d7315a338
--- /dev/null
+++ b/src/util/url.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2015-2018 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_URL_H
+#define BITCOIN_UTIL_URL_H
+
+#include <string>
+
+std::string urlDecode(const std::string &urlEncoded);
+
+#endif // BITCOIN_UTIL_URL_H
diff --git a/src/util/validation.cpp b/src/util/validation.cpp
new file mode 100644
index 0000000000..fe1f5a277e
--- /dev/null
+++ b/src/util/validation.cpp
@@ -0,0 +1,20 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 <util/validation.h>
+
+#include <consensus/validation.h>
+#include <tinyformat.h>
+
+/** Convert CValidationState to a human-readable message for logging */
+std::string FormatStateMessage(const CValidationState &state)
+{
+ return strprintf("%s%s (code %i)",
+ state.GetRejectReason(),
+ state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
+ state.GetRejectCode());
+}
+
+const std::string strMessageMagic = "Bitcoin Signed Message:\n";
diff --git a/src/util/validation.h b/src/util/validation.h
new file mode 100644
index 0000000000..32559853ee
--- /dev/null
+++ b/src/util/validation.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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_VALIDATION_H
+#define BITCOIN_UTIL_VALIDATION_H
+
+#include <string>
+
+class CValidationState;
+
+/** Convert CValidationState to a human-readable message for logging */
+std::string FormatStateMessage(const CValidationState &state);
+
+extern const std::string strMessageMagic;
+
+#endif // BITCOIN_UTIL_VALIDATION_H
diff --git a/src/validation.cpp b/src/validation.cpp
index 358992b74d..d39b78614c 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -8,10 +8,10 @@
#include <arith_uint256.h>
#include <chain.h>
#include <chainparams.h>
-#include <checkpoints.h>
#include <checkqueue.h>
#include <consensus/consensus.h>
#include <consensus/merkle.h>
+#include <consensus/tx_check.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <cuckoocache.h>
@@ -20,7 +20,7 @@
#include <index/txindex.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <policy/rbf.h>
+#include <policy/settings.h>
#include <pow.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
@@ -35,15 +35,19 @@
#include <txdb.h>
#include <txmempool.h>
#include <ui_interface.h>
+#include <uint256.h>
#include <undo.h>
-#include <util/system.h>
#include <util/moneystr.h>
+#include <util/rbf.h>
#include <util/strencodings.h>
+#include <util/system.h>
+#include <util/validation.h>
#include <validationinterface.h>
#include <warnings.h>
#include <future>
#include <sstream>
+#include <string>
#include <boost/algorithm/string/replace.hpp>
#include <boost/thread.hpp>
@@ -55,161 +59,29 @@
#define MICRO 0.000001
#define MILLI 0.001
-/**
- * Global state
- */
-namespace {
- struct CBlockIndexWorkComparator
- {
- bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
- // First sort by most total work, ...
- if (pa->nChainWork > pb->nChainWork) return false;
- if (pa->nChainWork < pb->nChainWork) return true;
+bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
+ // First sort by most total work, ...
+ if (pa->nChainWork > pb->nChainWork) return false;
+ if (pa->nChainWork < pb->nChainWork) return true;
- // ... then by earliest time received, ...
- if (pa->nSequenceId < pb->nSequenceId) return false;
- if (pa->nSequenceId > pb->nSequenceId) return true;
-
- // Use pointer address as tie breaker (should only happen with blocks
- // loaded from disk, as those all have id 0).
- if (pa < pb) return false;
- if (pa > pb) return true;
-
- // Identical blocks.
- return false;
- }
- };
-} // anon namespace
+ // ... then by earliest time received, ...
+ if (pa->nSequenceId < pb->nSequenceId) return false;
+ if (pa->nSequenceId > pb->nSequenceId) return true;
-enum DisconnectResult
-{
- DISCONNECT_OK, // All good.
- DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
- DISCONNECT_FAILED // Something else went wrong.
-};
-
-class ConnectTrace;
-
-/**
- * CChainState stores and provides an API to update our local knowledge of the
- * current best chain and header tree.
- *
- * It generally provides access to the current block tree, as well as functions
- * to provide new data, which it will appropriately validate and incorporate in
- * its state as necessary.
- *
- * Eventually, the API here is targeted at being exposed externally as a
- * consumable libconsensus library, so any functions added must only call
- * other class member functions, pure functions in other parts of the consensus
- * library, callbacks via the validation interface, or read/write-to-disk
- * functions (eventually this will also be via callbacks).
- */
-class CChainState {
-private:
- /**
- * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
- * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
- * missing the data for the block.
- */
- std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+ // Use pointer address as tie breaker (should only happen with blocks
+ // loaded from disk, as those all have id 0).
+ if (pa < pb) return false;
+ if (pa > pb) return true;
- /**
- * Every received block is assigned a unique and increasing identifier, so we
- * know which one to give priority in case of a fork.
- */
- CCriticalSection cs_nBlockSequenceId;
- /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
- int32_t nBlockSequenceId = 1;
- /** Decreasing counter (used by subsequent preciousblock calls). */
- int32_t nBlockReverseSequenceId = -1;
- /** chainwork for the last block that preciousblock has been applied to. */
- arith_uint256 nLastPreciousChainwork = 0;
-
- /** In order to efficiently track invalidity of headers, we keep the set of
- * blocks which we tried to connect and found to be invalid here (ie which
- * were set to BLOCK_FAILED_VALID since the last restart). We can then
- * walk this set and check if a new header is a descendant of something in
- * this set, preventing us from having to walk mapBlockIndex when we try
- * to connect a bad block and fail.
- *
- * While this is more complicated than marking everything which descends
- * from an invalid block as invalid at the time we discover it to be
- * invalid, doing so would require walking all of mapBlockIndex to find all
- * descendants. Since this case should be very rare, keeping track of all
- * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
- * well.
- *
- * Because we already walk mapBlockIndex in height-order at startup, we go
- * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
- * instead of putting things in this set.
- */
- std::set<CBlockIndex*> m_failed_blocks;
-
- /**
- * the ChainState CriticalSection
- * A lock that must be held when modifying this ChainState - held in ActivateBestChain()
- */
- CCriticalSection m_cs_chainstate;
-
-public:
- CChain chainActive;
- BlockMap mapBlockIndex GUARDED_BY(cs_main);
- std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
- CBlockIndex *pindexBestInvalid = nullptr;
-
- bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
-
- /**
- * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
- * that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
- */
- bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- // Block (dis)connection on a given view:
- DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
- bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
- CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- // Block disconnection on our pcoinsTip:
- bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- // Manual block validity manipulation:
- bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
- bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
- bool RewindBlockIndex(const CChainParams& params);
- bool LoadGenesisBlock(const CChainParams& chainparams);
-
- void PruneBlockIndexCandidates();
-
- void UnloadBlockIndex();
-
-private:
- bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
- CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /** Create a new block index entry for a given block hash */
- CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- /**
- * Make various assertions about the state of the block index.
- *
- * By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
- */
- void CheckBlockIndex(const Consensus::Params& consensusParams);
+ // Identical blocks.
+ return false;
+}
- void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+static CChainState g_chainstate;
+CChainState& ChainstateActive() { return g_chainstate; }
- bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-} g_chainstate;
+CChain& ChainActive() { return g_chainstate.m_chain; }
/**
* Mutex to guard access to validation specific variables, such as reading
@@ -223,8 +95,7 @@ private:
*/
RecursiveMutex cs_main;
-BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex;
-CChain& chainActive = g_chainstate.chainActive;
+BlockMap& mapBlockIndex = ::ChainstateActive().mapBlockIndex;
CBlockIndex *pindexBestHeader = nullptr;
Mutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
@@ -234,38 +105,32 @@ std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
bool fHavePruned = false;
bool fPruneMode = false;
-bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
-bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
uint256 hashAssumeValid;
arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
-CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
CBlockPolicyEstimator feeEstimator;
CTxMemPool mempool(&feeEstimator);
-std::atomic_bool g_is_mempool_loaded{false};
/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;
-const std::string strMessageMagic = "Bitcoin Signed Message:\n";
-
// Internal stuff
namespace {
- CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid;
+ CBlockIndex *&pindexBestInvalid = ::ChainstateActive().pindexBestInvalid;
/** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
* Pruned nodes may have entries where B is missing data.
*/
- std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = g_chainstate.mapBlocksUnlinked;
+ std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = ::ChainstateActive().mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile;
@@ -306,15 +171,7 @@ std::unique_ptr<CCoinsViewDB> pcoinsdbview;
std::unique_ptr<CCoinsViewCache> pcoinsTip;
std::unique_ptr<CBlockTreeDB> pblocktree;
-enum class FlushStateMode {
- NONE,
- IF_NEEDED,
- PERIODIC,
- ALWAYS
-};
-
// See definition for documentation
-static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
@@ -334,13 +191,13 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
// scheduled, so no flags are set.
flags = std::max(flags, 0);
- // CheckFinalTx() uses chainActive.Height()+1 to evaluate
+ // CheckFinalTx() uses ::ChainActive().Height()+1 to evaluate
// nLockTime because when IsFinalTx() is called within
// CBlock::AcceptBlock(), the height of the block *being*
// evaluated is what is used. Thus if we want to know if a
// transaction can be part of the *next* block, we need to call
- // IsFinalTx() with one more than chainActive.Height().
- const int nBlockHeight = chainActive.Height() + 1;
+ // IsFinalTx() with one more than ::ChainActive().Height().
+ const int nBlockHeight = ::ChainActive().Height() + 1;
// BIP113 requires that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
@@ -348,7 +205,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
// chain tip, so we use that to calculate the median time passed to
// IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set.
const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST)
- ? chainActive.Tip()->GetMedianTimePast()
+ ? ::ChainActive().Tip()->GetMedianTimePast()
: GetAdjustedTime();
return IsFinalTx(tx, nBlockHeight, nBlockTime);
@@ -361,9 +218,9 @@ bool TestLockPointValidity(const LockPoints* lp)
// If there are relative lock times then the maxInputBlock will be set
// If there are no relative lock times, the LockPoints don't depend on the chain
if (lp->maxInputBlock) {
- // Check whether chainActive is an extension of the block at which the LockPoints
+ // Check whether ::ChainActive() is an extension of the block at which the LockPoints
// calculation was valid. If not LockPoints are no longer valid
- if (!chainActive.Contains(lp->maxInputBlock)) {
+ if (!::ChainActive().Contains(lp->maxInputBlock)) {
return false;
}
}
@@ -377,17 +234,17 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
AssertLockHeld(cs_main);
AssertLockHeld(pool.cs);
- CBlockIndex* tip = chainActive.Tip();
+ CBlockIndex* tip = ::ChainActive().Tip();
assert(tip != nullptr);
CBlockIndex index;
index.pprev = tip;
- // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate
+ // CheckSequenceLocks() uses ::ChainActive().Height()+1 to evaluate
// height based locks because when SequenceLocks() is called within
// ConnectBlock(), the height of the block *being*
// evaluated is what is used.
// Thus if we want to know if a transaction can be part of the
- // *next* block, we need to use one more than chainActive.Height()
+ // *next* block, we need to use one more than ::ChainActive().Height()
index.nHeight = tip->nHeight + 1;
std::pair<int, int64_t> lockPair;
@@ -397,7 +254,7 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
lockPair.second = lp->time;
}
else {
- // pcoinsTip contains the UTXO set for chainActive.Tip()
+ // pcoinsTip contains the UTXO set for ::ChainActive().Tip()
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
std::vector<int> prevheights;
prevheights.resize(tx.vin.size());
@@ -459,23 +316,14 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
pcoinsTip->Uncache(removed);
}
-/** Convert CValidationState to a human-readable message for logging */
-std::string FormatStateMessage(const CValidationState &state)
-{
- return strprintf("%s%s (code %i)",
- state.GetRejectReason(),
- state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
- state.GetRejectCode());
-}
-
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
- if (IsInitialBlockDownload())
+ if (::ChainstateActive().IsInitialBlockDownload())
return false;
- if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))
+ if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))
return false;
- if (chainActive.Height() < pindexBestHeader->nHeight - 1)
+ if (::ChainActive().Height() < pindexBestHeader->nHeight - 1)
return false;
return true;
}
@@ -527,7 +375,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions &disconnectpool,
mempool.UpdateTransactionsFromBlock(vHashUpdate);
// We also need to remove any now-immature transactions
- mempool.removeForReorg(pcoinsTip.get(), chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ mempool.removeForReorg(pcoinsTip.get(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
// Re-limit mempool size, in case we added any transactions
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
}
@@ -568,6 +416,13 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, txdata);
}
+/**
+ * @param[out] coins_to_uncache Return any outpoints which were not previously present in the
+ * coins cache, but were added as a result of validating the tx
+ * for mempool acceptance. This allows the caller to optionally
+ * remove the cache additions if the associated transaction ends
+ * up being rejected by the mempool.
+ */
static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx,
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
bool bypass_limits, const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -585,28 +440,28 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
- return state.DoS(100, false, REJECT_INVALID, "coinbase");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "coinbase");
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason;
if (fRequireStandard && !IsStandardTx(tx, reason))
- return state.DoS(0, false, REJECT_NONSTANDARD, reason);
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, reason);
// Do not work on transactions that are too small.
// A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
// Transactions smaller than this are not relayed to reduce unnecessary malloc overhead.
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE)
- return state.DoS(0, false, REJECT_NONSTANDARD, "tx-size-small");
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "tx-size-small");
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
- return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
+ return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool?
if (pool.exists(hash)) {
- return state.Invalid(false, REJECT_DUPLICATE, "txn-already-in-mempool");
+ return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-in-mempool");
}
// Check for conflicts with in-memory transactions
@@ -630,19 +485,16 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// unconfirmed ancestors anyway; doing otherwise is hopelessly
// insecure.
bool fReplacementOptOut = true;
- if (fEnableReplacement)
+ for (const CTxIn &_txin : ptxConflicting->vin)
{
- for (const CTxIn &_txin : ptxConflicting->vin)
+ if (_txin.nSequence <= MAX_BIP125_RBF_SEQUENCE)
{
- if (_txin.nSequence <= MAX_BIP125_RBF_SEQUENCE)
- {
- fReplacementOptOut = false;
- break;
- }
+ fReplacementOptOut = false;
+ break;
}
}
if (fReplacementOptOut) {
- return state.Invalid(false, REJECT_DUPLICATE, "txn-mempool-conflict");
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_DUPLICATE, "txn-mempool-conflict");
}
setConflicts.insert(ptxConflicting->GetHash());
@@ -663,12 +515,16 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
+
+ // Note: this call may add txin.prevout to the coins cache
+ // (pcoinsTip.cacheCoins) by way of FetchCoin(). It should be removed
+ // later (via coins_to_uncache) if this tx turns out to be invalid.
if (!view.HaveCoin(txin.prevout)) {
// Are inputs missing because we already have the tx?
for (size_t out = 0; out < tx.vout.size(); out++) {
// Optimistically just do efficient check of cache for outputs
if (pcoinsTip->HaveCoinInCache(COutPoint(hash, out))) {
- return state.Invalid(false, REJECT_DUPLICATE, "txn-already-known");
+ return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known");
}
}
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
@@ -691,7 +547,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
// CoinsViewCache instead of create its own
if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
- return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
+ return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, REJECT_NONSTANDARD, "non-BIP68-final");
CAmount nFees = 0;
if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees)) {
@@ -700,11 +556,11 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// Check for non-standard pay-to-script-hash in inputs
if (fRequireStandard && !AreInputsStandard(tx, view))
- return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
// Check for non-standard witness in P2WSH
if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, view))
- return state.DoS(0, false, REJECT_NONSTANDARD, "bad-witness-nonstandard", true);
+ return state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false, REJECT_NONSTANDARD, "bad-witness-nonstandard");
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);
@@ -723,31 +579,26 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
}
- CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(),
+ CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, ::ChainActive().Height(),
fSpendsCoinbase, nSigOpsCost, lp);
unsigned int nSize = entry.GetTxSize();
- // Check that the transaction doesn't have an excessive number of
- // sigops, making it impossible to mine. Since the coinbase transaction
- // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
- // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
- // merely non-standard transaction.
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
- return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops",
strprintf("%d", nSigOpsCost));
CAmount mempoolRejectFee = pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (!bypass_limits && mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nModifiedFees, mempoolRejectFee));
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", strprintf("%d < %d", nModifiedFees, mempoolRejectFee));
}
// No transactions are allowed below minRelayTxFee except from disconnected blocks
if (!bypass_limits && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", false, strprintf("%d < %d", nModifiedFees, ::minRelayTxFee.GetFee(nSize)));
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met", strprintf("%d < %d", nModifiedFees, ::minRelayTxFee.GetFee(nSize)));
}
if (nAbsurdFee && nFees > nAbsurdFee)
- return state.Invalid(false,
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false,
REJECT_HIGHFEE, "absurdly-high-fee",
strprintf("%d > %d", nFees, nAbsurdFee));
@@ -759,7 +610,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
std::string errString;
if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
- return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString);
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString);
}
// A transaction that spends outputs that would be replaced by it is invalid. Now
@@ -771,8 +622,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
if (setConflicts.count(hashAncestor))
{
- return state.DoS(10, false,
- REJECT_INVALID, "bad-txns-spends-conflicting-tx", false,
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-spends-conflicting-tx",
strprintf("%s spends conflicting transaction %s",
hash.ToString(),
hashAncestor.ToString()));
@@ -814,8 +664,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
if (newFeeRate <= oldFeeRate)
{
- return state.DoS(0, false,
- REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "insufficient fee",
strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
hash.ToString(),
newFeeRate.ToString(),
@@ -843,8 +692,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
nConflictingSize += it->GetTxSize();
}
} else {
- return state.DoS(0, false,
- REJECT_NONSTANDARD, "too many potential replacements", false,
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too many potential replacements",
strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
hash.ToString(),
nConflictingCount,
@@ -863,8 +711,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// it's cheaper to just check if the new input refers to a
// tx that's in the mempool.
if (pool.exists(tx.vin[j].prevout.hash)) {
- return state.DoS(0, false,
- REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false,
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "replacement-adds-unconfirmed",
strprintf("replacement %s adds unconfirmed input, idx %d",
hash.ToString(), j));
}
@@ -876,8 +723,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// transactions would not be paid for.
if (nModifiedFees < nConflictingFees)
{
- return state.DoS(0, false,
- REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "insufficient fee",
strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)));
}
@@ -887,8 +733,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
{
- return state.DoS(0, false,
- REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "insufficient fee",
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
hash.ToString(),
FormatMoney(nDeltaFees),
@@ -909,8 +754,10 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
!CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
// Only the witness is missing, so the transaction itself may be fine.
- state.SetCorruptionPossible();
+ state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false,
+ state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
}
+ assert(IsTransactionReason(state.GetReason()));
return false; // state filled in by CheckInputs
}
@@ -929,7 +776,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack.
- unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), chainparams.GetConsensus());
+ unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(::ChainActive().Tip(), chainparams.GetConsensus());
if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, true, txdata)) {
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s",
__func__, hash.ToString(), FormatStateMessage(state));
@@ -967,7 +814,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (!bypass_limits) {
LimitMempoolSize(pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
if (!pool.exists(hash))
- return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full");
+ return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full");
}
}
@@ -984,12 +831,17 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
std::vector<COutPoint> coins_to_uncache;
bool res = AcceptToMemoryPoolWorker(chainparams, pool, state, tx, pfMissingInputs, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept);
if (!res) {
+ // Remove coins that were not present in the coins cache before calling ATMPW;
+ // this is to prevent memory DoS in case we receive a large number of
+ // invalid transactions that attempt to overrun the in-memory coins cache
+ // (`CCoinsViewCache::cacheCoins`).
+
for (const COutPoint& hashTx : coins_to_uncache)
pcoinsTip->Uncache(hashTx);
}
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
CValidationState stateDummy;
- FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
+ ::ChainstateActive().FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
return res;
}
@@ -1165,31 +1017,34 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
return nSubsidy;
}
-bool IsInitialBlockDownload()
+// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which
+// is a performance-related implementation detail. This function must be marked
+// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`)
+// can call it.
+//
+bool CChainState::IsInitialBlockDownload() const
{
- // Once this function has returned false, it must remain false.
- static std::atomic<bool> latchToFalse{false};
// Optimization: pre-test latch before taking the lock.
- if (latchToFalse.load(std::memory_order_relaxed))
+ if (m_cached_finished_ibd.load(std::memory_order_relaxed))
return false;
LOCK(cs_main);
- if (latchToFalse.load(std::memory_order_relaxed))
+ if (m_cached_finished_ibd.load(std::memory_order_relaxed))
return false;
if (fImporting || fReindex)
return true;
- if (chainActive.Tip() == nullptr)
+ if (m_chain.Tip() == nullptr)
return true;
- if (chainActive.Tip()->nChainWork < nMinimumChainWork)
+ if (m_chain.Tip()->nChainWork < nMinimumChainWork)
return true;
- if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
+ if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
return true;
LogPrintf("Leaving InitialBlockDownload (latching to false)\n");
- latchToFalse.store(true, std::memory_order_relaxed);
+ m_cached_finished_ibd.store(true, std::memory_order_relaxed);
return false;
}
-CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
+static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr;
static void AlertNotify(const std::string& strMessage)
{
@@ -1214,15 +1069,15 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
// (we assume we don't get stuck on a fork before finishing our initial sync)
- if (IsInitialBlockDownload())
+ if (::ChainstateActive().IsInitialBlockDownload())
return;
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
// of our head, drop it
- if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72)
+ if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72)
pindexBestForkTip = nullptr;
- if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6)))
+ if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6)))
{
if (!GetfLargeWorkForkFound() && pindexBestForkBase)
{
@@ -1255,7 +1110,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) E
AssertLockHeld(cs_main);
// If we are on a fork that is sufficiently large, set a warning flag
CBlockIndex* pfork = pindexNewForkTip;
- CBlockIndex* plonger = chainActive.Tip();
+ CBlockIndex* plonger = ::ChainActive().Tip();
while (pfork && pfork != plonger)
{
while (plonger && plonger->nHeight > pfork->nHeight)
@@ -1274,7 +1129,7 @@ static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) E
// the 7-block condition and from this always have the most-likely-to-cause-warning fork
if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) &&
pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) &&
- chainActive.Height() - pindexNewForkTip->nHeight < 72)
+ ::ChainActive().Height() - pindexNewForkTip->nHeight < 72)
{
pindexBestForkTip = pindexNewForkTip;
pindexBestForkBase = pfork;
@@ -1291,16 +1146,16 @@ void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(c
LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__,
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime()));
- CBlockIndex *tip = chainActive.Tip();
+ CBlockIndex *tip = ::ChainActive().Tip();
assert (tip);
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__,
- tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0),
+ tip->GetBlockHash().ToString(), ::ChainActive().Height(), log(tip->nChainWork.getdouble())/log(2.0),
FormatISO8601DateTime(tip->GetBlockTime()));
CheckForkWarningConditions();
}
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
- if (!state.CorruptionPossible()) {
+ if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID;
m_failed_blocks.insert(pindex);
setDirtyBlockIndex.insert(pindex);
@@ -1368,6 +1223,9 @@ void InitScriptExecutionCache() {
* which are matched. This is useful for checking blocks where we will likely never need the cache
* entry again.
*
+ * Note that we may set state.reason to NOT_STANDARD for extra soft-fork flags in flags, block-checking
+ * callers should probably reset it to CONSENSUS in such cases.
+ *
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
*/
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -1423,22 +1281,26 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// Check whether the failure was caused by a
// non-mandatory script verification check, such as
// non-standard DER encodings or non-null dummy
- // arguments; if so, don't trigger DoS protection to
- // avoid splitting the network between upgraded and
- // non-upgraded nodes.
+ // arguments; if so, ensure we return NOT_STANDARD
+ // instead of CONSENSUS to avoid downstream users
+ // splitting the network between upgraded and
+ // non-upgraded nodes by banning CONSENSUS-failing
+ // data providers.
CScriptCheck check2(coin.out, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
if (check2())
- return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
+ return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
- // Failures of other flags indicate a transaction that is
- // invalid in new blocks, e.g. an invalid P2SH. We DoS ban
- // such nodes as they are not following the protocol. That
- // said during an upgrade careful thought should be taken
- // as to the correct behavior - we may want to continue
- // peering with non-upgraded nodes even after soft-fork
- // super-majority signaling has occurred.
- return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
+ // MANDATORY flag failures correspond to
+ // ValidationInvalidReason::CONSENSUS. Because CONSENSUS
+ // failures are the most serious case of validation
+ // failures, we may need to consider using
+ // RECENT_CONSENSUS_CHANGE for any script failure that
+ // could be due to non-upgraded nodes which we may want to
+ // support, to avoid splitting the network (but this
+ // depends on the details of how net_processing handles
+ // such errors).
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
}
}
@@ -1453,9 +1315,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
return true;
}
-namespace {
-
-bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
+static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
@@ -1482,7 +1342,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint25
return true;
}
-static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
+bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex)
{
FlatFilePos pos = pindex->GetUndoPos();
if (pos.IsNull()) {
@@ -1514,25 +1374,25 @@ static bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex *pindex)
}
/** Abort with a message */
-static bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
+static bool AbortNode(const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
{
SetMiscWarning(strMessage);
LogPrintf("*** %s\n", strMessage);
- uiInterface.ThreadSafeMessageBox(
- userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage,
- "", CClientUIInterface::MSG_ERROR);
+ if (!userMessage.empty()) {
+ uiInterface.ThreadSafeMessageBox(userMessage, "", CClientUIInterface::MSG_ERROR | prefix);
+ } else {
+ uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details"), "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX);
+ }
StartShutdown();
return false;
}
-static bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="")
+static bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
{
- AbortNode(strMessage, userMessage);
+ AbortNode(strMessage, userMessage, prefix);
return state.Error(strMessage);
}
-} // namespace
-
/**
* Restore the UTXO in a Coin at a given COutPoint
* @param undo The Coin to be restored.
@@ -1664,8 +1524,8 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState&
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
-void ThreadScriptCheck() {
- RenameThread("bitcoin-scriptch");
+void ThreadScriptCheck(int worker_num) {
+ util::ThreadRename(strprintf("scriptch.%i", worker_num));
scriptcheckqueue.Thread();
}
@@ -1802,7 +1662,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// re-enforce that rule here (at least until we make it impossible for
// GetAdjustedTime() to go backward).
if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) {
- if (state.CorruptionPossible()) {
+ if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED) {
// We don't write down blocks to disk if they may have been
// corrupted, so this should be impossible unless we're having hardware
// problems.
@@ -1937,7 +1797,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
for (const auto& tx : block.vtx) {
for (size_t o = 0; o < tx->vout.size(); o++) {
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
- return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
}
}
@@ -1977,11 +1837,19 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
{
CAmount txfee = 0;
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, txfee)) {
+ if (!IsBlockReason(state.GetReason())) {
+ // CheckTxInputs may return MISSING_INPUTS or
+ // PREMATURE_SPEND but we can't return that, as it's not
+ // defined for a block, so we reset the reason flag to
+ // CONSENSUS here.
+ state.Invalid(ValidationInvalidReason::CONSENSUS, false,
+ state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
+ }
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
}
nFees += txfee;
if (!MoneyRange(nFees)) {
- return state.DoS(100, error("%s: accumulated fee in the block out of range.", __func__),
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__),
REJECT_INVALID, "bad-txns-accumulated-fee-outofrange");
}
@@ -1994,7 +1862,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
}
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
- return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__),
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__),
REJECT_INVALID, "bad-txns-nonfinal");
}
}
@@ -2005,7 +1873,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
// * witness (when witness enabled in flags and excludes coinbase)
nSigOpsCost += GetTransactionSigOpCost(tx, view, flags);
if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST)
- return state.DoS(100, error("ConnectBlock(): too many sigops"),
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
txdata.emplace_back(tx);
@@ -2013,9 +1881,20 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
{
std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
- if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr))
+ if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr)) {
+ if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) {
+ // CheckInputs may return NOT_STANDARD for extra flags we passed,
+ // but we can't return that, as it's not defined for a block, so
+ // we reset the reason flag to CONSENSUS here.
+ // In the event of a future soft-fork, we may need to
+ // consider whether rewriting to CONSENSUS or
+ // RECENT_CONSENSUS_CHANGE would be more appropriate.
+ state.Invalid(ValidationInvalidReason::CONSENSUS, false,
+ state.GetRejectCode(), state.GetRejectReason(), state.GetDebugMessage());
+ }
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state));
+ }
control.Add(vChecks);
}
@@ -2030,13 +1909,13 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
if (block.vtx[0]->GetValueOut() > blockReward)
- return state.DoS(100,
+ return state.Invalid(ValidationInvalidReason::CONSENSUS,
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
block.vtx[0]->GetValueOut(), blockReward),
REJECT_INVALID, "bad-cb-amount");
if (!control.Wait())
- return state.DoS(100, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), REJECT_INVALID, "block-validation-failed");
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
@@ -2064,16 +1943,12 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
return true;
}
-/**
- * Update the on-disk chain state.
- * The caches and indexes are flushed depending on the mode we're called with
- * if they're too large, if it's been a while since the last write,
- * or always and in all cases if we're in prune mode and are deleting files.
- *
- * If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
- * besides checking if we need to prune.
- */
-bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
+bool CChainState::FlushStateToDisk(
+ const CChainParams& chainparams,
+ CValidationState &state,
+ FlushStateMode mode,
+ int nManualPruneHeight)
+{
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
LOCK(cs_main);
static int64_t nLastWrite = 0;
@@ -2125,7 +2000,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
if (fDoFullFlush || fPeriodicWrite) {
// Depend on nMinDiskSpace to ensure we can write block index
if (!CheckDiskSpace(GetBlocksDir())) {
- return AbortNode(state, "Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
@@ -2160,7 +2035,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
// an overestimation, as most will delete an existing entry or
// overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * pcoinsTip->GetCacheSize())) {
- return AbortNode(state, "Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
// Flush the chainstate (which may refer to block index entries).
if (!pcoinsTip->Flush())
@@ -2171,7 +2046,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
}
if (full_flush_completed) {
// Update best block in wallet (so we can detect restored wallets).
- GetMainSignals().ChainStateFlushed(chainActive.GetLocator());
+ GetMainSignals().ChainStateFlushed(m_chain.GetLocator());
}
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error while flushing: ") + e.what());
@@ -2179,19 +2054,20 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
return true;
}
-void FlushStateToDisk() {
+void CChainState::ForceFlushStateToDisk() {
CValidationState state;
const CChainParams& chainparams = Params();
- if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
+ if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
-void PruneAndFlush() {
+void CChainState::PruneAndFlush() {
CValidationState state;
fCheckForPruning = true;
const CChainParams& chainparams = Params();
- if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
+
+ if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
@@ -2225,7 +2101,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
}
std::string warningMessages;
- if (!IsInitialBlockDownload())
+ if (!::ChainstateActive().IsInitialBlockDownload())
{
int nUpgraded = 0;
const CBlockIndex* pindex = pindexNew;
@@ -2263,7 +2139,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
}
-/** Disconnect chainActive's tip.
+/** Disconnect m_chain's tip.
* After calling, the mempool will be in an inconsistent state, with
* transactions from disconnected blocks being added to disconnectpool. You
* should make the mempool consistent again by calling UpdateMempoolForReorg.
@@ -2275,7 +2151,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
*/
bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
{
- CBlockIndex *pindexDelete = chainActive.Tip();
+ CBlockIndex *pindexDelete = m_chain.Tip();
assert(pindexDelete);
// Read block from disk.
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
@@ -2310,7 +2186,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha
}
}
- chainActive.SetTip(pindexDelete->pprev);
+ m_chain.SetTip(pindexDelete->pprev);
UpdateTip(pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
@@ -2388,14 +2264,14 @@ public:
};
/**
- * Connect a new block to chainActive. pblock is either nullptr or a pointer to a CBlock
+ * Connect a new block to m_chain. pblock is either nullptr or a pointer to a CBlock
* corresponding to pindexNew, to bypass loading it again from disk.
*
* The block is added to connectTrace if connection succeeds.
*/
bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
{
- assert(pindexNew->pprev == chainActive.Tip());
+ assert(pindexNew->pprev == m_chain.Tip());
// Read block from disk.
int64_t nTime1 = GetTimeMicros();
std::shared_ptr<const CBlock> pthisBlock;
@@ -2436,8 +2312,8 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
// Remove conflicting transactions from the mempool.;
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight);
disconnectpool.removeForBlock(blockConnecting.vtx);
- // Update chainActive & related variables.
- chainActive.SetTip(pindexNew);
+ // Update m_chain & related variables.
+ m_chain.SetTip(pindexNew);
UpdateTip(pindexNew, chainparams);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -2468,7 +2344,7 @@ CBlockIndex* CChainState::FindMostWorkChain() {
// Just going until the active chain is an optimization, as we know all blocks in it are valid already.
CBlockIndex *pindexTest = pindexNew;
bool fInvalidAncestor = false;
- while (pindexTest && !chainActive.Contains(pindexTest)) {
+ while (pindexTest && !m_chain.Contains(pindexTest)) {
assert(pindexTest->HaveTxsDownloaded() || pindexTest->nHeight == 0);
// Pruned nodes may have entries in setBlockIndexCandidates for
@@ -2511,7 +2387,7 @@ void CChainState::PruneBlockIndexCandidates() {
// Note that we can't delete the current block itself, as we may need to return to it later in case a
// reorganization to a better block fails.
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();
- while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) {
+ while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, m_chain.Tip())) {
setBlockIndexCandidates.erase(it++);
}
// Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates.
@@ -2526,13 +2402,13 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
{
AssertLockHeld(cs_main);
- const CBlockIndex *pindexOldTip = chainActive.Tip();
- const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
+ const CBlockIndex *pindexOldTip = m_chain.Tip();
+ const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork);
// Disconnect active blocks which are no longer in the best chain.
bool fBlocksDisconnected = false;
DisconnectedBlockTransactions disconnectpool;
- while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
+ while (m_chain.Tip() && m_chain.Tip() != pindexFork) {
if (!DisconnectTip(state, chainparams, &disconnectpool)) {
// This is likely a fatal error, but keep the mempool consistent,
// just in case. Only remove from the mempool in this case.
@@ -2564,7 +2440,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
- if (!state.CorruptionPossible()) {
+ if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
InvalidChainFound(vpindexToConnect.front());
}
state = CValidationState();
@@ -2580,7 +2456,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
}
} else {
PruneBlockIndexCandidates();
- if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) {
+ if (!pindexOldTip || m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) {
// We're in a better position than we were. Return temporarily to release the lock.
fContinue = false;
break;
@@ -2616,7 +2492,7 @@ static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
if (pindexHeader != pindexHeaderOld) {
fNotify = true;
- fInitialBlockDownload = IsInitialBlockDownload();
+ fInitialBlockDownload = ::ChainstateActive().IsInitialBlockDownload();
pindexHeaderOld = pindexHeader;
}
}
@@ -2626,6 +2502,14 @@ static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
}
}
+static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) {
+ AssertLockNotHeld(cs_main);
+
+ if (GetMainSignals().CallbacksPending() > 10) {
+ SyncWithValidationInterfaceQueue();
+ }
+}
+
/**
* Make the best chain active, in multiple steps. The result is either failure
* or an activated best chain. pblock is either nullptr or a pointer to a block
@@ -2654,19 +2538,17 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
do {
boost::this_thread::interruption_point();
- if (GetMainSignals().CallbacksPending() > 10) {
- // Block until the validation queue drains. This should largely
- // never happen in normal operation, however may happen during
- // reindex, causing memory blowup if we run too far ahead.
- // Note that if a validationinterface callback ends up calling
- // ActivateBestChain this may lead to a deadlock! We should
- // probably have a DEBUG_LOCKORDER test for this in the future.
- SyncWithValidationInterfaceQueue();
- }
+ // Block until the validation queue drains. This should largely
+ // never happen in normal operation, however may happen during
+ // reindex, causing memory blowup if we run too far ahead.
+ // Note that if a validationinterface callback ends up calling
+ // ActivateBestChain this may lead to a deadlock! We should
+ // probably have a DEBUG_LOCKORDER test for this in the future.
+ LimitValidationInterfaceQueue();
{
LOCK(cs_main);
- CBlockIndex* starting_tip = chainActive.Tip();
+ CBlockIndex* starting_tip = m_chain.Tip();
bool blocks_connected = false;
do {
// We absolutely may not unlock cs_main until we've made forward progress
@@ -2678,7 +2560,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
}
// Whether we have anything to do at all.
- if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip()) {
+ if (pindexMostWork == nullptr || pindexMostWork == m_chain.Tip()) {
break;
}
@@ -2692,16 +2574,16 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
// Wipe cache, we may need another branch now.
pindexMostWork = nullptr;
}
- pindexNewTip = chainActive.Tip();
+ pindexNewTip = m_chain.Tip();
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
assert(trace.pblock && trace.pindex);
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
}
- } while (!chainActive.Tip() || (starting_tip && CBlockIndexWorkComparator()(chainActive.Tip(), starting_tip)));
+ } while (!m_chain.Tip() || (starting_tip && CBlockIndexWorkComparator()(m_chain.Tip(), starting_tip)));
if (!blocks_connected) return true;
- const CBlockIndex* pindexFork = chainActive.FindFork(starting_tip);
+ const CBlockIndex* pindexFork = m_chain.FindFork(starting_tip);
bool fInitialDownload = IsInitialBlockDownload();
// Notify external listeners about the new tip.
@@ -2736,22 +2618,22 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
}
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
- return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
+ return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
}
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
{
{
LOCK(cs_main);
- if (pindex->nChainWork < chainActive.Tip()->nChainWork) {
+ if (pindex->nChainWork < m_chain.Tip()->nChainWork) {
// Nothing to do, this block is not at the tip.
return true;
}
- if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) {
+ if (m_chain.Tip()->nChainWork > nLastPreciousChainwork) {
// The chain has been extended since the last call, reset the counter.
nBlockReverseSequenceId = -1;
}
- nLastPreciousChainwork = chainActive.Tip()->nChainWork;
+ nLastPreciousChainwork = m_chain.Tip()->nChainWork;
setBlockIndexCandidates.erase(pindex);
pindex->nSequenceId = nBlockReverseSequenceId;
if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {
@@ -2768,75 +2650,96 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par
return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
}
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
- return g_chainstate.PreciousBlock(state, params, pindex);
+ return ::ChainstateActive().PreciousBlock(state, params, pindex);
}
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{
- AssertLockHeld(cs_main);
+ CBlockIndex* to_mark_failed = pindex;
+ bool pindex_was_in_chain = false;
+ int disconnected = 0;
- // We first disconnect backwards and then mark the blocks as invalid.
- // This prevents a case where pruned nodes may fail to invalidateblock
- // and be left unable to start as they have no tip candidates (as there
- // are no blocks that meet the "have data and are not invalid per
- // nStatus" criteria for inclusion in setBlockIndexCandidates).
+ // Disconnect (descendants of) pindex, and mark them invalid.
+ while (true) {
+ if (ShutdownRequested()) break;
- bool pindex_was_in_chain = false;
- CBlockIndex *invalid_walk_tip = chainActive.Tip();
+ // Make sure the queue of validation callbacks doesn't grow unboundedly.
+ LimitValidationInterfaceQueue();
- DisconnectedBlockTransactions disconnectpool;
- while (chainActive.Contains(pindex)) {
+ LOCK(cs_main);
+ if (!m_chain.Contains(pindex)) break;
pindex_was_in_chain = true;
- // ActivateBestChain considers blocks already in chainActive
- // unconditionally valid already, so force disconnect away from it.
- if (!DisconnectTip(state, chainparams, &disconnectpool)) {
- // It's probably hopeless to try to make the mempool consistent
- // here if DisconnectTip failed, but we can try.
- UpdateMempoolForReorg(disconnectpool, false);
- return false;
- }
- }
+ CBlockIndex *invalid_walk_tip = m_chain.Tip();
- // Now mark the blocks we just disconnected as descendants invalid
- // (note this may not be all descendants).
- while (pindex_was_in_chain && invalid_walk_tip != pindex) {
- invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
+ // ActivateBestChain considers blocks already in m_chain
+ // unconditionally valid already, so force disconnect away from it.
+ DisconnectedBlockTransactions disconnectpool;
+ bool ret = DisconnectTip(state, chainparams, &disconnectpool);
+ // DisconnectTip will add transactions to disconnectpool.
+ // Adjust the mempool to be consistent with the new tip, adding
+ // transactions back to the mempool if disconnecting was successful,
+ // and we're not doing a very deep invalidation (in which case
+ // keeping the mempool up to date is probably futile anyway).
+ UpdateMempoolForReorg(disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret);
+ if (!ret) return false;
+ assert(invalid_walk_tip->pprev == m_chain.Tip());
+
+ // We immediately mark the disconnected blocks as invalid.
+ // This prevents a case where pruned nodes may fail to invalidateblock
+ // and be left unable to start as they have no tip candidates (as there
+ // are no blocks that meet the "have data and are not invalid per
+ // nStatus" criteria for inclusion in setBlockIndexCandidates).
+ invalid_walk_tip->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(invalid_walk_tip);
setBlockIndexCandidates.erase(invalid_walk_tip);
- invalid_walk_tip = invalid_walk_tip->pprev;
- }
+ setBlockIndexCandidates.insert(invalid_walk_tip->pprev);
+ if (invalid_walk_tip->pprev == to_mark_failed && (to_mark_failed->nStatus & BLOCK_FAILED_VALID)) {
+ // We only want to mark the last disconnected block as BLOCK_FAILED_VALID; its children
+ // need to be BLOCK_FAILED_CHILD instead.
+ to_mark_failed->nStatus = (to_mark_failed->nStatus ^ BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;
+ setDirtyBlockIndex.insert(to_mark_failed);
+ }
- // Mark the block itself as invalid.
- pindex->nStatus |= BLOCK_FAILED_VALID;
- setDirtyBlockIndex.insert(pindex);
- setBlockIndexCandidates.erase(pindex);
- m_failed_blocks.insert(pindex);
+ // Track the last disconnected block, so we can correct its BLOCK_FAILED_CHILD status in future
+ // iterations, or, if it's the last one, call InvalidChainFound on it.
+ to_mark_failed = invalid_walk_tip;
+ }
- // DisconnectTip will add transactions to disconnectpool; try to add these
- // back to the mempool.
- UpdateMempoolForReorg(disconnectpool, true);
+ {
+ LOCK(cs_main);
+ if (m_chain.Contains(to_mark_failed)) {
+ // If the to-be-marked invalid block is in the active chain, something is interfering and we can't proceed.
+ return false;
+ }
- // The resulting new best tip may not be in setBlockIndexCandidates anymore, so
- // add it again.
- BlockMap::iterator it = mapBlockIndex.begin();
- while (it != mapBlockIndex.end()) {
- if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
- setBlockIndexCandidates.insert(it->second);
+ // Mark pindex (or the last disconnected block) as invalid, even when it never was in the main chain
+ to_mark_failed->nStatus |= BLOCK_FAILED_VALID;
+ setDirtyBlockIndex.insert(to_mark_failed);
+ setBlockIndexCandidates.erase(to_mark_failed);
+ m_failed_blocks.insert(to_mark_failed);
+
+ // The resulting new best tip may not be in setBlockIndexCandidates anymore, so
+ // add it again.
+ BlockMap::iterator it = mapBlockIndex.begin();
+ while (it != mapBlockIndex.end()) {
+ if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, m_chain.Tip())) {
+ setBlockIndexCandidates.insert(it->second);
+ }
+ it++;
}
- it++;
- }
- InvalidChainFound(pindex);
+ InvalidChainFound(to_mark_failed);
+ }
// Only notify about a new block tip if the active chain was modified.
if (pindex_was_in_chain) {
- uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
+ uiInterface.NotifyBlockTip(IsInitialBlockDownload(), to_mark_failed->pprev);
}
return true;
}
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
- return g_chainstate.InvalidateBlock(state, chainparams, pindex);
+ return ::ChainstateActive().InvalidateBlock(state, chainparams, pindex);
}
void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
@@ -2850,7 +2753,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) {
it->second->nStatus &= ~BLOCK_FAILED_MASK;
setDirtyBlockIndex.insert(it->second);
- if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) {
+ if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), it->second)) {
setBlockIndexCandidates.insert(it->second);
}
if (it->second == pindexBestInvalid) {
@@ -2874,7 +2777,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
}
void ResetBlockFailureFlags(CBlockIndex *pindex) {
- return g_chainstate.ResetBlockFailureFlags(pindex);
+ return ::ChainstateActive().ResetBlockFailureFlags(pindex);
}
CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
@@ -2942,7 +2845,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi
LOCK(cs_nBlockSequenceId);
pindex->nSequenceId = nBlockSequenceId++;
}
- if (chainActive.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) {
+ if (m_chain.Tip() == nullptr || !setBlockIndexCandidates.value_comp()(pindex, m_chain.Tip())) {
setBlockIndexCandidates.insert(pindex);
}
std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> range = mapBlocksUnlinked.equal_range(pindex);
@@ -2998,7 +2901,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
bool out_of_space;
size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space);
if (out_of_space) {
- return AbortNode("Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode("Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
if (bytes_allocated != 0 && fPruneMode) {
fCheckForPruning = true;
@@ -3022,7 +2925,7 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un
bool out_of_space;
size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space);
if (out_of_space) {
- return AbortNode(state, "Disk space is low!", _("Error: Disk space is low!"));
+ return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX);
}
if (bytes_allocated != 0 && fPruneMode) {
fCheckForPruning = true;
@@ -3035,7 +2938,7 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
{
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
- return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed");
+ return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "high-hash", "proof of work failed");
return true;
}
@@ -3057,13 +2960,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
bool mutated;
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
if (block.hashMerkleRoot != hashMerkleRoot2)
- return state.DoS(100, false, REJECT_INVALID, "bad-txnmrklroot", true, "hashMerkleRoot mismatch");
+ return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txnmrklroot", "hashMerkleRoot mismatch");
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences
// of transactions in a block without affecting the merkle root of a block,
// while still invalidating it.
if (mutated)
- return state.DoS(100, false, REJECT_INVALID, "bad-txns-duplicate", true, "duplicate transaction");
+ return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txns-duplicate", "duplicate transaction");
}
// All potential-corruption validation must be done before we do any
@@ -3074,19 +2977,19 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
// Size limits
if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
- return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", "size limits failed");
// First transaction must be coinbase, the rest must not be
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
- return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-missing", "first tx is not coinbase");
for (unsigned int i = 1; i < block.vtx.size(); i++)
if (block.vtx[i]->IsCoinBase())
- return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-multiple", "more than one coinbase");
// Check transactions
for (const auto& tx : block.vtx)
if (!CheckTransaction(*tx, state, true))
- return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
+ return state.Invalid(state.GetReason(), false, state.GetRejectCode(), state.GetRejectReason(),
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
unsigned int nSigOps = 0;
@@ -3095,7 +2998,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
nSigOps += GetLegacySigOpCount(*tx);
}
if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST)
- return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-sigops", "out-of-bounds SigOpCount");
if (fCheckPOW && fCheckMerkleRoot)
block.fChecked = true;
@@ -3171,6 +3074,22 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
return commitment;
}
+//! Returns last CBlockIndex* that is a checkpoint
+static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+{
+ const MapCheckpoints& checkpoints = data.mapCheckpoints;
+
+ for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints))
+ {
+ const uint256& hash = i.second;
+ CBlockIndex* pindex = LookupBlockIndex(hash);
+ if (pindex) {
+ return pindex;
+ }
+ }
+ return nullptr;
+}
+
/** Context-dependent validity checks.
* By "context", we mean only the previous block headers, but not the UTXO
* set; UTXO-related validity checks are done in ConnectBlock().
@@ -3180,7 +3099,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
* in ConnectBlock().
* Note that -reindex-chainstate skips the validation that happens here!
*/
-static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime)
+static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
assert(pindexPrev != nullptr);
const int nHeight = pindexPrev->nHeight + 1;
@@ -3188,32 +3107,32 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
// Check proof of work
const Consensus::Params& consensusParams = params.GetConsensus();
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
- return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
+ return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "bad-diffbits", "incorrect proof of work");
// Check against checkpoints
if (fCheckpointsEnabled) {
// Don't accept any forks from the main chain prior to last checkpoint.
// GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's in our
// MapBlockIndex.
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(params.Checkpoints());
+ CBlockIndex* pcheckpoint = GetLastCheckpoint(params.Checkpoints());
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
+ return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint");
}
// Check timestamp against prev
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
- return state.Invalid(false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
+ return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "time-too-old", "block's timestamp is too early");
// Check timestamp
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
- return state.Invalid(false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");
+ return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, REJECT_INVALID, "time-too-new", "block timestamp too far in the future");
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
// check for version 2, 3 and 4 upgrades
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
- return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion),
+ return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion),
strprintf("rejected nVersion=0x%08x block", block.nVersion));
return true;
@@ -3243,7 +3162,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// Check that all transactions are finalized
for (const auto& tx : block.vtx) {
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
- return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-nonfinal", "non-final transaction");
}
}
@@ -3253,7 +3172,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
CScript expect = CScript() << nHeight;
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
- return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase");
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-height", "block height mismatch in coinbase");
}
}
@@ -3275,11 +3194,11 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// already does not permit it, it is impossible to trigger in the
// witness tree.
if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) {
- return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness reserved value size", __func__));
+ return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-witness-nonce-size", strprintf("%s : invalid witness reserved value size", __func__));
}
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) {
- return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__));
+ return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-witness-merkle-match", strprintf("%s : witness merkle commitment mismatch", __func__));
}
fHaveWitness = true;
}
@@ -3289,7 +3208,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
if (!fHaveWitness) {
for (const auto& tx : block.vtx) {
if (tx->HasWitness()) {
- return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__));
+ return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "unexpected-witness", strprintf("%s : unexpected witness data found", __func__));
}
}
}
@@ -3301,7 +3220,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
// the block hash, so we couldn't mark the block as permanently
// failed).
if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) {
- return state.DoS(100, false, REJECT_INVALID, "bad-blk-weight", false, strprintf("%s : weight limit failed", __func__));
+ return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-weight", strprintf("%s : weight limit failed", __func__));
}
return true;
@@ -3321,7 +3240,7 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
if (ppindex)
*ppindex = pindex;
if (pindex->nStatus & BLOCK_FAILED_MASK)
- return state.Invalid(error("%s: block %s is marked invalid", __func__, hash.ToString()), 0, "duplicate");
+ return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), 0, "duplicate");
return true;
}
@@ -3332,10 +3251,10 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
CBlockIndex* pindexPrev = nullptr;
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
- return state.DoS(10, error("%s: prev block not found", __func__), 0, "prev-blk-not-found");
+ return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), 0, "prev-blk-not-found");
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
- return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
+ return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
@@ -3372,7 +3291,7 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
setDirtyBlockIndex.insert(invalid_walk);
invalid_walk = invalid_walk->pprev;
}
- return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
+ return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
}
}
}
@@ -3396,7 +3315,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
LOCK(cs_main);
for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
- if (!g_chainstate.AcceptBlockHeader(header, state, chainparams, &pindex)) {
+ if (!::ChainstateActive().AcceptBlockHeader(header, state, chainparams, &pindex)) {
if (first_invalid) *first_invalid = header;
return false;
}
@@ -3446,13 +3365,13 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
// process an unrequested block if it's new and has enough work to
// advance our tip, and isn't too many blocks ahead.
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
- bool fHasMoreOrSameWork = (chainActive.Tip() ? pindex->nChainWork >= chainActive.Tip()->nChainWork : true);
+ bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainWork >= m_chain.Tip()->nChainWork : true);
// Blocks that are too out-of-order needlessly limit the effectiveness of
// pruning, because pruning will not delete block files that contain any
// blocks which are too close in height to the tip. Apply this test
// regardless of whether pruning is enabled; it should generally be safe to
// not process unrequested blocks.
- bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP));
+ bool fTooFarAhead = (pindex->nHeight > int(m_chain.Height() + MIN_BLOCKS_TO_KEEP));
// TODO: Decouple this function from the block download logic by removing fRequested
// This requires some new chain data structure to efficiently look up if a
@@ -3476,7 +3395,8 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
- if (state.IsInvalid() && !state.CorruptionPossible()) {
+ assert(IsBlockReason(state.GetReason()));
+ if (state.IsInvalid() && state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
}
@@ -3485,7 +3405,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
// Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW
// (but if it does not build on our best tip, let the SendMessages loop relay it)
- if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev)
+ if (!IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev)
GetMainSignals().NewPoWValidBlock(pindex, pblock);
// Write block to history file
@@ -3526,7 +3446,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
if (ret) {
// Store to disk
- ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
+ ret = ::ChainstateActive().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
}
if (!ret) {
GetMainSignals().BlockChecked(*pblock, state);
@@ -3537,7 +3457,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
NotifyHeaderTip();
CValidationState state; // Only used to report errors, not invalidity - ignore it
- if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
+ if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
return true;
@@ -3546,7 +3466,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
{
AssertLockHeld(cs_main);
- assert(pindexPrev && pindexPrev == chainActive.Tip());
+ assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
CCoinsViewCache viewNew(pcoinsTip.get());
uint256 block_hash(block.GetHash());
CBlockIndex indexDummy(block);
@@ -3561,7 +3481,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state));
- if (!g_chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
+ if (!::ChainstateActive().ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
return false;
assert(state.IsValid());
@@ -3635,11 +3555,11 @@ static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPr
assert(fPruneMode && nManualPruneHeight > 0);
LOCK2(cs_main, cs_LastBlockFile);
- if (chainActive.Tip() == nullptr)
+ if (::ChainActive().Tip() == nullptr)
return;
// last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
- unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP);
+ unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP);
int count=0;
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
@@ -3656,7 +3576,8 @@ void PruneBlockFilesManual(int nManualPruneHeight)
{
CValidationState state;
const CChainParams& chainparams = Params();
- if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
+ if (!::ChainstateActive().FlushStateToDisk(
+ chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
@@ -3679,14 +3600,14 @@ void PruneBlockFilesManual(int nManualPruneHeight)
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight)
{
LOCK2(cs_main, cs_LastBlockFile);
- if (chainActive.Tip() == nullptr || nPruneTarget == 0) {
+ if (::ChainActive().Tip() == nullptr || nPruneTarget == 0) {
return;
}
- if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) {
+ if ((uint64_t)::ChainActive().Tip()->nHeight <= nPruneAfterHeight) {
return;
}
- unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
+ unsigned int nLastBlockWeCanPrune = ::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
uint64_t nCurrentUsage = CalculateCurrentUsage();
// We don't check to prune until after we've allocated new space for files
// So we should leave a buffer under our target to account for another allocation
@@ -3700,7 +3621,7 @@ static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfte
// To avoid excessive prune events negating the benefit of high dbcache
// values, we should not prune too rapidly.
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
- if (IsInitialBlockDownload()) {
+ if (::ChainstateActive().IsInitialBlockDownload()) {
// Since this is only relevant during IBD, we use a fixed 10%
nBuffer += nPruneTarget / 10;
}
@@ -3792,6 +3713,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
sort(vSortedByHeight.begin(), vSortedByHeight.end());
for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight)
{
+ if (ShutdownRequested()) return false;
CBlockIndex* pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
@@ -3828,7 +3750,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
- if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
+ if (!::ChainstateActive().LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
return false;
// Load block file info
@@ -3882,33 +3804,23 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE
bool LoadChainTip(const CChainParams& chainparams)
{
AssertLockHeld(cs_main);
+ assert(!pcoinsTip->GetBestBlock().IsNull()); // Never called when the coins view is empty
- if (chainActive.Tip() && chainActive.Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
-
- if (pcoinsTip->GetBestBlock().IsNull() && mapBlockIndex.size() == 1) {
- // In case we just added the genesis block, connect it now, so
- // that we always have a chainActive.Tip() when we return.
- LogPrintf("%s: Connecting genesis block...\n", __func__);
- CValidationState state;
- if (!ActivateBestChain(state, chainparams)) {
- LogPrintf("%s: failed to activate chain (%s)\n", __func__, FormatStateMessage(state));
- return false;
- }
- }
+ if (::ChainActive().Tip() && ::ChainActive().Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
// Load pointer to end of best chain
CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
if (!pindex) {
return false;
}
- chainActive.SetTip(pindex);
+ ::ChainActive().SetTip(pindex);
- g_chainstate.PruneBlockIndexCandidates();
+ ::ChainstateActive().PruneBlockIndexCandidates();
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
- FormatISO8601DateTime(chainActive.Tip()->GetBlockTime()),
- GuessVerificationProgress(chainparams.TxData(), chainActive.Tip()));
+ ::ChainActive().Tip()->GetBlockHash().ToString(), ::ChainActive().Height(),
+ FormatISO8601DateTime(::ChainActive().Tip()->GetBlockTime()),
+ GuessVerificationProgress(chainparams.TxData(), ::ChainActive().Tip()));
return true;
}
@@ -3925,12 +3837,12 @@ CVerifyDB::~CVerifyDB()
bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth)
{
LOCK(cs_main);
- if (chainActive.Tip() == nullptr || chainActive.Tip()->pprev == nullptr)
+ if (::ChainActive().Tip() == nullptr || ::ChainActive().Tip()->pprev == nullptr)
return true;
// Verify blocks in the best chain
- if (nCheckDepth <= 0 || nCheckDepth > chainActive.Height())
- nCheckDepth = chainActive.Height();
+ if (nCheckDepth <= 0 || nCheckDepth > ::ChainActive().Height())
+ nCheckDepth = ::ChainActive().Height();
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CCoinsViewCache coins(coinsview);
@@ -3940,16 +3852,16 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CValidationState state;
int reportDone = 0;
LogPrintf("[0%%]..."); /* Continued */
- for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
+ for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
boost::this_thread::interruption_point();
- const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
+ const int percentageDone = std::max(1, std::min(99, (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
if (reportDone < percentageDone/10) {
// report every 10% step
LogPrintf("[%d%%]...", percentageDone); /* Continued */
reportDone = percentageDone/10;
}
uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false);
- if (pindex->nHeight <= chainActive.Height()-nCheckDepth)
+ if (pindex->nHeight <= ::ChainActive().Height()-nCheckDepth)
break;
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
// If pruning, only go back as far as we have data.
@@ -3976,7 +3888,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
- DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
+ DisconnectResult res = ::ChainstateActive().DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
@@ -3991,27 +3903,27 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
return true;
}
if (pindexFailure)
- return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
+ return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", ::ChainActive().Height() - pindexFailure->nHeight + 1, nGoodTransactions);
// store block count as we move pindex at check level >= 4
- int block_count = chainActive.Height() - pindex->nHeight;
+ int block_count = ::ChainActive().Height() - pindex->nHeight;
// check level 4: try reconnecting blocks
if (nCheckLevel >= 4) {
- while (pindex != chainActive.Tip()) {
+ while (pindex != ::ChainActive().Tip()) {
boost::this_thread::interruption_point();
- const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)));
+ const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(::ChainActive().Height() - pindex->nHeight)) / (double)nCheckDepth * 50)));
if (reportDone < percentageDone/10) {
// report every 10% step
LogPrintf("[%d%%]...", percentageDone); /* Continued */
reportDone = percentageDone/10;
}
uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false);
- pindex = chainActive.Next(pindex);
+ pindex = ::ChainActive().Next(pindex);
CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
- if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
+ if (!::ChainstateActive().ConnectBlock(block, state, pindex, coins, chainparams))
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
}
}
@@ -4110,41 +4022,117 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
}
bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
- return g_chainstate.ReplayBlocks(params, view);
+ return ::ChainstateActive().ReplayBlocks(params, view);
+}
+
+//! Helper for CChainState::RewindBlockIndex
+void CChainState::EraseBlockData(CBlockIndex* index)
+{
+ AssertLockHeld(cs_main);
+ assert(!m_chain.Contains(index)); // Make sure this block isn't active
+
+ // Reduce validity
+ index->nStatus = std::min<unsigned int>(index->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (index->nStatus & ~BLOCK_VALID_MASK);
+ // Remove have-data flags.
+ index->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);
+ // Remove storage location.
+ index->nFile = 0;
+ index->nDataPos = 0;
+ index->nUndoPos = 0;
+ // Remove various other things
+ index->nTx = 0;
+ index->nChainTx = 0;
+ index->nSequenceId = 0;
+ // Make sure it gets written.
+ setDirtyBlockIndex.insert(index);
+ // Update indexes
+ setBlockIndexCandidates.erase(index);
+ std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> ret = mapBlocksUnlinked.equal_range(index->pprev);
+ while (ret.first != ret.second) {
+ if (ret.first->second == index) {
+ mapBlocksUnlinked.erase(ret.first++);
+ } else {
+ ++ret.first;
+ }
+ }
+ // Mark parent as eligible for main chain again
+ if (index->pprev && index->pprev->IsValid(BLOCK_VALID_TRANSACTIONS) && index->pprev->HaveTxsDownloaded()) {
+ setBlockIndexCandidates.insert(index->pprev);
+ }
}
bool CChainState::RewindBlockIndex(const CChainParams& params)
{
- LOCK(cs_main);
+ // Note that during -reindex-chainstate we are called with an empty m_chain!
- // Note that during -reindex-chainstate we are called with an empty chainActive!
+ // First erase all post-segwit blocks without witness not in the main chain,
+ // as this can we done without costly DisconnectTip calls. Active
+ // blocks will be dealt with below (releasing cs_main in between).
+ {
+ LOCK(cs_main);
+ for (const auto& entry : mapBlockIndex) {
+ if (IsWitnessEnabled(entry.second->pprev, params.GetConsensus()) && !(entry.second->nStatus & BLOCK_OPT_WITNESS) && !m_chain.Contains(entry.second)) {
+ EraseBlockData(entry.second);
+ }
+ }
+ }
+ // Find what height we need to reorganize to.
+ CBlockIndex *tip;
int nHeight = 1;
- while (nHeight <= chainActive.Height()) {
- // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
- // blocks in ConnectBlock, we don't need to go back and
- // re-download/re-verify blocks from before segwit actually activated.
- if (IsWitnessEnabled(chainActive[nHeight - 1], params.GetConsensus()) && !(chainActive[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
- break;
+ {
+ LOCK(cs_main);
+ while (nHeight <= m_chain.Height()) {
+ // Although SCRIPT_VERIFY_WITNESS is now generally enforced on all
+ // blocks in ConnectBlock, we don't need to go back and
+ // re-download/re-verify blocks from before segwit actually activated.
+ if (IsWitnessEnabled(m_chain[nHeight - 1], params.GetConsensus()) && !(m_chain[nHeight]->nStatus & BLOCK_OPT_WITNESS)) {
+ break;
+ }
+ nHeight++;
}
- nHeight++;
- }
+ tip = m_chain.Tip();
+ }
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
+
CValidationState state;
- CBlockIndex* pindex = chainActive.Tip();
- while (chainActive.Height() >= nHeight) {
- if (fPruneMode && !(chainActive.Tip()->nStatus & BLOCK_HAVE_DATA)) {
- // If pruning, don't try rewinding past the HAVE_DATA point;
- // since older blocks can't be served anyway, there's
- // no need to walk further, and trying to DisconnectTip()
- // will fail (and require a needless reindex/redownload
- // of the blockchain).
- break;
- }
- if (!DisconnectTip(state, params, nullptr)) {
- return error("RewindBlockIndex: unable to disconnect block at height %i (%s)", pindex->nHeight, FormatStateMessage(state));
+ // Loop until the tip is below nHeight, or we reach a pruned block.
+ while (!ShutdownRequested()) {
+ {
+ LOCK(cs_main);
+ // Make sure nothing changed from under us (this won't happen because RewindBlockIndex runs before importing/network are active)
+ assert(tip == m_chain.Tip());
+ if (tip == nullptr || tip->nHeight < nHeight) break;
+ if (fPruneMode && !(tip->nStatus & BLOCK_HAVE_DATA)) {
+ // If pruning, don't try rewinding past the HAVE_DATA point;
+ // since older blocks can't be served anyway, there's
+ // no need to walk further, and trying to DisconnectTip()
+ // will fail (and require a needless reindex/redownload
+ // of the blockchain).
+ break;
+ }
+
+ // Disconnect block
+ if (!DisconnectTip(state, params, nullptr)) {
+ return error("RewindBlockIndex: unable to disconnect block at height %i (%s)", tip->nHeight, FormatStateMessage(state));
+ }
+
+ // Reduce validity flag and have-data flags.
+ // We do this after actual disconnecting, otherwise we'll end up writing the lack of data
+ // to disk before writing the chainstate, resulting in a failure to continue if interrupted.
+ // Note: If we encounter an insufficiently validated block that
+ // is on m_chain, it must be because we are a pruning node, and
+ // this block or some successor doesn't HAVE_DATA, so we were unable to
+ // rewind all the way. Blocks remaining on m_chain at this point
+ // must not have their validity reduced.
+ EraseBlockData(tip);
+
+ tip = tip->pprev;
}
+ // Make sure the queue of validation callbacks doesn't grow unboundedly.
+ LimitValidationInterfaceQueue();
+
// Occasionally flush state to disk.
if (!FlushStateToDisk(params, state, FlushStateMode::PERIODIC)) {
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
@@ -4152,69 +4140,32 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
}
}
- // Reduce validity flag and have-data flags.
- // We do this after actual disconnecting, otherwise we'll end up writing the lack of data
- // to disk before writing the chainstate, resulting in a failure to continue if interrupted.
- for (const auto& entry : mapBlockIndex) {
- CBlockIndex* pindexIter = entry.second;
-
- // Note: If we encounter an insufficiently validated block that
- // is on chainActive, it must be because we are a pruning node, and
- // this block or some successor doesn't HAVE_DATA, so we were unable to
- // rewind all the way. Blocks remaining on chainActive at this point
- // must not have their validity reduced.
- if (IsWitnessEnabled(pindexIter->pprev, params.GetConsensus()) && !(pindexIter->nStatus & BLOCK_OPT_WITNESS) && !chainActive.Contains(pindexIter)) {
- // Reduce validity
- pindexIter->nStatus = std::min<unsigned int>(pindexIter->nStatus & BLOCK_VALID_MASK, BLOCK_VALID_TREE) | (pindexIter->nStatus & ~BLOCK_VALID_MASK);
- // Remove have-data flags.
- pindexIter->nStatus &= ~(BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO);
- // Remove storage location.
- pindexIter->nFile = 0;
- pindexIter->nDataPos = 0;
- pindexIter->nUndoPos = 0;
- // Remove various other things
- pindexIter->nTx = 0;
- pindexIter->nChainTx = 0;
- pindexIter->nSequenceId = 0;
- // Make sure it gets written.
- setDirtyBlockIndex.insert(pindexIter);
- // Update indexes
- setBlockIndexCandidates.erase(pindexIter);
- std::pair<std::multimap<CBlockIndex*, CBlockIndex*>::iterator, std::multimap<CBlockIndex*, CBlockIndex*>::iterator> ret = mapBlocksUnlinked.equal_range(pindexIter->pprev);
- while (ret.first != ret.second) {
- if (ret.first->second == pindexIter) {
- mapBlocksUnlinked.erase(ret.first++);
- } else {
- ++ret.first;
- }
- }
- } else if (pindexIter->IsValid(BLOCK_VALID_TRANSACTIONS) && pindexIter->HaveTxsDownloaded()) {
- setBlockIndexCandidates.insert(pindexIter);
- }
- }
-
- if (chainActive.Tip() != nullptr) {
- // We can't prune block index candidates based on our tip if we have
- // no tip due to chainActive being empty!
- PruneBlockIndexCandidates();
+ {
+ LOCK(cs_main);
+ if (m_chain.Tip() != nullptr) {
+ // We can't prune block index candidates based on our tip if we have
+ // no tip due to m_chain being empty!
+ PruneBlockIndexCandidates();
- CheckBlockIndex(params.GetConsensus());
+ CheckBlockIndex(params.GetConsensus());
+ }
}
return true;
}
bool RewindBlockIndex(const CChainParams& params) {
- if (!g_chainstate.RewindBlockIndex(params)) {
+ if (!::ChainstateActive().RewindBlockIndex(params)) {
return false;
}
- if (chainActive.Tip() != nullptr) {
- // FlushStateToDisk can possibly read chainActive. Be conservative
+ LOCK(cs_main);
+ if (::ChainActive().Tip() != nullptr) {
+ // FlushStateToDisk can possibly read ::ChainActive(). Be conservative
// and skip it here, we're about to -reindex-chainstate anyway, so
// it'll get called a bunch real soon.
CValidationState state;
- if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
+ if (!::ChainstateActive().FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
return false;
}
@@ -4235,7 +4186,7 @@ void CChainState::UnloadBlockIndex() {
void UnloadBlockIndex()
{
LOCK(cs_main);
- chainActive.SetTip(nullptr);
+ ::ChainActive().SetTip(nullptr);
pindexBestInvalid = nullptr;
pindexBestHeader = nullptr;
mempool.clear();
@@ -4255,7 +4206,7 @@ void UnloadBlockIndex()
mapBlockIndex.clear();
fHavePruned = false;
- g_chainstate.UnloadBlockIndex();
+ ::ChainstateActive().UnloadBlockIndex();
}
bool LoadBlockIndex(const CChainParams& chainparams)
@@ -4285,7 +4236,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
LOCK(cs_main);
// Check whether we're already initialized by checking for genesis in
- // mapBlockIndex. Note that we can't use chainActive here, since it is
+ // mapBlockIndex. Note that we can't use m_chain here, since it is
// set based on the coins db, not the block index db, which is the only
// thing loaded at this point.
if (mapBlockIndex.count(chainparams.GenesisBlock().GetHash()))
@@ -4307,7 +4258,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
bool LoadGenesisBlock(const CChainParams& chainparams)
{
- return g_chainstate.LoadGenesisBlock(chainparams);
+ return ::ChainstateActive().LoadGenesisBlock(chainparams);
}
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos *dbp)
@@ -4372,7 +4323,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
CBlockIndex* pindex = LookupBlockIndex(hash);
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
CValidationState state;
- if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
+ if (::ChainstateActive().AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
nLoaded++;
}
if (state.IsError()) {
@@ -4409,7 +4360,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
head.ToString());
LOCK(cs_main);
CValidationState dummy;
- if (g_chainstate.AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
+ if (::ChainstateActive().AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
{
nLoaded++;
queue.push_back(pblockrecursive->GetHash());
@@ -4442,8 +4393,8 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
// During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain,
// so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when
- // iterating the block tree require that chainActive has been initialized.)
- if (chainActive.Height() < 0) {
+ // iterating the block tree require that m_chain has been initialized.)
+ if (m_chain.Height() < 0) {
assert(mapBlockIndex.size() <= 1);
return;
}
@@ -4487,7 +4438,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
if (pindex->pprev == nullptr) {
// Genesis block checks.
assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match.
- assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block.
+ assert(pindex == m_chain.Genesis()); // The current active chain's genesis block must be this block.
}
if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
@@ -4516,13 +4467,13 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
// Checks for not-invalid blocks.
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.
}
- if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == nullptr) {
+ if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && pindexFirstNeverProcessed == nullptr) {
if (pindexFirstInvalid == nullptr) {
// If this block sorts at least as good as the current tip and
// is valid and we have all data for its parents, it must be in
- // setBlockIndexCandidates. chainActive.Tip() must also be there
+ // setBlockIndexCandidates. m_chain.Tip() must also be there
// even if some data has been pruned.
- if (pindexFirstMissing == nullptr || pindex == chainActive.Tip()) {
+ if (pindexFirstMissing == nullptr || pindex == m_chain.Tip()) {
assert(setBlockIndexCandidates.count(pindex));
}
// If some parent is missing, then it could be that this block was in
@@ -4556,11 +4507,11 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
// - it has a descendant that at some point had more work than the
// tip, and
// - we tried switching to that descendant but were missing
- // data for some intermediate block between chainActive and the
+ // data for some intermediate block between m_chain and the
// tip.
- // So if this block is itself better than chainActive.Tip() and it wasn't in
+ // So if this block is itself better than m_chain.Tip() and it wasn't in
// setBlockIndexCandidates, then it must be in mapBlocksUnlinked.
- if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {
+ if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {
if (pindexFirstInvalid == nullptr) {
assert(foundInUnlinked);
}
@@ -4631,24 +4582,24 @@ CBlockFileInfo* GetBlockFileInfo(size_t n)
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
- return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
+ return VersionBitsState(::ChainActive().Tip(), params, pos, versionbitscache);
}
BIP9Stats VersionBitsTipStatistics(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
- return VersionBitsStatistics(chainActive.Tip(), params, pos);
+ return VersionBitsStatistics(::ChainActive().Tip(), params, pos);
}
int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
LOCK(cs_main);
- return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);
+ return VersionBitsStateSinceHeight(::ChainActive().Tip(), params, pos, versionbitscache);
}
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
-bool LoadMempool()
+bool LoadMempool(CTxMemPool& pool)
{
const CChainParams& chainparams = Params();
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
@@ -4683,12 +4634,12 @@ bool LoadMempool()
CAmount amountdelta = nFeeDelta;
if (amountdelta) {
- mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
+ pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
}
CValidationState state;
if (nTime + nExpiryTimeout > nNow) {
LOCK(cs_main);
- AcceptToMemoryPoolWithTime(chainparams, mempool, state, tx, nullptr /* pfMissingInputs */, nTime,
+ AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nullptr /* pfMissingInputs */, nTime,
nullptr /* plTxnReplaced */, false /* bypass_limits */, 0 /* nAbsurdFee */,
false /* test_accept */);
if (state.IsValid()) {
@@ -4698,7 +4649,7 @@ bool LoadMempool()
// wallet(s) having loaded it while we were processing
// mempool transactions; consider these as valid, instead of
// failed, but mark them as 'already there'
- if (mempool.exists(tx->GetHash())) {
+ if (pool.exists(tx->GetHash())) {
++already_there;
} else {
++failed;
@@ -4714,7 +4665,7 @@ bool LoadMempool()
file >> mapDeltas;
for (const auto& i : mapDeltas) {
- mempool.PrioritiseTransaction(i.first, i.second);
+ pool.PrioritiseTransaction(i.first, i.second);
}
} catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
@@ -4725,7 +4676,7 @@ bool LoadMempool()
return true;
}
-bool DumpMempool()
+bool DumpMempool(const CTxMemPool& pool)
{
int64_t start = GetTimeMicros();
@@ -4736,11 +4687,11 @@ bool DumpMempool()
LOCK(dump_mutex);
{
- LOCK(mempool.cs);
- for (const auto &i : mempool.mapDeltas) {
+ LOCK(pool.cs);
+ for (const auto &i : pool.mapDeltas) {
mapDeltas[i.first] = i.second;
}
- vinfo = mempool.infoAll();
+ vinfo = pool.infoAll();
}
int64_t mid = GetTimeMicros();
@@ -4808,4 +4759,5 @@ public:
delete (*it1).second;
mapBlockIndex.clear();
}
-} instance_of_cmaincleanup;
+};
+static CMainCleanup instance_of_cmaincleanup;
diff --git a/src/validation.h b/src/validation.h
index 4ef82ee2c7..638229952d 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -21,6 +21,7 @@
#include <versionbits.h>
#include <algorithm>
+#include <atomic>
#include <exception>
#include <map>
#include <memory>
@@ -30,10 +31,10 @@
#include <utility>
#include <vector>
-#include <atomic>
-
+class CChainState;
class CBlockIndex;
class CBlockTreeDB;
+class CBlockUndo;
class CChainParams;
class CCoinsViewDB;
class CInv;
@@ -44,6 +45,7 @@ class CTxMemPool;
class CValidationState;
struct ChainTxData;
+struct DisconnectedBlockTransactions;
struct PrecomputedTransactionData;
struct LockPoints;
@@ -53,12 +55,6 @@ static const bool DEFAULT_WHITELISTRELAY = true;
static const bool DEFAULT_WHITELISTFORCERELAY = false;
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
-//! -maxtxfee default
-static const CAmount DEFAULT_TRANSACTION_MAXFEE = COIN / 10;
-//! Discourage users to set fees higher than this amount (in satoshis) per kB
-static const CAmount HIGH_TX_FEE_PER_KB = COIN / 100;
-//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
-static const CAmount HIGH_MAX_TX_FEE = 100 * HIGH_TX_FEE_PER_KB;
/** Default for -limitancestorcount, max number of in-mempool ancestors */
static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */
@@ -114,15 +110,12 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
/** Maximum age of our tip in seconds for us to be considered current for fee estimation */
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;
-/** Default for -permitbaremultisig */
-static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
+static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
/** Default for -persistmempool */
static const bool DEFAULT_PERSIST_MEMPOOL = true;
-/** Default for -mempoolreplacement */
-static const bool DEFAULT_ENABLE_REPLACEMENT = true;
/** Default for using fee filter */
static const bool DEFAULT_FEEFILTER = true;
@@ -149,28 +142,22 @@ extern CScript COINBASE_FLAGS;
extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool;
-extern std::atomic_bool g_is_mempool_loaded;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern BlockMap& mapBlockIndex GUARDED_BY(cs_main);
-extern const std::string strMessageMagic;
extern Mutex g_best_block_mutex;
extern std::condition_variable g_best_block_cv;
extern uint256 g_best_block;
extern std::atomic_bool fImporting;
extern std::atomic_bool fReindex;
extern int nScriptCheckThreads;
-extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
extern CFeeRate minRelayTxFee;
-/** Absolute maximum transaction fee (in satoshis) used by wallet and mempool (rejects high fee in sendrawtransaction) */
-extern CAmount maxTxFee;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
extern int64_t nMaxTipAge;
-extern bool fEnableReplacement;
/** Block hash whose ancestors we will assume to have valid scripts without checking them. */
extern uint256 hashAssumeValid;
@@ -188,7 +175,7 @@ extern bool fHavePruned;
extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */
extern uint64_t nPruneTarget;
-/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
+/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ::ChainActive().Tip() will not be pruned. */
static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
@@ -258,9 +245,7 @@ bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_m
/** Unload database information */
void UnloadBlockIndex();
/** Run an instance of the script checking thread */
-void ThreadScriptCheck();
-/** Check whether we are doing an initial block download (synchronizing from disk or network) */
-bool IsInitialBlockDownload();
+void ThreadScriptCheck(int worker_num);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
/**
@@ -288,10 +273,6 @@ void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
*/
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
-/** Flush all state, indexes and buffers to disk. */
-void FlushStateToDisk();
-/** Prune block files and flush state to disk. */
-void PruneAndFlush();
/** Prune block files up to a given height */
void PruneBlockFilesManual(int nManualPruneHeight);
@@ -301,9 +282,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-/** Convert CValidationState to a human-readable message for logging */
-std::string FormatStateMessage(const CValidationState &state);
-
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
@@ -391,6 +369,8 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start);
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start);
+bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
+
/** Functions for validating blocks and updating the block tree */
/** Context-independent validity checks */
@@ -406,7 +386,7 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
bool IsNullDummyEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& params);
/** When there are blocks in the active chain with missing data, rewind the chainstate and remove them from the block index */
-bool RewindBlockIndex(const CChainParams& params);
+bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
/** Update uncommitted block structures (currently: only the witness reserved value). This is safe for submitted blocks. */
void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams);
@@ -425,7 +405,7 @@ public:
/** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
-inline CBlockIndex* LookupBlockIndex(const uint256& hash)
+inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
AssertLockHeld(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash);
@@ -435,6 +415,186 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash)
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+enum DisconnectResult
+{
+ DISCONNECT_OK, // All good.
+ DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
+ DISCONNECT_FAILED // Something else went wrong.
+};
+
+class ConnectTrace;
+
+/** @see CChainState::FlushStateToDisk */
+enum class FlushStateMode {
+ NONE,
+ IF_NEEDED,
+ PERIODIC,
+ ALWAYS
+};
+
+struct CBlockIndexWorkComparator
+{
+ bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const;
+};
+
+/**
+ * CChainState stores and provides an API to update our local knowledge of the
+ * current best chain and header tree.
+ *
+ * It generally provides access to the current block tree, as well as functions
+ * to provide new data, which it will appropriately validate and incorporate in
+ * its state as necessary.
+ *
+ * Eventually, the API here is targeted at being exposed externally as a
+ * consumable libconsensus library, so any functions added must only call
+ * other class member functions, pure functions in other parts of the consensus
+ * library, callbacks via the validation interface, or read/write-to-disk
+ * functions (eventually this will also be via callbacks).
+ */
+class CChainState {
+private:
+ /**
+ * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
+ * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
+ * missing the data for the block.
+ */
+ std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
+
+ /**
+ * Every received block is assigned a unique and increasing identifier, so we
+ * know which one to give priority in case of a fork.
+ */
+ CCriticalSection cs_nBlockSequenceId;
+ /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
+ int32_t nBlockSequenceId = 1;
+ /** Decreasing counter (used by subsequent preciousblock calls). */
+ int32_t nBlockReverseSequenceId = -1;
+ /** chainwork for the last block that preciousblock has been applied to. */
+ arith_uint256 nLastPreciousChainwork = 0;
+
+ /** In order to efficiently track invalidity of headers, we keep the set of
+ * blocks which we tried to connect and found to be invalid here (ie which
+ * were set to BLOCK_FAILED_VALID since the last restart). We can then
+ * walk this set and check if a new header is a descendant of something in
+ * this set, preventing us from having to walk mapBlockIndex when we try
+ * to connect a bad block and fail.
+ *
+ * While this is more complicated than marking everything which descends
+ * from an invalid block as invalid at the time we discover it to be
+ * invalid, doing so would require walking all of mapBlockIndex to find all
+ * descendants. Since this case should be very rare, keeping track of all
+ * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
+ * well.
+ *
+ * Because we already walk mapBlockIndex in height-order at startup, we go
+ * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
+ * instead of putting things in this set.
+ */
+ std::set<CBlockIndex*> m_failed_blocks;
+
+ /**
+ * the ChainState CriticalSection
+ * A lock that must be held when modifying this ChainState - held in ActivateBestChain()
+ */
+ CCriticalSection m_cs_chainstate;
+
+ /**
+ * Whether this chainstate is undergoing initial block download.
+ *
+ * Mutable because we need to be able to mark IsInitialBlockDownload()
+ * const, which latches this for caching purposes.
+ */
+ mutable std::atomic<bool> m_cached_finished_ibd{false};
+
+public:
+ //! The current chain of blockheaders we consult and build on.
+ //! @see CChain, CBlockIndex.
+ CChain m_chain;
+ BlockMap mapBlockIndex GUARDED_BY(cs_main);
+ std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
+ CBlockIndex *pindexBestInvalid = nullptr;
+
+ bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ /**
+ * Update the on-disk chain state.
+ * The caches and indexes are flushed depending on the mode we're called with
+ * if they're too large, if it's been a while since the last write,
+ * or always and in all cases if we're in prune mode and are deleting files.
+ *
+ * If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
+ * besides checking if we need to prune.
+ */
+ bool FlushStateToDisk(
+ const CChainParams& chainparams,
+ CValidationState &state,
+ FlushStateMode mode,
+ int nManualPruneHeight = 0);
+
+ //! Unconditionally flush all changes to disk.
+ void ForceFlushStateToDisk();
+
+ //! Prune blockfiles from the disk if necessary and then flush chainstate changes
+ //! if we pruned.
+ void PruneAndFlush();
+
+ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
+
+ /**
+ * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
+ * that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
+ */
+ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ // Block (dis)connection on a given view:
+ DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
+ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
+ CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ // Block disconnection on our pcoinsTip:
+ bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ // Manual block validity manipulation:
+ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
+ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
+ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
+ bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
+ bool LoadGenesisBlock(const CChainParams& chainparams);
+
+ void PruneBlockIndexCandidates();
+
+ void UnloadBlockIndex();
+
+ /** Check whether we are doing an initial block download (synchronizing from disk or network) */
+ bool IsInitialBlockDownload() const;
+
+private:
+ bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /** Create a new block index entry for a given block hash */
+ CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ /**
+ * Make various assertions about the state of the block index.
+ *
+ * By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
+ */
+ void CheckBlockIndex(const Consensus::Params& consensusParams);
+
+ void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+
+ //! Mark a block as not having block data
+ void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+};
+
/** Mark a block as precious and reorganize.
*
* May not be called in a
@@ -443,13 +603,16 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main);
/** Mark a block as invalid. */
-bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
/** Remove invalidity status from a block and its descendants. */
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-/** The currently-connected chain of blocks (protected by cs_main). */
-extern CChain& chainActive;
+/** @returns the most-work valid chainstate. */
+CChainState& ChainstateActive();
+
+/** @returns the most-work chain. */
+CChain& ChainActive();
/** Global variable that points to the coins database (protected by cs_main) */
extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;
@@ -486,10 +649,10 @@ static const unsigned int REJECT_HIGHFEE = 0x100;
CBlockFileInfo* GetBlockFileInfo(size_t n);
/** Dump the mempool to disk. */
-bool DumpMempool();
+bool DumpMempool(const CTxMemPool& pool);
/** Load the mempool from disk. */
-bool LoadMempool();
+bool LoadMempool(CTxMemPool& pool);
//! Check whether the block associated with this index entry is pruned or not.
inline bool IsBlockPruned(const CBlockIndex* pblockindex)
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 70c274d20e..59a620ab95 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -8,8 +8,6 @@
#include <primitives/block.h>
#include <scheduler.h>
#include <txmempool.h>
-#include <util/system.h>
-#include <validation.h>
#include <list>
#include <atomic>
@@ -25,7 +23,6 @@ struct ValidationInterfaceConnections {
boost::signals2::scoped_connection BlockDisconnected;
boost::signals2::scoped_connection TransactionRemovedFromMempool;
boost::signals2::scoped_connection ChainStateFlushed;
- boost::signals2::scoped_connection Broadcast;
boost::signals2::scoped_connection BlockChecked;
boost::signals2::scoped_connection NewPoWValidBlock;
};
@@ -37,7 +34,6 @@ struct MainSignalsInstance {
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
- boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
@@ -101,7 +97,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1));
conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1));
conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
- conns.Broadcast = g_signals.m_internals->Broadcast.connect(std::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, std::placeholders::_1, std::placeholders::_2));
conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
conns.NewPoWValidBlock = g_signals.m_internals->NewPoWValidBlock.connect(std::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
}
@@ -175,10 +170,6 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
});
}
-void CMainSignals::Broadcast(int64_t nBestBlockTime, CConnman* connman) {
- m_internals->Broadcast(nBestBlockTime, connman);
-}
-
void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
m_internals->BlockChecked(block, state);
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index f0374e8e78..3ce617b827 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -16,9 +16,7 @@ extern CCriticalSection cs_main;
class CBlock;
class CBlockIndex;
struct CBlockLocator;
-class CBlockIndex;
class CConnman;
-class CReserveScript;
class CValidationInterface;
class CValidationState;
class uint256;
@@ -134,8 +132,6 @@ protected:
* Called on a background thread.
*/
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
- /** Tells listeners to broadcast their data. */
- virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
/**
* Notifies listeners of a block validation result.
* If the provided CValidationState IsValid, the provided block
@@ -184,7 +180,6 @@ public:
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
void ChainStateFlushed(const CBlockLocator &);
- void Broadcast(int64_t nBestBlockTime, CConnman* connman);
void BlockChecked(const CBlock&, const CValidationState&);
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
};
diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp
index 87d2c4f06e..60bce66839 100644
--- a/src/wallet/coincontrol.cpp
+++ b/src/wallet/coincontrol.cpp
@@ -13,6 +13,7 @@ void CCoinControl::SetNull()
fAllowOtherInputs = false;
fAllowWatchOnly = false;
m_avoid_partial_spends = gArgs.GetBoolArg("-avoidpartialspends", DEFAULT_AVOIDPARTIALSPENDS);
+ m_avoid_address_reuse = false;
setSelected.clear();
m_feerate.reset();
fOverrideFeeRate = false;
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index 48a924abfb..249c402e4d 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -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.
@@ -34,8 +34,12 @@ public:
boost::optional<bool> m_signal_bip125_rbf;
//! Avoid partial use of funds sent to a given address
bool m_avoid_partial_spends;
+ //! Forbids inclusion of dirty (previously used) addresses
+ bool m_avoid_address_reuse;
//! Fee estimation mode to control arguments to estimateSmartFee
FeeEstimateMode m_fee_mode;
+ //! Minimum chain depth value for coin availability
+ int m_min_depth{0};
CCoinControl()
{
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index a255177e36..dd56ea10ab 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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/db.cpp b/src/wallet/db.cpp
index 99d880daa0..b5f90deabd 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -1,15 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <wallet/db.h>
-#include <addrman.h>
-#include <hash.h>
-#include <protocol.h>
#include <util/strencodings.h>
-#include <wallet/walletutil.h>
#include <stdint.h>
@@ -84,6 +80,14 @@ bool IsWalletLoaded(const fs::path& wallet_path)
return database && database->IsDatabaseLoaded(database_filename);
}
+fs::path WalletDataFilePath(const fs::path& wallet_path)
+{
+ fs::path env_directory;
+ std::string database_filename;
+ SplitWalletPath(wallet_path, env_directory, database_filename);
+ return env_directory / database_filename;
+}
+
/**
* @param[in] wallet_path Path to wallet directory. Or (for backwards compatibility only) a path to a berkeley btree data file inside a wallet directory.
* @param[out] database_filename Filename of berkeley btree data file inside the wallet directory.
@@ -399,13 +403,6 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(nullptr, nullptr, nullptr));
LogPrintf("Using wallet %s\n", file_path.string());
- // Wallet file must be a plain filename without a directory
- if (walletFile != fs::basename(walletFile) + fs::extension(walletFile))
- {
- errorStr = strprintf(_("Wallet %s resides outside wallet directory %s"), walletFile, walletDir.string());
- return false;
- }
-
if (!env->Open(true /* retry */)) {
errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
return false;
@@ -606,7 +603,9 @@ void BerkeleyBatch::Flush()
if (fReadOnly)
nMinutes = 1;
- env->dbenv->txn_checkpoint(nMinutes ? gArgs.GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
+ if (env) { // env is nullptr for dummy databases (i.e. in tests). Don't actually flush if env is nullptr so we don't segfault
+ env->dbenv->txn_checkpoint(nMinutes ? gArgs.GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
+ }
}
void BerkeleyDatabase::IncrementUpdateCounter()
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 9df965305a..b3856fbaf9 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -101,6 +101,9 @@ public:
/** Return whether a wallet database is currently loaded. */
bool IsWalletLoaded(const fs::path& wallet_path);
+/** Given a wallet directory path or legacy file path, return path to main data file in the wallet database. */
+fs::path WalletDataFilePath(const fs::path& wallet_path);
+
/** Get BerkeleyEnvironment and database filename given a wallet path. */
std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index a1c3a21d4b..46cf6b7616 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -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.
@@ -10,12 +10,10 @@
#include <wallet/wallet.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <policy/rbf.h>
-#include <validation.h> //for mempool access
-#include <txmempool.h>
#include <util/moneystr.h>
+#include <util/rbf.h>
#include <util/system.h>
-#include <net.h>
+#include <util/validation.h>
//! Check whether transaction has descendant in wallet or mempool, or has been
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
@@ -73,9 +71,11 @@ bool TransactionCanBeBumped(const CWallet* wallet, const uint256& txid)
return res == feebumper::Result::OK;
}
-Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, CAmount total_fee, std::vector<std::string>& errors,
- CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
+Result CreateTotalBumpTransaction(const CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, CAmount total_fee, std::vector<std::string>& errors,
+ CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
{
+ new_fee = total_fee;
+
auto locked_chain = wallet->chain().lock();
LOCK(wallet->cs_wallet);
errors.clear();
@@ -119,49 +119,33 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
// calculate the old fee and fee-rate
old_fee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
CFeeRate nOldFeeRate(old_fee, txSize);
- CFeeRate nNewFeeRate;
// The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
// future proof against changes to network wide policy for incremental relay
// fee that our node may not be aware of.
+ CFeeRate nodeIncrementalRelayFee = wallet->chain().relayIncrementalFee();
CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
- if (::incrementalRelayFee > walletIncrementalRelayFee) {
- walletIncrementalRelayFee = ::incrementalRelayFee;
+ if (nodeIncrementalRelayFee > walletIncrementalRelayFee) {
+ walletIncrementalRelayFee = nodeIncrementalRelayFee;
}
- if (total_fee > 0) {
- CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
- if (total_fee < minTotalFee) {
- errors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
- FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
- return Result::INVALID_PARAMETER;
- }
- CAmount requiredFee = GetRequiredFee(*wallet, maxNewTxSize);
- if (total_fee < requiredFee) {
- errors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
- FormatMoney(requiredFee)));
- return Result::INVALID_PARAMETER;
- }
- new_fee = total_fee;
- nNewFeeRate = CFeeRate(total_fee, maxNewTxSize);
- } else {
- new_fee = GetMinimumFee(*wallet, maxNewTxSize, coin_control, nullptr /* FeeCalculation */);
- nNewFeeRate = CFeeRate(new_fee, maxNewTxSize);
-
- // New fee rate must be at least old rate + minimum incremental relay rate
- // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
- // in that unit (fee per kb).
- // However, nOldFeeRate is a calculated value from the tx fee/size, so
- // add 1 satoshi to the result, because it may have been rounded down.
- if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
- nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
- new_fee = nNewFeeRate.GetFee(maxNewTxSize);
- }
+ CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + nodeIncrementalRelayFee.GetFee(maxNewTxSize);
+ if (total_fee < minTotalFee) {
+ errors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
+ FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(nodeIncrementalRelayFee.GetFee(maxNewTxSize))));
+ return Result::INVALID_PARAMETER;
+ }
+ CAmount requiredFee = GetRequiredFee(*wallet, maxNewTxSize);
+ if (total_fee < requiredFee) {
+ errors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
+ FormatMoney(requiredFee)));
+ return Result::INVALID_PARAMETER;
}
// Check that in all cases the new fee doesn't violate maxTxFee
- if (new_fee > maxTxFee) {
- errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
- FormatMoney(new_fee), FormatMoney(maxTxFee)));
+ const CAmount max_tx_fee = wallet->m_default_max_tx_fee;
+ if (new_fee > max_tx_fee) {
+ errors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)",
+ FormatMoney(new_fee), FormatMoney(max_tx_fee)));
return Result::WALLET_ERROR;
}
@@ -170,15 +154,15 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
// in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
// moment earlier. In this case, we report an error to the user, who may use total_fee to make an adjustment.
- CFeeRate minMempoolFeeRate = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+ CFeeRate minMempoolFeeRate = wallet->chain().mempoolMinFee();
+ CFeeRate nNewFeeRate = CFeeRate(total_fee, maxNewTxSize);
if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
errors.push_back(strprintf(
"New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "
- "the totalFee value should be at least %s or the settxfee value should be at least %s to add transaction",
+ "the totalFee value should be at least %s to add transaction",
FormatMoney(nNewFeeRate.GetFeePerK()),
FormatMoney(minMempoolFeeRate.GetFeePerK()),
- FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)),
- FormatMoney(minMempoolFeeRate.GetFeePerK())));
+ FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize))));
return Result::WALLET_ERROR;
}
@@ -208,6 +192,109 @@ Result CreateTransaction(const CWallet* wallet, const uint256& txid, const CCoin
}
}
+ return Result::OK;
+}
+
+
+Result CreateRateBumpTransaction(CWallet* wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<std::string>& errors,
+ CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
+{
+ // We are going to modify coin control later, copy to re-use
+ CCoinControl new_coin_control(coin_control);
+
+ auto locked_chain = wallet->chain().lock();
+ LOCK(wallet->cs_wallet);
+ errors.clear();
+ auto it = wallet->mapWallet.find(txid);
+ if (it == wallet->mapWallet.end()) {
+ errors.push_back("Invalid or non-wallet transaction id");
+ return Result::INVALID_ADDRESS_OR_KEY;
+ }
+ const CWalletTx& wtx = it->second;
+
+ Result result = PreconditionChecks(*locked_chain, wallet, wtx, errors);
+ if (result != Result::OK) {
+ return result;
+ }
+
+ // Fill in recipients(and preserve a single change key if there is one)
+ std::vector<CRecipient> recipients;
+ for (const auto& output : wtx.tx->vout) {
+ if (!wallet->IsChange(output)) {
+ CRecipient recipient = {output.scriptPubKey, output.nValue, false};
+ recipients.push_back(recipient);
+ } else {
+ CTxDestination change_dest;
+ ExtractDestination(output.scriptPubKey, change_dest);
+ new_coin_control.destChange = change_dest;
+ }
+ }
+
+ // Get the fee rate of the original transaction. This is calculated from
+ // the tx fee/vsize, so it may have been rounded down. Add 1 satoshi to the
+ // result.
+ old_fee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
+ int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
+ // Feerate of thing we are bumping
+ CFeeRate feerate(old_fee, txSize);
+ feerate += CFeeRate(1);
+
+ // The node has a configurable incremental relay fee. Increment the fee by
+ // the minimum of that and the wallet's conservative
+ // WALLET_INCREMENTAL_RELAY_FEE value to future proof against changes to
+ // network wide policy for incremental relay fee that our node may not be
+ // aware of. This ensures we're over the over the required relay fee rate
+ // (BIP 125 rule 4). The replacement tx will be at least as large as the
+ // original tx, so the total fee will be greater (BIP 125 rule 3)
+ CFeeRate node_incremental_relay_fee = wallet->chain().relayIncrementalFee();
+ CFeeRate wallet_incremental_relay_fee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
+ feerate += std::max(node_incremental_relay_fee, wallet_incremental_relay_fee);
+
+ // Fee rate must also be at least the wallet's GetMinimumFeeRate
+ CFeeRate min_feerate(GetMinimumFeeRate(*wallet, new_coin_control, /* feeCalc */ nullptr));
+
+ // Set the required fee rate for the replacement transaction in coin control.
+ new_coin_control.m_feerate = std::max(feerate, min_feerate);
+
+ // Fill in required inputs we are double-spending(all of them)
+ // N.B.: bip125 doesn't require all the inputs in the replaced transaction to be
+ // used in the replacement transaction, but it's very important for wallets to make
+ // sure that happens. If not, it would be possible to bump a transaction A twice to
+ // A2 and A3 where A2 and A3 don't conflict (or alternatively bump A to A2 and A2
+ // to A3 where A and A3 don't conflict). If both later get confirmed then the sender
+ // has accidentally double paid.
+ for (const auto& inputs : wtx.tx->vin) {
+ new_coin_control.Select(COutPoint(inputs.prevout));
+ }
+ new_coin_control.fAllowOtherInputs = true;
+
+ // We cannot source new unconfirmed inputs(bip125 rule 2)
+ new_coin_control.m_min_depth = 1;
+
+ CTransactionRef tx_new = MakeTransactionRef();
+ CReserveKey reservekey(wallet);
+ CAmount fee_ret;
+ int change_pos_in_out = -1; // No requested location for change
+ std::string fail_reason;
+ if (!wallet->CreateTransaction(*locked_chain, recipients, tx_new, reservekey, fee_ret, change_pos_in_out, fail_reason, new_coin_control, false)) {
+ errors.push_back("Unable to create transaction: " + fail_reason);
+ return Result::WALLET_ERROR;
+ }
+
+ // If change key hasn't been ReturnKey'ed by this point, we take it out of keypool
+ reservekey.KeepKey();
+
+ // Write back new fee if successful
+ new_fee = fee_ret;
+
+ // 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)) {
+ for (auto& input : mtx.vin) {
+ if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
+ }
+ }
return Result::OK;
}
diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h
index a1eb5d0e0d..0c4e1cb7dd 100644
--- a/src/wallet/feebumper.h
+++ b/src/wallet/feebumper.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.
@@ -28,8 +28,8 @@ enum class Result
//! Return whether transaction can be bumped.
bool TransactionCanBeBumped(const CWallet* wallet, const uint256& txid);
-//! Create bumpfee transaction.
-Result CreateTransaction(const CWallet* wallet,
+//! Create bumpfee transaction based on total amount.
+Result CreateTotalBumpTransaction(const CWallet* wallet,
const uint256& txid,
const CCoinControl& coin_control,
CAmount total_fee,
@@ -38,6 +38,15 @@ Result CreateTransaction(const CWallet* wallet,
CAmount& new_fee,
CMutableTransaction& mtx);
+//! Create bumpfee transaction based on feerate estimates.
+Result CreateRateBumpTransaction(CWallet* wallet,
+ const uint256& txid,
+ const CCoinControl& coin_control,
+ std::vector<std::string>& errors,
+ CAmount& old_fee,
+ CAmount& new_fee,
+ CMutableTransaction& mtx);
+
//! Sign the new transaction,
//! @return false if the tx couldn't be found or if it was
//! impossible to create the signature(s)
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 545adaebc1..2792058f2a 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -1,13 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <wallet/fees.h>
-#include <policy/policy.h>
#include <util/system.h>
-#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/wallet.h>
@@ -20,18 +18,12 @@ CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes)
CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc)
{
- CAmount fee_needed = GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
- // Always obey the maximum
- if (fee_needed > maxTxFee) {
- fee_needed = maxTxFee;
- if (feeCalc) feeCalc->reason = FeeReason::MAXTXFEE;
- }
- return fee_needed;
+ return GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
}
CFeeRate GetRequiredFeeRate(const CWallet& wallet)
{
- return std::max(wallet.m_min_fee, ::minRelayTxFee);
+ return std::max(wallet.m_min_fee, wallet.chain().relayMinFee());
}
CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, FeeCalculation* feeCalc)
@@ -96,6 +88,6 @@ CFeeRate GetDiscardRate(const CWallet& wallet)
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
// Discard rate must be at least dustRelayFee
- discard_rate = std::max(discard_rate, ::dustRelayFee);
+ discard_rate = std::max(discard_rate, wallet.chain().relayDustFee());
return discard_rate;
}
diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp
index 7ad343c15f..0265433863 100644
--- a/src/wallet/init.cpp
+++ b/src/wallet/init.cpp
@@ -1,19 +1,15 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <chainparams.h>
#include <init.h>
#include <interfaces/chain.h>
#include <net.h>
-#include <scheduler.h>
#include <outputtype.h>
#include <util/system.h>
#include <util/moneystr.h>
-#include <validation.h>
#include <walletinitinterface.h>
-#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>
@@ -38,7 +34,7 @@ const WalletInitInterface& g_wallet_init_interface = WalletInit();
void WalletInit::AddWalletOptions() const
{
gArgs.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", or \"bech32\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), false, OptionsCategory::WALLET);
- gArgs.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u)", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of selecting on a per-output basis. Privacy is improved as an address is only used once (unless someone sends to it after spending from it), but may result in slightly higher fees as suboptimal coin selection may result due to the added limitation (default: %u (always enabled for wallets with \"avoid_reuse\" enabled))", DEFAULT_AVOIDPARTIALSPENDS), false, OptionsCategory::WALLET);
gArgs.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", or \"bech32\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", false, OptionsCategory::WALLET);
gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", false, OptionsCategory::WALLET);
gArgs.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
@@ -47,6 +43,8 @@ void WalletInit::AddWalletOptions() const
gArgs.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), false, OptionsCategory::WALLET);
gArgs.AddArg("-keypool=<n>", strprintf("Set key pool size to <n> (default: %u)", DEFAULT_KEYPOOL_SIZE), false, OptionsCategory::WALLET);
+ gArgs.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",
+ CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), false, OptionsCategory::DEBUG_TEST);
gArgs.AddArg("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)), false, OptionsCategory::WALLET);
gArgs.AddArg("-paytxfee=<amt>", strprintf("Fee (in %s/kB) to add to transactions you send (default: %s)",
@@ -123,62 +121,6 @@ bool WalletInit::ParameterInteraction() const
if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false))
return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
- if (::minRelayTxFee.GetFeePerK() > HIGH_TX_FEE_PER_KB)
- InitWarning(AmountHighWarn("-minrelaytxfee") + " " +
- _("The wallet will avoid paying less than the minimum relay fee."));
-
- return true;
-}
-
-bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
-{
- if (gArgs.IsArgSet("-walletdir")) {
- fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
- boost::system::error_code error;
- // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
- fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
- if (error || !fs::exists(wallet_dir)) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
- return false;
- } else if (!fs::is_directory(wallet_dir)) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
- return false;
- // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
- } else if (!wallet_dir.is_absolute()) {
- chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
- return false;
- }
- gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
- }
-
- LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
-
- uiInterface.InitMessage(_("Verifying wallet(s)..."));
-
- // Parameter interaction code should have thrown an error if -salvagewallet
- // was enabled with more than wallet file, so the wallet_files size check
- // here should have no effect.
- bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;
-
- // Keep track of each wallet absolute path to detect duplicates.
- std::set<fs::path> wallet_paths;
-
- for (const auto& wallet_file : wallet_files) {
- WalletLocation location(wallet_file);
-
- if (!wallet_paths.insert(location.GetPath()).second) {
- chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
- return false;
- }
-
- std::string error_string;
- std::string warning_string;
- bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warning_string);
- if (!error_string.empty()) chain.initError(error_string);
- if (!warning_string.empty()) chain.initWarning(warning_string);
- if (!verify_success) return false;
- }
-
return true;
}
@@ -191,51 +133,3 @@ void WalletInit::Construct(InitInterfaces& interfaces) const
gArgs.SoftSetArg("-wallet", "");
interfaces.chain_clients.emplace_back(interfaces::MakeWalletClient(*interfaces.chain, gArgs.GetArgs("-wallet")));
}
-
-bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
-{
- for (const std::string& walletFile : wallet_files) {
- std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile));
- if (!pwallet) {
- return false;
- }
- AddWallet(pwallet);
- }
-
- return true;
-}
-
-void StartWallets(CScheduler& scheduler)
-{
- for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
- pwallet->postInitProcess();
- }
-
- // Run a thread to flush wallet periodically
- scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
-}
-
-void FlushWallets()
-{
- for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
- pwallet->Flush(false);
- }
-}
-
-void StopWallets()
-{
- for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
- pwallet->Flush(true);
- }
-}
-
-void UnloadWallets()
-{
- auto wallets = GetWallets();
- while (!wallets.empty()) {
- auto wallet = wallets.back();
- wallets.pop_back();
- RemoveWallet(wallet);
- UnloadWallet(std::move(wallet));
- }
-}
diff --git a/src/script/ismine.cpp b/src/wallet/ismine.cpp
index 51bd2d6e9f..6138d4ae44 100644
--- a/src/script/ismine.cpp
+++ b/src/wallet/ismine.cpp
@@ -3,13 +3,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <script/ismine.h>
+#include <wallet/ismine.h>
#include <key.h>
-#include <keystore.h>
#include <script/script.h>
#include <script/sign.h>
-
+#include <wallet/wallet.h>
typedef std::vector<unsigned char> valtype;
@@ -46,7 +45,7 @@ bool PermitsUncompressed(IsMineSigVersion sigversion)
return sigversion == IsMineSigVersion::TOP || sigversion == IsMineSigVersion::P2SH;
}
-bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
+bool HaveKeys(const std::vector<valtype>& pubkeys, const CWallet& keystore)
{
for (const valtype& pubkey : pubkeys) {
CKeyID keyID = CPubKey(pubkey).GetID();
@@ -55,7 +54,7 @@ bool HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore)
return true;
}
-IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
+IsMineResult IsMineInner(const CWallet& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion)
{
IsMineResult ret = IsMineResult::NO;
@@ -90,7 +89,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
// This also applies to the P2WSH case.
break;
}
- ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
+ ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
break;
}
case TX_PUBKEYHASH:
@@ -172,7 +171,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
} // namespace
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
+isminetype IsMine(const CWallet& keystore, const CScript& scriptPubKey)
{
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) {
case IsMineResult::INVALID:
@@ -186,7 +185,7 @@ isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey)
assert(false);
}
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest)
+isminetype IsMine(const CWallet& keystore, const CTxDestination& dest)
{
CScript script = GetScriptForDestination(dest);
return IsMine(keystore, script);
diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h
new file mode 100644
index 0000000000..41555fcb93
--- /dev/null
+++ b/src/wallet/ismine.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 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_WALLET_ISMINE_H
+#define BITCOIN_WALLET_ISMINE_H
+
+#include <script/standard.h>
+
+#include <stdint.h>
+#include <bitset>
+
+class CWallet;
+class CScript;
+
+/** IsMine() return codes */
+enum isminetype : unsigned int
+{
+ ISMINE_NO = 0,
+ ISMINE_WATCH_ONLY = 1 << 0,
+ ISMINE_SPENDABLE = 1 << 1,
+ ISMINE_USED = 1 << 2,
+ ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE,
+ ISMINE_ALL_USED = ISMINE_ALL | ISMINE_USED,
+ ISMINE_ENUM_ELEMENTS,
+};
+/** used for bitflags of isminetype */
+typedef uint8_t isminefilter;
+
+isminetype IsMine(const CWallet& wallet, const CScript& scriptPubKey);
+isminetype IsMine(const CWallet& wallet, const CTxDestination& dest);
+
+/**
+ * Cachable amount subdivided into watchonly and spendable parts.
+ */
+struct CachableAmount
+{
+ // NO and ALL are never (supposed to be) cached
+ std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
+ CAmount m_value[ISMINE_ENUM_ELEMENTS];
+ inline void Reset()
+ {
+ m_cached.reset();
+ }
+ void Set(isminefilter filter, CAmount value)
+ {
+ m_cached.set(filter);
+ m_value[filter] = value;
+ }
+};
+
+#endif // BITCOIN_WALLET_ISMINE_H
diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp
new file mode 100644
index 0000000000..54aa12dba8
--- /dev/null
+++ b/src/wallet/load.cpp
@@ -0,0 +1,112 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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 <wallet/load.h>
+
+#include <interfaces/chain.h>
+#include <scheduler.h>
+#include <util/system.h>
+#include <wallet/wallet.h>
+
+bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
+{
+ if (gArgs.IsArgSet("-walletdir")) {
+ fs::path wallet_dir = gArgs.GetArg("-walletdir", "");
+ boost::system::error_code error;
+ // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
+ fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
+ if (error || !fs::exists(wallet_dir)) {
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), wallet_dir.string()));
+ return false;
+ } else if (!fs::is_directory(wallet_dir)) {
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), wallet_dir.string()));
+ return false;
+ // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
+ } else if (!wallet_dir.is_absolute()) {
+ chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), wallet_dir.string()));
+ return false;
+ }
+ gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string());
+ }
+
+ LogPrintf("Using wallet directory %s\n", GetWalletDir().string());
+
+ chain.initMessage(_("Verifying wallet(s)..."));
+
+ // Parameter interaction code should have thrown an error if -salvagewallet
+ // was enabled with more than wallet file, so the wallet_files size check
+ // here should have no effect.
+ bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1;
+
+ // Keep track of each wallet absolute path to detect duplicates.
+ std::set<fs::path> wallet_paths;
+
+ for (const auto& wallet_file : wallet_files) {
+ WalletLocation location(wallet_file);
+
+ if (!wallet_paths.insert(location.GetPath()).second) {
+ chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file));
+ return false;
+ }
+
+ std::string error_string;
+ std::string warning_string;
+ bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warning_string);
+ if (!error_string.empty()) chain.initError(error_string);
+ if (!warning_string.empty()) chain.initWarning(warning_string);
+ if (!verify_success) return false;
+ }
+
+ return true;
+}
+
+bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files)
+{
+ for (const std::string& walletFile : wallet_files) {
+ std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile));
+ if (!pwallet) {
+ return false;
+ }
+ AddWallet(pwallet);
+ }
+
+ return true;
+}
+
+void StartWallets(CScheduler& scheduler)
+{
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
+ pwallet->postInitProcess();
+ }
+
+ // Schedule periodic wallet flushes and tx rebroadcasts
+ scheduler.scheduleEvery(MaybeCompactWalletDB, 500);
+ scheduler.scheduleEvery(MaybeResendWalletTxs, 1000);
+}
+
+void FlushWallets()
+{
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
+ pwallet->Flush(false);
+ }
+}
+
+void StopWallets()
+{
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
+ pwallet->Flush(true);
+ }
+}
+
+void UnloadWallets()
+{
+ auto wallets = GetWallets();
+ while (!wallets.empty()) {
+ auto wallet = wallets.back();
+ wallets.pop_back();
+ RemoveWallet(wallet);
+ UnloadWallet(std::move(wallet));
+ }
+}
diff --git a/src/wallet/load.h b/src/wallet/load.h
new file mode 100644
index 0000000000..81f078fd10
--- /dev/null
+++ b/src/wallet/load.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-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_WALLET_LOAD_H
+#define BITCOIN_WALLET_LOAD_H
+
+#include <string>
+#include <vector>
+
+class CScheduler;
+
+namespace interfaces {
+class Chain;
+} // namespace interfaces
+
+//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
+//! This function will perform salvage on the wallet if requested, as long as only one wallet is
+//! being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
+bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
+
+//! Load wallet databases.
+bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
+
+//! Complete startup of wallets.
+void StartWallets(CScheduler& scheduler);
+
+//! Flush all wallets in preparation for shutdown.
+void FlushWallets();
+
+//! Stop all wallets. Wallets will be flushed first.
+void StopWallets();
+
+//! Close all wallets.
+void UnloadWallets();
+
+#endif // BITCOIN_WALLET_LOAD_H
diff --git a/src/wallet/psbtwallet.cpp b/src/wallet/psbtwallet.cpp
index 1b17b09763..ce4788dee1 100644
--- a/src/wallet/psbtwallet.cpp
+++ b/src/wallet/psbtwallet.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 684d900478..3112dca9f5 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -16,12 +16,12 @@
#include <util/bip32.h>
#include <util/system.h>
#include <util/time.h>
-#include <validation.h>
#include <wallet/wallet.h>
#include <wallet/rpcwallet.h>
#include <stdint.h>
+#include <tuple>
#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
@@ -115,7 +115,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
"\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
"Hint: use importmulti to import more than one private key.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n",
+ "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
{"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"},
@@ -157,8 +158,11 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (!request.params[2].isNull())
fRescan = request.params[2].get_bool();
- if (fRescan && pwallet->chain().getPruneMode()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
+ if (fRescan && pwallet->chain().havePruned()) {
+ // Exit early and print an error.
+ // If a block is pruned after this check, we will import the key(s),
+ // but fail the rescan with a generic error.
+ throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
}
if (fRescan && !reserver.reserve()) {
@@ -216,7 +220,8 @@ UniValue abortrescan(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"abortrescan",
- "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n",
+ "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{},
RPCResults{},
RPCExamples{
@@ -252,7 +257,7 @@ static void ImportScript(CWallet* const pwallet, const CScript& script, const st
if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
}
- ImportAddress(pwallet, id, strLabel);
+ ImportAddress(pwallet, ScriptHash(id), strLabel);
} else {
CTxDestination destination;
if (ExtractDestination(script, destination)) {
@@ -285,8 +290,10 @@ UniValue importaddress(const JSONRPCRequest& request)
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
"If you have the full public key, you should call importpubkey instead of this.\n"
+ "Hint: use importmulti to import more than one address.\n"
"\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
- "as change, and not show up in many RPCs.\n",
+ "as change, and not show up in many RPCs.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
{"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
@@ -314,8 +321,11 @@ UniValue importaddress(const JSONRPCRequest& request)
if (!request.params[2].isNull())
fRescan = request.params[2].get_bool();
- if (fRescan && pwallet->chain().getPruneMode()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
+ if (fRescan && pwallet->chain().havePruned()) {
+ // Exit early and print an error.
+ // If a block is pruned after this check, we will import the key(s),
+ // but fail the rescan with a generic error.
+ throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
}
WalletRescanReserver reserver(pwallet);
@@ -348,7 +358,11 @@ UniValue importaddress(const JSONRPCRequest& request)
if (fRescan)
{
RescanWallet(*pwallet, reserver);
- pwallet->ReacceptWalletTransactions();
+ {
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
+ pwallet->ReacceptWalletTransactions(*locked_chain);
+ }
}
return NullUniValue;
@@ -475,8 +489,10 @@ UniValue importpubkey(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"importpubkey",
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
+ "Hint: use importmulti to import more than one public key.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n",
+ "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
{"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
@@ -503,8 +519,11 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (!request.params[2].isNull())
fRescan = request.params[2].get_bool();
- if (fRescan && pwallet->chain().getPruneMode()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
+ if (fRescan && pwallet->chain().havePruned()) {
+ // Exit early and print an error.
+ // If a block is pruned after this check, we will import the key(s),
+ // but fail the rescan with a generic error.
+ throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
}
WalletRescanReserver reserver(pwallet);
@@ -532,7 +551,11 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (fRescan)
{
RescanWallet(*pwallet, reserver);
- pwallet->ReacceptWalletTransactions();
+ {
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
+ pwallet->ReacceptWalletTransactions(*locked_chain);
+ }
}
return NullUniValue;
@@ -550,7 +573,8 @@ UniValue importwallet(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"importwallet",
- "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n",
+ "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"},
},
@@ -565,8 +589,11 @@ UniValue importwallet(const JSONRPCRequest& request)
},
}.ToString());
- if (pwallet->chain().getPruneMode()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
+ if (pwallet->chain().havePruned()) {
+ // Exit early and print an error.
+ // If a block is pruned after this check, we will import the key(s),
+ // but fail the rescan with a generic error.
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned");
}
WalletRescanReserver reserver(pwallet);
@@ -595,11 +622,11 @@ UniValue importwallet(const JSONRPCRequest& request)
// Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
// we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
- uiInterface.ShowProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
+ pwallet->chain().showProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
std::vector<std::pair<CScript, int64_t>> scripts;
while (file.good()) {
- uiInterface.ShowProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
+ pwallet->chain().showProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
std::string line;
std::getline(file, line);
if (line.empty() || line[0] == '#')
@@ -637,13 +664,13 @@ UniValue importwallet(const JSONRPCRequest& request)
file.close();
// We now know whether we are importing private keys, so we can error if private keys are disabled
if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
}
double total = (double)(keys.size() + scripts.size());
double progress = 0;
for (const auto& key_tuple : keys) {
- uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
+ pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
const CKey& key = std::get<0>(key_tuple);
int64_t time = std::get<1>(key_tuple);
bool has_label = std::get<2>(key_tuple);
@@ -653,22 +680,22 @@ UniValue importwallet(const JSONRPCRequest& request)
assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
- pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
+ pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(PKHash(keyid)));
continue;
}
- pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(keyid));
+ pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid)));
if (!pwallet->AddKeyPubKey(key, pubkey)) {
fGood = false;
continue;
}
pwallet->mapKeyMetadata[keyid].nCreateTime = time;
if (has_label)
- pwallet->SetAddressBook(keyid, label, "receive");
+ pwallet->SetAddressBook(PKHash(keyid), label, "receive");
nTimeBegin = std::min(nTimeBegin, time);
progress++;
}
for (const auto& script_pair : scripts) {
- uiInterface.ShowProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
+ pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
const CScript& script = script_pair.first;
int64_t time = script_pair.second;
CScriptID id(script);
@@ -687,10 +714,10 @@ UniValue importwallet(const JSONRPCRequest& request)
}
progress++;
}
- uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
pwallet->UpdateTimeFirstKey(nTimeBegin);
}
- uiInterface.ShowProgress("", 100, false); // hide progress dialog in GUI
+ pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
pwallet->MarkDirty();
@@ -799,19 +826,16 @@ UniValue dumpwallet(const JSONRPCRequest& request)
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
- std::map<CTxDestination, int64_t> mapKeyBirth;
+ std::map<CKeyID, int64_t> mapKeyBirth;
const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys();
pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth);
std::set<CScriptID> scripts = pwallet->GetCScripts();
- // TODO: include scripts in GetKeyBirthTimes() output instead of separate
// sort time/key pairs
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
for (const auto& entry : mapKeyBirth) {
- if (const CKeyID* keyID = boost::get<CKeyID>(&entry.first)) { // set and test
- vKeyBirth.push_back(std::make_pair(entry.second, *keyID));
- }
+ vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
}
mapKeyBirth.clear();
std::sort(vKeyBirth.begin(), vKeyBirth.end());
@@ -862,7 +886,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
for (const CScriptID &scriptid : scripts) {
CScript script;
std::string create_time = "0";
- std::string address = EncodeDestination(scriptid);
+ std::string address = EncodeDestination(ScriptHash(scriptid));
// get birth times for scripts with metadata
auto it = pwallet->m_script_metadata.find(scriptid);
if (it != pwallet->m_script_metadata.end()) {
@@ -892,7 +916,7 @@ struct ImportData
// Output data
std::set<CScript> import_scripts;
std::map<CKeyID, bool> used_keys; //!< Import these private keys if available (the value indicates whether if the key is required for solvability)
- std::map<CKeyID, KeyOriginInfo> key_origins;
+ std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
};
enum class ScriptContext
@@ -1136,18 +1160,12 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
if (!data.exists("range")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
}
- auto range = ParseRange(data["range"]);
- range_start = range.first;
- range_end = range.second;
- if (range_start < 0 || (range_end >> 31) != 0 || range_end - range_start >= 1000000) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid descriptor range specified");
- }
+ std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
}
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
- // Expand all descriptors to get public keys and scripts.
- // TODO: get private keys from descriptors too
+ // Expand all descriptors to get public keys and scripts, and private keys if available.
for (int i = range_start; i <= range_end; ++i) {
FlatSigningProvider out_keys;
std::vector<CScript> scripts_temp;
@@ -1161,7 +1179,10 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
import_data.import_scripts.emplace(x.second);
}
+ parsed_desc->ExpandPrivate(i, keys, out_keys);
+
std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
+ std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
}
@@ -1189,6 +1210,9 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
[&](const std::pair<CKeyID, CPubKey>& used_key) {
return privkey_map.count(used_key.first) > 0;
+ }) && std::all_of(import_data.key_origins.begin(), import_data.key_origins.end(),
+ [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
+ return privkey_map.count(entry.first) > 0;
});
if (!watch_only && !spendable) {
warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
@@ -1250,56 +1274,17 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
// All good, time to import
pwallet->MarkDirty();
- for (const auto& entry : import_data.import_scripts) {
- if (!pwallet->HaveCScript(CScriptID(entry)) && !pwallet->AddCScript(entry)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
- }
- }
- for (const auto& entry : privkey_map) {
- const CKey& key = entry.second;
- CPubKey pubkey = key.GetPubKey();
- const CKeyID& id = entry.first;
- assert(key.VerifyPubKey(pubkey));
- pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
- // If the private key is not present in the wallet, insert it.
- if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKey(key, pubkey)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
- }
- pwallet->UpdateTimeFirstKey(timestamp);
- }
- for (const CKeyID& id : ordered_pubkeys) {
- auto entry = pubkey_map.find(id);
- if (entry == pubkey_map.end()) {
- continue;
- }
- const CPubKey& pubkey = entry->second;
- CPubKey temp;
- if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
- }
- const auto& key_orig_it = import_data.key_origins.find(id);
- if (key_orig_it != import_data.key_origins.end()) {
- pwallet->AddKeyOrigin(pubkey, key_orig_it->second);
- }
- pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
-
- // Add to keypool only works with pubkeys
- if (add_keypool) {
- pwallet->AddKeypoolPubkey(pubkey, internal);
- }
+ if (!pwallet->ImportScripts(import_data.import_scripts)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
}
-
- for (const CScript& script : script_pub_keys) {
- if (!have_solving_data || !::IsMine(*pwallet, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
- if (!pwallet->AddWatchOnly(script, timestamp)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
- }
- }
- CTxDestination dest;
- ExtractDestination(script, dest);
- if (!internal && IsValidDestination(dest)) {
- pwallet->SetAddressBook(dest, label, "receive");
- }
+ if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
+ }
+ if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ }
+ if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, internal, timestamp)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
result.pushKV("success", UniValue(true));
@@ -1344,7 +1329,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
"If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
"Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
- "may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n",
+ "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
{
@@ -1468,7 +1454,11 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
if (fRescan && fRunScan && requests.size()) {
int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
- pwallet->ReacceptWalletTransactions();
+ {
+ auto locked_chain = pwallet->chain().lock();
+ LOCK(pwallet->cs_wallet);
+ pwallet->ReacceptWalletTransactions(*locked_chain);
+ }
if (pwallet->IsAbortingRescan()) {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 31a3209a49..eae5f876ea 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1,34 +1,30 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <amount.h>
-#include <chain.h>
#include <consensus/validation.h>
#include <core_io.h>
-#include <httpserver.h>
#include <init.h>
#include <interfaces/chain.h>
-#include <validation.h>
#include <key_io.h>
-#include <net.h>
#include <node/transaction.h>
#include <outputtype.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
#include <policy/rbf.h>
-#include <rpc/rawtransaction.h>
+#include <rpc/rawtransaction_util.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <script/descriptor.h>
#include <script/sign.h>
-#include <shutdown.h>
-#include <timedata.h>
#include <util/bip32.h>
-#include <util/system.h>
+#include <util/fees.h>
#include <util/moneystr.h>
+#include <util/system.h>
+#include <util/url.h>
+#include <util/validation.h>
#include <wallet/coincontrol.h>
#include <wallet/feebumper.h>
#include <wallet/psbtwallet.h>
@@ -45,6 +41,17 @@
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
+static inline bool GetAvoidReuseFlag(CWallet * const pwallet, const UniValue& param) {
+ bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
+ bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
+
+ if (avoid_reuse && !can_avoid_reuse) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
+ }
+
+ return avoid_reuse;
+}
+
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
{
if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
@@ -68,14 +75,14 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
return wallets.size() == 1 || (request.fHelp && wallets.size() > 0) ? wallets[0] : nullptr;
}
-std::string HelpRequiringPassphrase(CWallet * const pwallet)
+std::string HelpRequiringPassphrase(const CWallet* pwallet)
{
return pwallet && pwallet->IsCrypted()
? "\nRequires wallet passphrase to be set with walletpassphrase call."
: "";
}
-bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
+bool EnsureWalletIsAvailable(const CWallet* pwallet, bool avoidException)
{
if (pwallet) return true;
if (avoidException) return false;
@@ -87,7 +94,7 @@ bool EnsureWalletIsAvailable(CWallet * const pwallet, bool avoidException)
"Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
}
-void EnsureWalletIsUnlocked(CWallet * const pwallet)
+void EnsureWalletIsUnlocked(const CWallet* pwallet)
{
if (pwallet->IsLocked()) {
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
@@ -308,7 +315,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
{
- CAmount curBalance = pwallet->GetBalance();
+ CAmount curBalance = pwallet->GetBalance(0, coin_control.m_avoid_address_reuse).m_mine_trusted;
// Check amount
if (nValue <= 0)
@@ -355,7 +362,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 9)
throw std::runtime_error(
RPCHelpMan{"sendtoaddress",
"\nSend an amount to a given address." +
@@ -376,6 +383,8 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
" \"UNSET\"\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\""},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
+ " dirty if they have previously been used in a transaction."},
},
RPCResult{
"\"txid\" (string) The transaction id.\n"
@@ -432,6 +441,9 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
}
}
+ coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[8]);
+ // We also enable partial spend avoidance if reuse avoidance is set.
+ coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
EnsureWalletIsUnlocked(pwallet);
@@ -548,13 +560,14 @@ static UniValue signmessage(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
}
- const CKeyID *keyID = boost::get<CKeyID>(&dest);
- if (!keyID) {
+ const PKHash *pkhash = boost::get<PKHash>(&dest);
+ if (!pkhash) {
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
}
CKey key;
- if (!pwallet->GetKey(*keyID, key)) {
+ CKeyID keyID(*pkhash);
+ if (!pwallet->GetKey(keyID, key)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available");
}
@@ -720,7 +733,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || (request.params.size() > 3 ))
+ if (request.fHelp || request.params.size() > 4)
throw std::runtime_error(
RPCHelpMan{"getbalance",
"\nReturns the total available balance.\n"
@@ -730,6 +743,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
{"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
{"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
},
RPCResult{
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n"
@@ -761,12 +775,16 @@ static UniValue getbalance(const JSONRPCRequest& request)
min_depth = request.params[1].get_int();
}
- isminefilter filter = ISMINE_SPENDABLE;
+ bool include_watchonly = false;
if (!request.params[2].isNull() && request.params[2].get_bool()) {
- filter = filter | ISMINE_WATCH_ONLY;
+ include_watchonly = true;
}
- return ValueFromAmount(pwallet->GetBalance(filter, min_depth));
+ bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
+
+ const auto bal = pwallet->GetBalance(min_depth, avoid_reuse);
+
+ return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
}
static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
@@ -781,7 +799,7 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"getunconfirmedbalance",
- "Returns the server's total unconfirmed balance\n",
+ "DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
{},
RPCResults{},
RPCExamples{""},
@@ -794,7 +812,7 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request)
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
- return ValueFromAmount(pwallet->GetUnconfirmedBalance());
+ return ValueFromAmount(pwallet->GetBalance().m_mine_untrusted_pending);
}
@@ -807,9 +825,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
- throw std::runtime_error(
- RPCHelpMan{"sendmany",
+ const RPCHelpMan help{"sendmany",
"\nSend multiple times. Amounts are double-precision floating point numbers." +
HelpRequiringPassphrase(pwallet) + "\n",
{
@@ -819,7 +835,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
{"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
},
},
- {"minconf", RPCArg::Type::NUM, /* default */ "1", "Only use the balance confirmed at least this many times."},
+ {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
{"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
{"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array with addresses.\n"
" The fee will be equally deducted from the amount of each selected address.\n"
@@ -850,7 +866,11 @@ static UniValue sendmany(const JSONRPCRequest& request)
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("sendmany", "\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\":0.01,\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 6, \"testing\"")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -867,9 +887,6 @@ static UniValue sendmany(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
}
UniValue sendTo = request.params[1].get_obj();
- int nMinDepth = 1;
- if (!request.params[2].isNull())
- nMinDepth = request.params[2].get_int();
mapValue_t mapValue;
if (!request.params[3].isNull() && !request.params[3].get_str().empty())
@@ -897,7 +914,6 @@ static UniValue sendmany(const JSONRPCRequest& request)
std::set<CTxDestination> destinations;
std::vector<CRecipient> vecSend;
- CAmount totalAmount = 0;
std::vector<std::string> keys = sendTo.getKeys();
for (const std::string& name_ : keys) {
CTxDestination dest = DecodeDestination(name_);
@@ -914,7 +930,6 @@ static UniValue sendmany(const JSONRPCRequest& request)
CAmount nAmount = AmountFromValue(sendTo[name_]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- totalAmount += nAmount;
bool fSubtractFeeFromAmount = false;
for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
@@ -929,11 +944,6 @@ static UniValue sendmany(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- // Check funds
- if (totalAmount > pwallet->GetLegacyBalance(ISMINE_SPENDABLE, nMinDepth)) {
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Wallet has insufficient funds");
- }
-
// Shuffle recipient list
std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
@@ -1026,8 +1036,8 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
}
// Construct using pay-to-script-hash:
- CScript inner = CreateMultisigRedeemscript(required, pubkeys);
- CTxDestination dest = AddAndGetDestinationForScript(*pwallet, inner, output_type);
+ CScript inner;
+ CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, *pwallet, inner);
pwallet->SetAddressBook(dest, label, "send");
UniValue result(UniValue::VOBJ);
@@ -1760,7 +1770,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
entry.pushKV("details", details);
- std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
+ std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
entry.pushKV("hex", strHex);
return entry;
@@ -1978,7 +1988,7 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
// wallet before the following callback is called. If a valid shared pointer
// is acquired in the callback then the wallet is still loaded.
std::weak_ptr<CWallet> weak_wallet = wallet;
- RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet] {
+ pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet] {
if (auto shared_wallet = weak_wallet.lock()) {
LOCK(shared_wallet->cs_wallet);
shared_wallet->Lock();
@@ -2127,6 +2137,10 @@ static UniValue encryptwallet(const JSONRPCRequest& request)
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
+ if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
+ }
+
if (pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
}
@@ -2367,8 +2381,8 @@ static UniValue settxfee(const JSONRPCRequest& request)
CFeeRate tx_fee_rate(nAmount, 1000);
if (tx_fee_rate == 0) {
// automatic selection
- } else if (tx_fee_rate < ::minRelayTxFee) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", ::minRelayTxFee.ToString()));
+ } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
} else if (tx_fee_rate < pwallet->m_min_fee) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
}
@@ -2377,6 +2391,75 @@ static UniValue settxfee(const JSONRPCRequest& request)
return true;
}
+static UniValue getbalances(const JSONRPCRequest& request)
+{
+ std::shared_ptr<CWallet> const rpc_wallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(rpc_wallet.get(), request.fHelp)) {
+ return NullUniValue;
+ }
+ CWallet& wallet = *rpc_wallet;
+
+ const RPCHelpMan help{
+ "getbalances",
+ "Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
+ {},
+ RPCResult{
+ "{\n"
+ " \"mine\": { (object) balances from outputs that the wallet can sign\n"
+ " \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
+ " \"untrusted_pending\": xxx (numeric) untrusted pending balance (outputs created by others that are in the mempool)\n"
+ " \"immature\": xxx (numeric) balance from immature coinbase outputs\n"
+ " \"used\": xxx (numeric) (only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)\n"
+ " },\n"
+ " \"watchonly\": { (object) watchonly balances (not present if wallet does not watch anything)\n"
+ " \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
+ " \"untrusted_pending\": xxx (numeric) untrusted pending balance (outputs created by others that are in the mempool)\n"
+ " \"immature\": xxx (numeric) balance from immature coinbase outputs\n"
+ " },\n"
+ "}\n"},
+ RPCExamples{
+ HelpExampleCli("getbalances", "") +
+ HelpExampleRpc("getbalances", "")},
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
+
+ // Make sure the results are valid at least up to the most recent block
+ // the user could have gotten from another RPC command prior to now
+ wallet.BlockUntilSyncedToCurrentChain();
+
+ auto locked_chain = wallet.chain().lock();
+ LOCK(wallet.cs_wallet);
+
+ UniValue obj(UniValue::VOBJ);
+
+ const auto bal = wallet.GetBalance();
+ UniValue balances{UniValue::VOBJ};
+ {
+ UniValue balances_mine{UniValue::VOBJ};
+ balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
+ balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
+ balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
+ if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
+ // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
+ // the total balance, and then subtract bal to get the reused address balance.
+ const auto full_bal = wallet.GetBalance(0, false);
+ balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
+ }
+ balances.pushKV("mine", balances_mine);
+ }
+ if (wallet.HaveWatchOnly()) {
+ UniValue balances_watchonly{UniValue::VOBJ};
+ balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
+ balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
+ balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
+ balances.pushKV("watchonly", balances_watchonly);
+ }
+ return balances;
+}
+
static UniValue getwalletinfo(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -2386,18 +2469,16 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
- RPCHelpMan{"getwalletinfo",
+ const RPCHelpMan help{"getwalletinfo",
"Returns an object containing various wallet state info.\n",
{},
RPCResult{
"{\n"
" \"walletname\": xxxxx, (string) the wallet name\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
- " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
- " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
+ " \"balance\": xxxxxxx, (numeric) DEPRECATED. Identical to getbalances().mine.trusted\n"
+ " \"unconfirmed_balance\": xxx, (numeric) DEPRECATED. Identical to getbalances().mine.untrusted_pending\n"
+ " \"immature_balance\": xxxxxx, (numeric) DEPRECATED. Identical to getbalances().mine.immature\n"
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since Unix epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated (only counts external keys)\n"
@@ -2406,13 +2487,23 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
" \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
" \"hdseedid\": \"<hash160>\" (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n"
" \"private_keys_enabled\": true|false (boolean) false if privatekeys are disabled for this wallet (enforced watch-only wallet)\n"
+ " \"avoid_reuse\": true|false (boolean) whether this wallet tracks clean/dirty coins in terms of reuse\n"
+ " \"scanning\": (json object) current scanning details, or false if no scan is in progress\n"
+ " {\n"
+ " \"duration\" : xxxx (numeric) elapsed seconds since scan start\n"
+ " \"progress\" : x.xxxx, (numeric) scanning progress percentage [0.0, 1.0]\n"
+ " }\n"
"}\n"
},
RPCExamples{
HelpExampleCli("getwalletinfo", "")
+ HelpExampleRpc("getwalletinfo", "")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -2424,11 +2515,12 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
+ const auto bal = pwallet->GetBalance();
obj.pushKV("walletname", pwallet->GetName());
obj.pushKV("walletversion", pwallet->GetVersion());
- obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance()));
- obj.pushKV("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance()));
- obj.pushKV("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance()));
+ obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
+ obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
+ obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
obj.pushKV("txcount", (int)pwallet->mapWallet.size());
obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
@@ -2444,6 +2536,15 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
obj.pushKV("hdseedid", seed_id.GetHex());
}
obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
+ if (pwallet->IsScanning()) {
+ UniValue scanning(UniValue::VOBJ);
+ scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
+ scanning.pushKV("progress", pwallet->ScanningProgress());
+ obj.pushKV("scanning", scanning);
+ } else {
+ obj.pushKV("scanning", false);
+ }
return obj;
}
@@ -2564,29 +2665,103 @@ static UniValue loadwallet(const JSONRPCRequest& request)
return obj;
}
-static UniValue createwallet(const JSONRPCRequest& request)
+static UniValue setwalletflag(const JSONRPCRequest& request)
{
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) {
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
+ CWallet* const pwallet = wallet.get();
+
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ std::string flags = "";
+ for (auto& it : WALLET_FLAG_MAP)
+ if (it.second & MUTABLE_WALLET_FLAGS)
+ flags += (flags == "" ? "" : ", ") + it.first;
throw std::runtime_error(
- RPCHelpMan{"createwallet",
- "\nCreates and loads a new wallet.\n",
+ RPCHelpMan{"setwalletflag",
+ "\nChange the state of the given wallet flag for a wallet.\n",
{
- {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
- {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
- {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
+ {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
+ {"value", RPCArg::Type::BOOL, /* default */ "true", "The new state."},
},
RPCResult{
"{\n"
- " \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n"
- " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n"
+ " \"flag_name\": string (string) The name of the flag that was modified\n"
+ " \"flag_state\": bool (bool) The new state of the flag\n"
+ " \"warnings\": string (string) Any warnings associated with the change\n"
"}\n"
},
RPCExamples{
- HelpExampleCli("createwallet", "\"testwallet\"")
- + HelpExampleRpc("createwallet", "\"testwallet\"")
+ HelpExampleCli("setwalletflag", "avoid_reuse")
+ + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
},
}.ToString());
}
+
+ std::string flag_str = request.params[0].get_str();
+ bool value = request.params[1].isNull() || request.params[1].get_bool();
+
+ if (!WALLET_FLAG_MAP.count(flag_str)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
+ }
+
+ auto flag = WALLET_FLAG_MAP.at(flag_str);
+
+ if (!(flag & MUTABLE_WALLET_FLAGS)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
+ }
+
+ UniValue res(UniValue::VOBJ);
+
+ if (pwallet->IsWalletFlagSet(flag) == value) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
+ }
+
+ res.pushKV("flag_name", flag_str);
+ res.pushKV("flag_state", value);
+
+ if (value) {
+ pwallet->SetWalletFlag(flag);
+ } else {
+ pwallet->UnsetWalletFlag(flag);
+ }
+
+ if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
+ res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
+ }
+
+ return res;
+}
+
+static UniValue createwallet(const JSONRPCRequest& request)
+{
+ const RPCHelpMan help{
+ "createwallet",
+ "\nCreates and loads a new wallet.\n",
+ {
+ {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
+ {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
+ {"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
+ {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
+ {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
+ },
+ RPCResult{
+ "{\n"
+ " \"name\" : <wallet_name>, (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.\n"
+ " \"warning\" : <warning>, (string) Warning message if wallet was not loaded cleanly.\n"
+ "}\n"
+ },
+ RPCExamples{
+ HelpExampleCli("createwallet", "\"testwallet\"")
+ + HelpExampleRpc("createwallet", "\"testwallet\"")
+ },
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
std::string error;
std::string warning;
@@ -2595,10 +2770,27 @@ static UniValue createwallet(const JSONRPCRequest& request)
flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS;
}
+ bool create_blank = false; // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
if (!request.params[2].isNull() && request.params[2].get_bool()) {
+ create_blank = true;
+ flags |= WALLET_FLAG_BLANK_WALLET;
+ }
+ SecureString passphrase;
+ passphrase.reserve(100);
+ if (!request.params[3].isNull()) {
+ passphrase = request.params[3].get_str().c_str();
+ if (passphrase.empty()) {
+ // Empty string is invalid
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Cannot encrypt a wallet with a blank password");
+ }
+ // Born encrypted wallets need to be blank first so that wallet creation doesn't make any unencrypted keys
flags |= WALLET_FLAG_BLANK_WALLET;
}
+ if (!request.params[4].isNull() && request.params[4].get_bool()) {
+ flags |= WALLET_FLAG_AVOID_REUSE;
+ }
+
WalletLocation location(request.params[0].get_str());
if (location.Exists()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists.");
@@ -2613,6 +2805,29 @@ static UniValue createwallet(const JSONRPCRequest& request)
if (!wallet) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed.");
}
+
+ // Encrypt the wallet if there's a passphrase
+ if (!passphrase.empty() && !(flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ if (!wallet->EncryptWallet(passphrase)) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet created but failed to encrypt.");
+ }
+
+ if (!create_blank) {
+ // Unlock the wallet
+ if (!wallet->Unlock(passphrase)) {
+ throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Wallet was encrypted but could not be unlocked");
+ }
+
+ // Set a seed for the wallet
+ CPubKey master_pub_key = wallet->GenerateNewSeed();
+ wallet->SetHDSeed(master_pub_key);
+ wallet->NewKeyPool();
+
+ // Relock the wallet
+ wallet->Lock();
+ }
+ }
+
AddWallet(wallet);
wallet->postInitProcess();
@@ -2668,50 +2883,6 @@ static UniValue unloadwallet(const JSONRPCRequest& request)
return NullUniValue;
}
-static UniValue resendwallettransactions(const JSONRPCRequest& request)
-{
- std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- CWallet* const pwallet = wallet.get();
-
- if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
- return NullUniValue;
- }
-
- if (request.fHelp || request.params.size() != 0)
- throw std::runtime_error(
- RPCHelpMan{"resendwallettransactions",
- "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
- "Intended only for testing; the wallet code periodically re-broadcasts\n"
- "automatically.\n",
- {},
- RPCResult{
- "Returns an RPC error if -walletbroadcast is set to false.\n"
- "Returns array of transaction ids that were re-broadcast.\n"
- },
- RPCExamples{""},
- }.ToString()
- );
-
- if (!pwallet->chain().p2pEnabled()) {
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- }
-
- auto locked_chain = pwallet->chain().lock();
- LOCK(pwallet->cs_wallet);
-
- if (!pwallet->GetBroadcastTransactions()) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast");
- }
-
- std::vector<uint256> txids = pwallet->ResendWalletTransactionsBefore(*locked_chain, GetTime());
- UniValue result(UniValue::VARR);
- for (const uint256& txid : txids)
- {
- result.push_back(txid.ToString());
- }
- return result;
-}
-
static UniValue listunspent(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -2721,9 +2892,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 5)
- throw std::runtime_error(
- RPCHelpMan{"listunspent",
+ const RPCHelpMan help{
+ "listunspent",
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n",
@@ -2760,6 +2930,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
" \"witnessScript\" : \"script\" (string) witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH\n"
" \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
" \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
+ " \"reused\" : xxx, (bool) (only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)\n"
" \"desc\" : xxx, (string, only when solvable) A descriptor for spending this output\n"
" \"safe\" : xxx (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
" from outside keys and unconfirmed replacement transactions are considered unsafe\n"
@@ -2775,7 +2946,11 @@ static UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
+ HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
int nMinDepth = 1;
if (!request.params[0].isNull()) {
@@ -2839,17 +3014,22 @@ static UniValue listunspent(const JSONRPCRequest& request)
UniValue results(UniValue::VARR);
std::vector<COutput> vecOutputs;
{
+ CCoinControl cctl;
+ cctl.m_avoid_address_reuse = false;
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
- pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
+ pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
}
LOCK(pwallet->cs_wallet);
+ const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
+
for (const COutput& out : vecOutputs) {
CTxDestination address;
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
bool fValidAddress = ExtractDestination(scriptPubKey, address);
+ bool reused = avoid_reuse && pwallet->IsUsedDestination(address);
if (destinations.size() && (!fValidAddress || !destinations.count(address)))
continue;
@@ -2867,7 +3047,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
}
if (scriptPubKey.IsPayToScriptHash()) {
- const CScriptID& hash = boost::get<CScriptID>(address);
+ const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
CScript redeemScript;
if (pwallet->GetCScript(hash, redeemScript)) {
entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()));
@@ -2906,6 +3086,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
auto descriptor = InferDescriptor(scriptPubKey, *pwallet);
entry.pushKV("desc", descriptor->ToString());
}
+ if (avoid_reuse) entry.pushKV("reused", reused);
entry.pushKV("safe", out.fSafe);
results.push_back(entry);
}
@@ -3038,9 +3219,7 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
- throw std::runtime_error(
- RPCHelpMan{"fundrawtransaction",
+ const RPCHelpMan help{"fundrawtransaction",
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
"This will not modify existing inputs, and will add at most one change output to the outputs.\n"
"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
@@ -3079,8 +3258,13 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"CONSERVATIVE\""},
},
"options"},
- {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction \n"
- " If iswitness is not present, heuristic tests will be used in decoding"},
+ {"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
+ "If iswitness is not present, heuristic tests will be used in decoding.\n"
+ "If true, only witness deserialization will be tried.\n"
+ "If false, only non-witness deserialization will be tried.\n"
+ "This boolean should reflect whether the transaction has inputs\n"
+ "(e.g. fully valid, or on-chain transactions), if known by the caller."
+ },
},
RPCResult{
"{\n"
@@ -3099,7 +3283,11 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
"\nSend the transaction\n"
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
},
- }.ToString());
+ };
+
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size())) {
+ throw std::runtime_error(help.ToString());
+ }
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
@@ -3150,7 +3338,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
{"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
{"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
{"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
- {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount spent"},
+ {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"},
},
},
},
@@ -3197,7 +3385,14 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
- return SignTransaction(pwallet->chain(), mtx, request.params[1], pwallet, false, request.params[2]);
+ // Fetch previous transactions (inputs):
+ std::map<COutPoint, Coin> coins;
+ for (const CTxIn& txin : mtx.vin) {
+ coins[txin.prevout]; // Create empty map entry keyed by prevout.
+ }
+ pwallet->chain().findCoins(coins);
+
+ return SignTransaction(mtx, request.params[1], pwallet, coins, false, request.params[2]);
}
static UniValue bumpfee(const JSONRPCRequest& request)
@@ -3214,9 +3409,9 @@ static UniValue bumpfee(const JSONRPCRequest& request)
RPCHelpMan{"bumpfee",
"\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
"An opt-in RBF transaction with the given txid must be in the wallet.\n"
- "The command will pay the additional fee by decreasing (or perhaps removing) its change output.\n"
- "If the change output is not big enough to cover the increased fee, the command will currently fail\n"
- "instead of adding new inputs to compensate. (A future implementation could improve this.)\n"
+ "The command will 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.\n"
+ "If `totalFee` is given, adding inputs is not supported, so there must be a single change output that is big enough or it will fail.\n"
+ "All inputs in the original transaction will be included in the replacement transaction.\n"
"The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
"By default, the new fee will be calculated automatically using estimatesmartfee.\n"
"The user can specify a confirmation target for estimatesmartfee.\n"
@@ -3313,7 +3508,14 @@ static UniValue bumpfee(const JSONRPCRequest& request)
CAmount old_fee;
CAmount new_fee;
CMutableTransaction mtx;
- feebumper::Result res = feebumper::CreateTransaction(pwallet, hash, coin_control, totalFee, errors, old_fee, new_fee, mtx);
+ feebumper::Result res;
+ if (totalFee > 0) {
+ // Targeting total fee bump. Requires a change output of sufficient size.
+ res = feebumper::CreateTotalBumpTransaction(pwallet, hash, coin_control, totalFee, errors, old_fee, new_fee, mtx);
+ } else {
+ // Targeting feerate bump.
+ res = feebumper::CreateRateBumpTransaction(pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
+ }
if (res != feebumper::Result::OK) {
switch(res) {
case feebumper::Result::INVALID_ADDRESS_OR_KEY:
@@ -3368,7 +3570,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 2) {
throw std::runtime_error(
RPCHelpMan{"rescanblockchain",
- "\nRescan the local blockchain for wallet related transactions.\n",
+ "\nRescan the local blockchain for wallet related transactions.\n"
+ "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"start_height", RPCArg::Type::NUM, /* default */ "0", "block height where the rescan should start"},
{"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
@@ -3455,7 +3658,7 @@ class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
public:
CWallet * const pwallet;
- void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const
+ void ProcessSubScript(const CScript& subscript, UniValue& obj) const
{
// Always present: script type and redeemscript
std::vector<std::vector<unsigned char>> solutions_data;
@@ -3464,7 +3667,6 @@ public:
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
CTxDestination embedded;
- UniValue a(UniValue::VARR);
if (ExtractDestination(subscript, embedded)) {
// Only when the script corresponds to an address.
UniValue subobj(UniValue::VOBJ);
@@ -3477,7 +3679,6 @@ public:
// Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
obj.pushKV("embedded", std::move(subobj));
- if (include_addresses) a.push_back(EncodeDestination(embedded));
} else if (which_type == TX_MULTISIG) {
// Also report some information on multisig scripts (which do not have a corresponding address).
// TODO: abstract out the common functionality between this logic and ExtractDestinations.
@@ -3485,25 +3686,19 @@ public:
UniValue pubkeys(UniValue::VARR);
for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
- if (include_addresses) a.push_back(EncodeDestination(key.GetID()));
pubkeys.push_back(HexStr(key.begin(), key.end()));
}
obj.pushKV("pubkeys", std::move(pubkeys));
}
-
- // The "addresses" field is confusing because it refers to public keys using their P2PKH address.
- // For that reason, only add the 'addresses' field when needed for backward compatibility. New applications
- // can use the 'embedded'->'address' field for P2SH or P2WSH wrapped addresses, and 'pubkeys' for
- // inspecting multisig participants.
- if (include_addresses) obj.pushKV("addresses", std::move(a));
}
explicit DescribeWalletAddressVisitor(CWallet* _pwallet) : pwallet(_pwallet) {}
UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
- UniValue operator()(const CKeyID& keyID) const
+ UniValue operator()(const PKHash& pkhash) const
{
+ CKeyID keyID(pkhash);
UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
@@ -3513,12 +3708,13 @@ public:
return obj;
}
- UniValue operator()(const CScriptID& scriptID) const
+ UniValue operator()(const ScriptHash& scripthash) const
{
+ CScriptID scriptID(scripthash);
UniValue obj(UniValue::VOBJ);
CScript subscript;
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
- ProcessSubScript(subscript, obj, IsDeprecatedRPCEnabled("validateaddress"));
+ ProcessSubScript(subscript, obj);
}
return obj;
}
@@ -3732,9 +3928,20 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
// Find all addresses that have the given label
UniValue ret(UniValue::VOBJ);
+ std::set<std::string> addresses;
for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
if (item.second.name == label) {
- ret.pushKV(EncodeDestination(item.first), AddressBookDataToJSON(item.second, false));
+ std::string address = EncodeDestination(item.first);
+ // CWallet::mapAddressBook is not expected to contain duplicate
+ // address strings, but build a separate set as a precaution just in
+ // case it does.
+ bool unique = addresses.emplace(address).second;
+ assert(unique);
+ // UniValue::pushKV checks if the key exists in O(N)
+ // and since duplicate addresses are unexpected (checked with
+ // std::set in O(log(N))), UniValue::__pushKV is used instead,
+ // which currently is O(1).
+ ret.__pushKV(address, AddressBookDataToJSON(item.second, false));
}
}
@@ -3881,19 +4088,6 @@ UniValue sethdseed(const JSONRPCRequest& request)
return NullUniValue;
}
-void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
-{
- CPubKey vchPubKey;
- if (!pwallet->GetPubKey(keyID, vchPubKey)) {
- return;
- }
- KeyOriginInfo info;
- if (!pwallet->GetKeyOrigin(keyID, info)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
- }
- hd_keypaths.emplace(vchPubKey, std::move(info));
-}
-
UniValue walletprocesspsbt(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
@@ -4098,26 +4292,26 @@ UniValue importmulti(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
- { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
{ "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", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank"} },
+ { "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse"} },
{ "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"} },
+ { "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"} },
{ "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
+ { "wallet", "getbalances", &getbalances, {} },
{ "wallet", "getwalletinfo", &getwalletinfo, {} },
{ "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
{ "wallet", "importmulti", &importmulti, {"requests","options"} },
@@ -4141,10 +4335,11 @@ static const CRPCCommand commands[] =
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
{ "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
- { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse"} },
{ "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"} },
@@ -4156,8 +4351,8 @@ static const CRPCCommand commands[] =
};
// clang-format on
-void RegisterWalletRPCCommands(CRPCTable &t)
+void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers)
{
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
- t.appendCommand(commands[vcidx].name, &commands[vcidx]);
+ handlers.emplace_back(chain.handleRpc(commands[vcidx]));
}
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index 58053bde59..1c0523c90b 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -1,11 +1,13 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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_WALLET_RPCWALLET_H
#define BITCOIN_WALLET_RPCWALLET_H
+#include <memory>
#include <string>
+#include <vector>
class CRPCTable;
class CWallet;
@@ -14,7 +16,12 @@ class UniValue;
struct PartiallySignedTransaction;
class CTransaction;
-void RegisterWalletRPCCommands(CRPCTable &t);
+namespace interfaces {
+class Chain;
+class Handler;
+}
+
+void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers);
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
@@ -24,9 +31,9 @@ void RegisterWalletRPCCommands(CRPCTable &t);
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
-std::string HelpRequiringPassphrase(CWallet *);
-void EnsureWalletIsUnlocked(CWallet *);
-bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
+std::string HelpRequiringPassphrase(const CWallet*);
+void EnsureWalletIsUnlocked(const CWallet*);
+bool EnsureWalletIsAvailable(const CWallet*, bool avoidException);
UniValue getaddressinfo(const JSONRPCRequest& request);
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 5c65acf601..9e7f0ed773 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -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.
@@ -8,7 +8,7 @@
#include <amount.h>
#include <primitives/transaction.h>
#include <random.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <wallet/test/wallet_test_fixture.h>
#include <boost/test/unit_test.hpp>
@@ -29,7 +29,7 @@ typedef std::set<CInputCoin> CoinSet;
static std::vector<COutput> vCoins;
static auto testChain = interfaces::MakeChain();
-static CWallet testWallet(*testChain, WalletLocation(), WalletDatabase::CreateDummy());
+static CWallet testWallet(testChain.get(), WalletLocation(), WalletDatabase::CreateDummy());
static CAmount balance = 0;
CoinEligibilityFilter filter_standard(1, 6, 0);
@@ -69,8 +69,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa
std::unique_ptr<CWalletTx> wtx = MakeUnique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
if (fIsFromMe)
{
- wtx->fDebitCached = true;
- wtx->nDebitCached = 1;
+ wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
}
COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
vCoins.push_back(output);
@@ -115,7 +114,7 @@ inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& coins)
{
static std::vector<OutputGroup> static_groups;
static_groups.clear();
- for (auto& coin : coins) static_groups.emplace_back(coin.GetInputCoin(), coin.nDepth, coin.tx->fDebitCached && coin.tx->nDebitCached == 1 /* HACK: we can't figure out the is_me flag so we use the conditions defined above; perhaps set safe to false for !fIsFromMe in add_coin() */, 0, 0);
+ for (auto& coin : coins) static_groups.emplace_back(coin.GetInputCoin(), coin.nDepth, coin.tx->m_amounts[CWalletTx::DEBIT].m_cached[ISMINE_SPENDABLE] && coin.tx->m_amounts[CWalletTx::DEBIT].m_value[ISMINE_SPENDABLE] == 1 /* HACK: we can't figure out the is_me flag so we use the conditions defined above; perhaps set safe to false for !fIsFromMe in add_coin() */, 0, 0);
return static_groups;
}
@@ -135,7 +134,6 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
/////////////////////////
// Known Outcome tests //
/////////////////////////
- BOOST_TEST_MESSAGE("Testing known outcomes");
// Empty utxo pool
BOOST_CHECK(!SelectCoinsBnB(GroupCoins(utxo_pool), 1 * CENT, 0.5 * CENT, selection, value_ret, not_input_fees));
diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp
index 2a64749379..c961456572 100644
--- a/src/wallet/test/db_tests.cpp
+++ b/src/wallet/test/db_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
@@ -7,7 +7,7 @@
#include <boost/test/unit_test.hpp>
#include <fs.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <wallet/db.h>
@@ -16,7 +16,7 @@ BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(getwalletenv_file)
{
std::string test_name = "test_name.dat";
- fs::path datadir = SetDataDir("tempdir");
+ const fs::path datadir = GetDataDir();
fs::path file_path = datadir / test_name;
std::ofstream f(file_path.BOOST_FILESYSTEM_C_STR);
f.close();
@@ -30,7 +30,7 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file)
BOOST_AUTO_TEST_CASE(getwalletenv_directory)
{
std::string expected_name = "wallet.dat";
- fs::path datadir = SetDataDir("tempdir");
+ const fs::path datadir = GetDataDir();
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(datadir, filename);
@@ -40,8 +40,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_directory)
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
{
- fs::path datadir = SetDataDir("tempdir");
- fs::path datadir_2 = SetDataDir("tempdir_2");
+ fs::path datadir = GetDataDir() / "1";
+ fs::path datadir_2 = GetDataDir() / "2";
std::string filename;
std::shared_ptr<BerkeleyEnvironment> env_1 = GetWalletEnv(datadir, filename);
@@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_multiple)
BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance)
{
- fs::path datadir = SetDataDir("tempdir");
- fs::path datadir_2 = SetDataDir("tempdir_2");
+ fs::path datadir = GetDataDir() / "1";
+ fs::path datadir_2 = GetDataDir() / "2";
std::string filename;
std::shared_ptr <BerkeleyEnvironment> env_1_a = GetWalletEnv(datadir, filename);
diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp
index 3b828d57f9..86ba0013fe 100644
--- a/src/wallet/test/init_test_fixture.cpp
+++ b/src/wallet/test/init_test_fixture.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <fs.h>
+#include <util/system.h>
#include <wallet/test/init_test_fixture.h>
@@ -13,7 +14,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam
std::string sep;
sep += fs::path::preferred_separator;
- m_datadir = SetDataDir("tempdir");
+ m_datadir = GetDataDir();
m_cwd = fs::current_path();
m_walletdir_path_cases["default"] = m_datadir / "wallets";
@@ -41,4 +42,4 @@ InitWalletDirTestingSetup::~InitWalletDirTestingSetup()
void InitWalletDirTestingSetup::SetWalletDir(const fs::path& walletdir_path)
{
gArgs.ForceSetArg("-walletdir", walletdir_path.string());
-} \ No newline at end of file
+}
diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h
index cd47b31da1..e2b7075085 100644
--- a/src/wallet/test/init_test_fixture.h
+++ b/src/wallet/test/init_test_fixture.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
@@ -6,7 +6,7 @@
#define BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H
#include <interfaces/chain.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
struct InitWalletDirTestingSetup: public BasicTestingSetup {
diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp
index 5852d3ef84..1816fca257 100644
--- a/src/wallet/test/init_tests.cpp
+++ b/src/wallet/test/init_tests.cpp
@@ -1,17 +1,13 @@
-// Copyright (c) 2018 The Bitcoin Core developers
+// 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.
#include <boost/test/unit_test.hpp>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
+#include <util/system.h>
#include <wallet/test/init_test_fixture.h>
-#include <init.h>
-#include <walletinitinterface.h>
-#include <wallet/wallet.h>
-
-
BOOST_FIXTURE_TEST_SUITE(init_tests, InitWalletDirTestingSetup)
BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default)
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
new file mode 100644
index 0000000000..062fef7748
--- /dev/null
+++ b/src/wallet/test/ismine_tests.cpp
@@ -0,0 +1,398 @@
+// 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.
+
+#include <key.h>
+#include <script/script.h>
+#include <script/standard.h>
+#include <test/setup_common.h>
+#include <wallet/ismine.h>
+#include <wallet/wallet.h>
+
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(ismine_standard)
+{
+ CKey keys[2];
+ CPubKey pubkeys[2];
+ for (int i = 0; i < 2; i++) {
+ keys[i].MakeNewKey(true);
+ pubkeys[i] = keys[i].GetPubKey();
+ }
+
+ CKey uncompressedKey;
+ uncompressedKey.MakeNewKey(false);
+ CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
+ std::unique_ptr<interfaces::Chain> chain = interfaces::MakeChain();
+
+ CScript scriptPubKey;
+ isminetype result;
+
+ // P2PK compressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PK uncompressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PKH compressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2PKH uncompressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
+
+ // Keystore does not have key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2SH
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+
+ // Keystore does not have redeemScript or key
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has redeemScript but no key
+ BOOST_CHECK(keystore.AddCScript(redeemScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has redeemScript and key
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // (P2PKH inside) P2SH inside P2SH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript redeemscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
+ CScript redeemscript = GetScriptForDestination(ScriptHash(redeemscript_inner));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemscript));
+
+ BOOST_CHECK(keystore.AddCScript(redeemscript));
+ BOOST_CHECK(keystore.AddCScript(redeemscript_inner));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // (P2PKH inside) P2SH inside P2WSH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript redeemscript = GetScriptForDestination(PKHash(pubkeys[0]));
+ CScript witnessscript = GetScriptForDestination(ScriptHash(redeemscript));
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
+
+ BOOST_CHECK(keystore.AddCScript(witnessscript));
+ BOOST_CHECK(keystore.AddCScript(redeemscript));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2WPKH inside P2WSH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
+
+ BOOST_CHECK(keystore.AddCScript(witnessscript));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // (P2PKH inside) P2WSH inside P2WSH (invalid)
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript witnessscript_inner = GetScriptForDestination(PKHash(pubkeys[0]));
+ CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
+
+ BOOST_CHECK(keystore.AddCScript(witnessscript_inner));
+ BOOST_CHECK(keystore.AddCScript(witnessscript));
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2WPKH compressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(pubkeys[0])));
+
+ // Keystore implicitly has key and P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WPKH uncompressed
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+
+ scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(PKHash(uncompressedPubkey)));
+
+ // Keystore has key, but no P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has key and P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // scriptPubKey multisig
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+
+ // Keystore does not have any keys
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has 1/2 keys
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has 2/2 keys
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has 2/2 keys and the script
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2SH multisig
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+
+ // Keystore has no redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has redeemScript
+ BOOST_CHECK(keystore.AddCScript(redeemScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WSH multisig with compressed keys
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(witnessScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // P2WSH multisig with uncompressed key
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(uncompressedKey));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+
+ CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
+ scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+
+ // Keystore has keys, but no witnessScript or P2SH redeemScript
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys and witnessScript, but no P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(witnessScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ BOOST_CHECK(keystore.AddCScript(scriptPubKey));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // P2WSH multisig wrapped in P2SH
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+
+ CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
+ CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
+ scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
+
+ // Keystore has no witnessScript, P2SH redeemScript, or keys
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has witnessScript and P2SH redeemScript, but no keys
+ BOOST_CHECK(keystore.AddCScript(redeemScript));
+ BOOST_CHECK(keystore.AddCScript(witnessScript));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+
+ // Keystore has keys, witnessScript, P2SH redeemScript
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+ BOOST_CHECK(keystore.AddKey(keys[1]));
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
+ }
+
+ // OP_RETURN
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // witness unspendable
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // witness unknown
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+
+ // Nonstandard
+ {
+ CWallet keystore(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
+ LOCK(keystore.cs_wallet);
+ BOOST_CHECK(keystore.AddKey(keys[0]));
+
+ scriptPubKey.clear();
+ scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
+
+ result = IsMine(keystore, scriptPubKey);
+ BOOST_CHECK_EQUAL(result, ISMINE_NO);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 789e86e21b..0400f1207c 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -1,18 +1,15 @@
-// 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.
#include <key_io.h>
-#include <script/sign.h>
#include <util/bip32.h>
#include <util/strencodings.h>
#include <wallet/psbtwallet.h>
-#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
-#include <univalue.h>
#include <boost/test/unit_test.hpp>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <wallet/test/wallet_test_fixture.h>
BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index ae7092fa89..2f41813234 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -1,8 +1,8 @@
-// Copyright (c) 2014-2018 The Bitcoin Core developers
+// Copyright (c) 2014-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 <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <util/strencodings.h>
#include <wallet/crypter.h>
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index a5fb1db86c..ba0843f352 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -1,24 +1,16 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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 <wallet/test/wallet_test_fixture.h>
-#include <rpc/server.h>
-#include <wallet/db.h>
-#include <wallet/rpcwallet.h>
-
-WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
- TestingSetup(chainName), m_wallet(*m_chain, WalletLocation(), WalletDatabase::CreateMock())
+WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
+ : TestingSetup(chainName),
+ m_wallet(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock())
{
bool fFirstRun;
m_wallet.LoadWallet(fFirstRun);
- RegisterValidationInterface(&m_wallet);
-
- RegisterWalletRPCCommands(tableRPC);
-}
+ m_wallet.handleNotifications();
-WalletTestingSetup::~WalletTestingSetup()
-{
- UnregisterValidationInterface(&m_wallet);
+ m_chain_client->registerRpcs();
}
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index e6fe8c9473..c1dbecdf8c 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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_WALLET_TEST_WALLET_TEST_FIXTURE_H
#define BITCOIN_WALLET_TEST_WALLET_TEST_FIXTURE_H
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <interfaces/chain.h>
#include <interfaces/wallet.h>
@@ -17,9 +17,9 @@
*/
struct WalletTestingSetup: public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
- ~WalletTestingSetup();
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
+ std::unique_ptr<interfaces::ChainClient> m_chain_client = interfaces::MakeWalletClient(*m_chain, {});
CWallet m_wallet;
};
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index af57dbf5f6..ef95d0544f 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -5,19 +5,17 @@
#include <wallet/wallet.h>
#include <memory>
-#include <set>
#include <stdint.h>
-#include <utility>
#include <vector>
#include <consensus/validation.h>
#include <interfaces/chain.h>
+#include <policy/policy.h>
#include <rpc/server.h>
-#include <test/test_bitcoin.h>
+#include <test/setup_common.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/test/wallet_test_fixture.h>
-#include <policy/policy.h>
#include <boost/test/unit_test.hpp>
#include <univalue.h>
@@ -36,20 +34,19 @@ static void AddKey(CWallet& wallet, const CKey& key)
BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
{
- auto chain = interfaces::MakeChain();
-
// Cap last block file size, and mine new block in a new block file.
- CBlockIndex* oldTip = chainActive.Tip();
+ CBlockIndex* oldTip = ::ChainActive().Tip();
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- CBlockIndex* newTip = chainActive.Tip();
+ CBlockIndex* newTip = ::ChainActive().Tip();
- LockAnnotation lock(::cs_main);
+ auto chain = interfaces::MakeChain();
auto locked_chain = chain->lock();
+ LockAssertion lock(::cs_main);
// Verify ScanForWalletTransactions accommodates a null start block.
{
- CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
@@ -58,13 +55,13 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK(result.last_scanned_block.IsNull());
BOOST_CHECK(!result.last_scanned_height);
- BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0);
+ BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0);
}
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
@@ -73,7 +70,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK(result.last_failed_block.IsNull());
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
- BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
+ BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 100 * COIN);
}
// Prune the older block file.
@@ -83,7 +80,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
@@ -92,7 +89,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK_EQUAL(result.last_failed_block, oldTip->GetBlockHash());
BOOST_CHECK_EQUAL(result.last_scanned_block, newTip->GetBlockHash());
BOOST_CHECK_EQUAL(*result.last_scanned_height, newTip->nHeight);
- BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
+ BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 50 * COIN);
}
// Prune the remaining block file.
@@ -101,7 +98,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions scans no blocks.
{
- CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
AddKey(wallet, coinbaseKey);
WalletRescanReserver reserver(&wallet);
reserver.reserve();
@@ -110,22 +107,21 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
BOOST_CHECK_EQUAL(result.last_failed_block, newTip->GetBlockHash());
BOOST_CHECK(result.last_scanned_block.IsNull());
BOOST_CHECK(!result.last_scanned_height);
- BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 0);
+ BOOST_CHECK_EQUAL(wallet.GetBalance().m_mine_immature, 0);
}
}
BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
{
- auto chain = interfaces::MakeChain();
-
// Cap last block file size, and mine new block in a new block file.
- CBlockIndex* oldTip = chainActive.Tip();
+ CBlockIndex* oldTip = ::ChainActive().Tip();
GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE;
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- CBlockIndex* newTip = chainActive.Tip();
+ CBlockIndex* newTip = ::ChainActive().Tip();
- LockAnnotation lock(::cs_main);
+ auto chain = interfaces::MakeChain();
auto locked_chain = chain->lock();
+ LockAssertion lock(::cs_main);
// Prune the older block file.
PruneOneBlockFile(oldTip->GetBlockPos().nFile);
@@ -135,7 +131,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
AddWallet(wallet);
UniValue keys;
keys.setArray();
@@ -177,11 +173,9 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// than or equal to key birthday.
BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
{
- auto chain = interfaces::MakeChain();
-
// Create two blocks with same timestamp to verify that importwallet rescan
// will pick up both blocks, not just the first.
- const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
+ const int64_t BLOCK_TIME = ::ChainActive().Tip()->GetBlockTimeMax() + 5;
SetMockTime(BLOCK_TIME);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
@@ -192,13 +186,15 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
SetMockTime(KEY_TIME);
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ auto chain = interfaces::MakeChain();
auto locked_chain = chain->lock();
+ LockAssertion lock(::cs_main);
- std::string backup_file = (SetDataDir("importwallet_rescan") / "wallet.backup").string();
+ std::string backup_file = (GetDataDir() / "wallet.backup").string();
// Import key into wallet and call dumpwallet to create backup file.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
LOCK(wallet->cs_wallet);
wallet->mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
wallet->AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
@@ -214,7 +210,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
JSONRPCRequest request;
request.params.setArray();
@@ -245,11 +241,15 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
auto chain = interfaces::MakeChain();
- CWallet wallet(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+
+ CWallet wallet(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
CWalletTx wtx(&wallet, m_coinbase_txns.back());
+
auto locked_chain = chain->lock();
+ LockAssertion lock(::cs_main);
LOCK(wallet.cs_wallet);
- wtx.hashBlock = chainActive.Tip()->GetBlockHash();
+
+ wtx.hashBlock = ::ChainActive().Tip()->GetBlockHash();
wtx.nIndex = 0;
// Call GetImmatureCredit() once before adding the key to the wallet to
@@ -270,8 +270,8 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
if (blockTime > 0) {
- LockAnnotation lock(::cs_main);
auto locked_chain = wallet.chain().lock();
+ LockAssertion lock(::cs_main);
auto inserted = mapBlockIndex.emplace(GetRandHash(), new CBlockIndex);
assert(inserted.second);
const uint256& hash = inserted.first->first;
@@ -322,7 +322,7 @@ BOOST_AUTO_TEST_CASE(ComputeTimeSmart)
BOOST_AUTO_TEST_CASE(LoadReceiveRequests)
{
- CTxDestination dest = CKeyID();
+ CTxDestination dest = PKHash();
LOCK(m_wallet.cs_wallet);
m_wallet.AddDestData(dest, "misc", "val_misc");
m_wallet.AddDestData(dest, "rr0", "val_rr0");
@@ -340,16 +340,16 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = MakeUnique<CWallet>(*m_chain, WalletLocation(), WalletDatabase::CreateMock());
+ wallet = MakeUnique<CWallet>(m_chain.get(), WalletLocation(), WalletDatabase::CreateMock());
bool firstRun;
wallet->LoadWallet(firstRun);
AddKey(*wallet, coinbaseKey);
WalletRescanReserver reserver(wallet.get());
reserver.reserve();
- CWallet::ScanResult result = wallet->ScanForWalletTransactions(chainActive.Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
+ CWallet::ScanResult result = wallet->ScanForWalletTransactions(::ChainActive().Genesis()->GetBlockHash(), {} /* stop_block */, reserver, false /* update */);
BOOST_CHECK_EQUAL(result.status, CWallet::ScanResult::SUCCESS);
- BOOST_CHECK_EQUAL(result.last_scanned_block, chainActive.Tip()->GetBlockHash());
- BOOST_CHECK_EQUAL(*result.last_scanned_height, chainActive.Height());
+ BOOST_CHECK_EQUAL(result.last_scanned_block, ::ChainActive().Tip()->GetBlockHash());
+ BOOST_CHECK_EQUAL(*result.last_scanned_height, ::ChainActive().Height());
BOOST_CHECK(result.last_failed_block.IsNull());
}
@@ -366,7 +366,10 @@ public:
int changePos = -1;
std::string error;
CCoinControl dummy;
- BOOST_CHECK(wallet->CreateTransaction(*m_locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy));
+ {
+ auto locked_chain = m_chain->lock();
+ BOOST_CHECK(wallet->CreateTransaction(*locked_chain, {recipient}, tx, reservekey, fee, changePos, error, dummy));
+ }
CValidationState state;
BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, state));
CMutableTransaction blocktx;
@@ -375,15 +378,16 @@ public:
blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx);
}
CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+
+ LOCK(cs_main);
LOCK(wallet->cs_wallet);
auto it = wallet->mapWallet.find(tx->GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
- it->second.SetMerkleBranch(chainActive.Tip()->GetBlockHash(), 1);
+ it->second.SetMerkleBranch(::ChainActive().Tip()->GetBlockHash(), 1);
return it->second;
}
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
- std::unique_ptr<interfaces::Chain::Lock> m_locked_chain = m_chain->assumeLocked(); // Temporary. Removed in upcoming lock cleanup
std::unique_ptr<CWallet> wallet;
};
@@ -395,11 +399,12 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
// address.
std::map<CTxDestination, std::vector<COutput>> list;
{
- LOCK2(cs_main, wallet->cs_wallet);
- list = wallet->ListCoins(*m_locked_chain);
+ auto locked_chain = m_chain->lock();
+ LOCK(wallet->cs_wallet);
+ list = wallet->ListCoins(*locked_chain);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 1U);
// Check initial balance from one mature coinbase transaction.
@@ -411,18 +416,20 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
// pubkey.
AddTx(CRecipient{GetScriptForRawPubKey({}), 1 * COIN, false /* subtract fee */});
{
- LOCK2(cs_main, wallet->cs_wallet);
- list = wallet->ListCoins(*m_locked_chain);
+ auto locked_chain = m_chain->lock();
+ LOCK(wallet->cs_wallet);
+ list = wallet->ListCoins(*locked_chain);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(boost::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.
{
- LOCK2(cs_main, wallet->cs_wallet);
+ auto locked_chain = m_chain->lock();
+ LOCK(wallet->cs_wallet);
std::vector<COutput> available;
- wallet->AvailableCoins(*m_locked_chain, available);
+ wallet->AvailableCoins(*locked_chain, available);
BOOST_CHECK_EQUAL(available.size(), 2U);
}
for (const auto& group : list) {
@@ -432,26 +439,28 @@ BOOST_FIXTURE_TEST_CASE(ListCoins, ListCoinsTestingSetup)
}
}
{
- LOCK2(cs_main, wallet->cs_wallet);
+ auto locked_chain = m_chain->lock();
+ LOCK(wallet->cs_wallet);
std::vector<COutput> available;
- wallet->AvailableCoins(*m_locked_chain, available);
+ wallet->AvailableCoins(*locked_chain, available);
BOOST_CHECK_EQUAL(available.size(), 0U);
}
// Confirm ListCoins still returns same result as before, despite coins
// being locked.
{
- LOCK2(cs_main, wallet->cs_wallet);
- list = wallet->ListCoins(*m_locked_chain);
+ auto locked_chain = m_chain->lock();
+ LOCK(wallet->cs_wallet);
+ list = wallet->ListCoins(*locked_chain);
}
BOOST_CHECK_EQUAL(list.size(), 1U);
- BOOST_CHECK_EQUAL(boost::get<CKeyID>(list.begin()->first).ToString(), coinbaseAddress);
+ BOOST_CHECK_EQUAL(boost::get<PKHash>(list.begin()->first).ToString(), coinbaseAddress);
BOOST_CHECK_EQUAL(list.begin()->second.size(), 2U);
}
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
auto chain = interfaces::MakeChain();
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(*chain, WalletLocation(), WalletDatabase::CreateDummy());
+ std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), WalletLocation(), WalletDatabase::CreateDummy());
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
BOOST_CHECK(!wallet->TopUpKeyPool(1000));
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 02f3a265d9..8807acb6b7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1,13 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <wallet/wallet.h>
-#include <checkpoints.h>
#include <chain.h>
-#include <wallet/coincontrol.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <fs.h>
@@ -16,20 +14,20 @@
#include <key.h>
#include <key_io.h>
#include <keystore.h>
-#include <validation.h>
-#include <net.h>
#include <policy/fees.h>
#include <policy/policy.h>
-#include <policy/rbf.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/descriptor.h>
#include <script/script.h>
-#include <shutdown.h>
-#include <timedata.h>
-#include <txmempool.h>
#include <util/bip32.h>
+#include <util/error.h>
+#include <util/fees.h>
#include <util/moneystr.h>
+#include <util/rbf.h>
+#include <util/validation.h>
+#include <validation.h>
+#include <wallet/coincontrol.h>
#include <wallet/fees.h>
#include <algorithm>
@@ -38,6 +36,14 @@
#include <boost/algorithm/string/replace.hpp>
+const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{
+ {WALLET_FLAG_AVOID_REUSE,
+ "You need to rescan the blockchain in order to correctly mark used "
+ "destinations in the past. Until this is done, some destinations may "
+ "be considered unused, even if the opposite is the case."
+ },
+};
+
static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10;
static CCriticalSection cs_wallets;
@@ -96,7 +102,7 @@ static void ReleaseWallet(CWallet* wallet)
wallet->WalletLogPrintf("Releasing wallet\n");
wallet->BlockUntilSyncedToCurrentChain();
wallet->Flush();
- UnregisterValidationInterface(wallet);
+ wallet->m_chain_notifications_handler.reset();
delete wallet;
// Wallet is now released, notify UnloadWallet, if any.
{
@@ -193,7 +199,7 @@ CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal)
{
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
assert(!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));
- AssertLockHeld(cs_wallet); // mapKeyMetadata
+ AssertLockHeld(cs_wallet);
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
CKey secret;
@@ -281,9 +287,9 @@ void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey
throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed");
}
-bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const CPubKey &pubkey)
+bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const CPubKey& pubkey)
{
- AssertLockHeld(cs_wallet); // mapKeyMetadata
+ AssertLockHeld(cs_wallet);
// Make sure we aren't adding private keys to private key disabled wallets
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
@@ -303,7 +309,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C
// check if we need to remove from watch-only
CScript script;
- script = GetScriptForDestination(pubkey.GetID());
+ script = GetScriptForDestination(PKHash(pubkey));
if (HaveWatchOnly(script)) {
RemoveWatchOnly(script);
}
@@ -317,7 +323,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C
secret.GetPrivKey(),
mapKeyMetadata[pubkey.GetID()]);
}
- UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
+ UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
return true;
}
@@ -345,35 +351,28 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
}
}
-void CWallet::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &meta)
+void CWallet::LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata& meta)
{
- AssertLockHeld(cs_wallet); // mapKeyMetadata
+ AssertLockHeld(cs_wallet);
UpdateTimeFirstKey(meta.nCreateTime);
mapKeyMetadata[keyID] = meta;
}
-void CWallet::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &meta)
+void CWallet::LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata& meta)
{
- AssertLockHeld(cs_wallet); // m_script_metadata
+ AssertLockHeld(cs_wallet);
UpdateTimeFirstKey(meta.nCreateTime);
m_script_metadata[script_id] = meta;
}
-// Writes a keymetadata for a public key. overwrite specifies whether to overwrite an existing metadata for that key if there exists one.
-bool CWallet::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
-{
- return WalletBatch(*database).WriteKeyMetadata(meta, pubkey, overwrite);
-}
-
void CWallet::UpgradeKeyMetadata()
{
- AssertLockHeld(cs_wallet); // mapKeyMetadata
+ AssertLockHeld(cs_wallet);
if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) {
return;
}
std::unique_ptr<WalletBatch> batch = MakeUnique<WalletBatch>(*database);
- size_t cnt = 0;
for (auto& meta_pair : mapKeyMetadata) {
CKeyMetadata& meta = meta_pair.second;
if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && meta.hdKeypath != "s") { // If the hdKeypath is "s", that's the seed and it doesn't have a key origin
@@ -396,10 +395,6 @@ void CWallet::UpgradeKeyMetadata()
CPubKey pubkey;
if (GetPubKey(meta_pair.first, pubkey)) {
batch->WriteKeyMetadata(meta, pubkey, true);
- if (++cnt % 1000 == 0) {
- // avoid creating overlarge in-memory batches in case the wallet contains large amounts of keys
- batch.reset(new WalletBatch(*database));
- }
}
}
}
@@ -430,10 +425,16 @@ void CWallet::UpdateTimeFirstKey(int64_t nCreateTime)
bool CWallet::AddCScript(const CScript& redeemScript)
{
+ WalletBatch batch(*database);
+ return AddCScriptWithDB(batch, redeemScript);
+}
+
+bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript)
+{
if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
- if (WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript)) {
- UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
+ if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) {
+ UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
return true;
}
return false;
@@ -446,7 +447,7 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
* these. Do not add them to the wallet and warn. */
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE)
{
- std::string strAddr = EncodeDestination(CScriptID(redeemScript));
+ std::string strAddr = EncodeDestination(ScriptHash(redeemScript));
WalletLogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr);
return true;
}
@@ -454,20 +455,32 @@ bool CWallet::LoadCScript(const CScript& redeemScript)
return CCryptoKeyStore::AddCScript(redeemScript);
}
-bool CWallet::AddWatchOnly(const CScript& dest)
+bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest)
{
if (!CCryptoKeyStore::AddWatchOnly(dest))
return false;
const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)];
UpdateTimeFirstKey(meta.nCreateTime);
NotifyWatchonlyChanged(true);
- if (WalletBatch(*database).WriteWatchOnly(dest, meta)) {
- UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET);
+ if (batch.WriteWatchOnly(dest, meta)) {
+ UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET);
return true;
}
return false;
}
+bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time)
+{
+ m_script_metadata[CScriptID(dest)].nCreateTime = create_time;
+ return AddWatchOnlyWithDB(batch, dest);
+}
+
+bool CWallet::AddWatchOnly(const CScript& dest)
+{
+ WalletBatch batch(*database);
+ return AddWatchOnlyWithDB(batch, dest);
+}
+
bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime)
{
m_script_metadata[CScriptID(dest)].nCreateTime = nCreateTime;
@@ -569,7 +582,7 @@ void CWallet::ChainStateFlushed(const CBlockLocator& loc)
void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in, bool fExplicit)
{
- LOCK(cs_wallet); // nWalletVersion
+ LOCK(cs_wallet);
if (nWalletVersion >= nVersion)
return;
@@ -593,7 +606,7 @@ void CWallet::SetMinVersion(enum WalletFeature nVersion, WalletBatch* batch_in,
bool CWallet::SetMaxVersion(int nVersion)
{
- LOCK(cs_wallet); // nWalletVersion, nWalletMaxVersion
+ LOCK(cs_wallet);
// cannot downgrade below current version
if (nWalletVersion > nVersion)
return false;
@@ -877,9 +890,9 @@ DBErrors CWallet::ReorderTransactions()
return DBErrors::LOAD_OK;
}
-int64_t CWallet::IncOrderPosNext(WalletBatch *batch)
+int64_t CWallet::IncOrderPosNext(WalletBatch* batch)
{
- AssertLockHeld(cs_wallet); // nOrderPosNext
+ AssertLockHeld(cs_wallet);
int64_t nRet = nOrderPosNext++;
if (batch) {
batch->WriteOrderPosNext(nOrderPosNext);
@@ -927,6 +940,37 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
return success;
}
+void CWallet::SetUsedDestinationState(const uint256& hash, unsigned int n, bool used)
+{
+ const CWalletTx* srctx = GetWalletTx(hash);
+ if (!srctx) return;
+
+ CTxDestination dst;
+ if (ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst)) {
+ if (::IsMine(*this, dst)) {
+ LOCK(cs_wallet);
+ if (used && !GetDestData(dst, "used", nullptr)) {
+ AddDestData(dst, "used", "p"); // p for "present", opposite of absent (null)
+ } else if (!used && GetDestData(dst, "used", nullptr)) {
+ EraseDestData(dst, "used");
+ }
+ }
+ }
+}
+
+bool CWallet::IsUsedDestination(const CTxDestination& dst) const
+{
+ LOCK(cs_wallet);
+ return ::IsMine(*this, dst) && GetDestData(dst, "used", nullptr);
+}
+
+bool CWallet::IsUsedDestination(const uint256& hash, unsigned int n) const
+{
+ CTxDestination dst;
+ const CWalletTx* srctx = GetWalletTx(hash);
+ return srctx && ExtractDestination(srctx->tx->vout[n].scriptPubKey, dst) && IsUsedDestination(dst);
+}
+
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
LOCK(cs_wallet);
@@ -935,6 +979,14 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
uint256 hash = wtxIn.GetHash();
+ if (IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
+ // Mark used destinations
+ for (const CTxIn& txin : wtxIn.tx->vin) {
+ const COutPoint& op = txin.prevout;
+ SetUsedDestinationState(op.hash, op.n, true);
+ }
+ }
+
// Inserts only if not already there, returns tx inserted or tx found
std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn));
CWalletTx& wtx = (*ret.first).second;
@@ -1243,7 +1295,8 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
}
}
-void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) {
+void CWallet::BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) {
+ const uint256& block_hash = block.GetHash();
auto locked_chain = chain().lock();
LOCK(cs_wallet);
// TODO: Temporarily ensure that mempool removals are notified before
@@ -1258,46 +1311,37 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
TransactionRemovedFromMempool(ptx);
}
- for (size_t i = 0; i < pblock->vtx.size(); i++) {
- SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i);
- TransactionRemovedFromMempool(pblock->vtx[i]);
+ for (size_t i = 0; i < block.vtx.size(); i++) {
+ SyncTransaction(block.vtx[i], block_hash, i);
+ TransactionRemovedFromMempool(block.vtx[i]);
}
- m_last_block_processed = pindex->GetBlockHash();
+ m_last_block_processed = block_hash;
}
-void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
+void CWallet::BlockDisconnected(const CBlock& block) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- for (const CTransactionRef& ptx : pblock->vtx) {
+ for (const CTransactionRef& ptx : block.vtx) {
SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
}
}
+void CWallet::UpdatedBlockTip()
+{
+ m_best_block_time = GetTime();
+}
void CWallet::BlockUntilSyncedToCurrentChain() {
- AssertLockNotHeld(cs_main);
AssertLockNotHeld(cs_wallet);
-
- {
- // Skip the queue-draining stuff if we know we're caught up with
- // chainActive.Tip()...
- // We could also take cs_wallet here, and call m_last_block_processed
- // protected by cs_wallet instead of cs_main, but as long as we need
- // cs_main here anyway, it's easier to just call it cs_main-protected.
- auto locked_chain = chain().lock();
-
- if (!m_last_block_processed.IsNull() && locked_chain->isPotentialTip(m_last_block_processed)) {
- return;
- }
- }
-
- // ...otherwise put a callback in the validation interface queue and wait
+ // Skip the queue-draining stuff if we know we're caught up with
+ // ::ChainActive().Tip(), otherwise put a callback in the validation interface queue and wait
// for the queue to drain enough to execute it (indicating we are caught up
// at least with the time we entered this function).
- SyncWithValidationInterfaceQueue();
+ uint256 last_block_hash = WITH_LOCK(cs_wallet, return m_last_block_processed);
+ chain().waitForNotificationsIfNewBlocksConnected(last_block_hash);
}
@@ -1548,13 +1592,19 @@ void CWallet::SetWalletFlag(uint64_t flags)
void CWallet::UnsetWalletFlag(uint64_t flag)
{
+ WalletBatch batch(*database);
+ UnsetWalletFlagWithDB(batch, flag);
+}
+
+void CWallet::UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag)
+{
LOCK(cs_wallet);
m_wallet_flags &= ~flag;
- if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags))
+ if (!batch.WriteWalletFlags(m_wallet_flags))
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
}
-bool CWallet::IsWalletFlagSet(uint64_t flag)
+bool CWallet::IsWalletFlagSet(uint64_t flag) const
{
return (m_wallet_flags & flag);
}
@@ -1563,7 +1613,7 @@ bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly)
{
LOCK(cs_wallet);
m_wallet_flags = overwriteFlags;
- if (((overwriteFlags & g_known_wallet_flags) >> 32) ^ (overwriteFlags >> 32)) {
+ if (((overwriteFlags & KNOWN_WALLET_FLAGS) >> 32) ^ (overwriteFlags >> 32)) {
// contains unknown non-tolerable wallet flags
return false;
}
@@ -1611,6 +1661,80 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut>
return true;
}
+bool CWallet::ImportScripts(const std::set<CScript> scripts)
+{
+ WalletBatch batch(*database);
+ for (const auto& entry : scripts) {
+ if (!HaveCScript(CScriptID(entry)) && !AddCScriptWithDB(batch, entry)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp)
+{
+ WalletBatch batch(*database);
+ for (const auto& entry : privkey_map) {
+ const CKey& key = entry.second;
+ CPubKey pubkey = key.GetPubKey();
+ const CKeyID& id = entry.first;
+ assert(key.VerifyPubKey(pubkey));
+ mapKeyMetadata[id].nCreateTime = timestamp;
+ // If the private key is not present in the wallet, insert it.
+ if (!HaveKey(id) && !AddKeyPubKeyWithDB(batch, key, pubkey)) {
+ return false;
+ }
+ UpdateTimeFirstKey(timestamp);
+ }
+ return true;
+}
+
+bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp)
+{
+ WalletBatch batch(*database);
+ for (const auto& entry : key_origins) {
+ AddKeyOriginWithDB(batch, entry.second.first, entry.second.second);
+ }
+ for (const CKeyID& id : ordered_pubkeys) {
+ auto entry = pubkey_map.find(id);
+ if (entry == pubkey_map.end()) {
+ continue;
+ }
+ const CPubKey& pubkey = entry->second;
+ CPubKey temp;
+ if (!GetPubKey(id, temp) && !AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) {
+ return false;
+ }
+ mapKeyMetadata[id].nCreateTime = timestamp;
+
+ // Add to keypool only works with pubkeys
+ if (add_keypool) {
+ AddKeypoolPubkeyWithDB(pubkey, internal, batch);
+ NotifyCanGetAddressesChanged();
+ }
+ }
+ return true;
+}
+
+bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool internal, const int64_t timestamp)
+{
+ WalletBatch batch(*database);
+ for (const CScript& script : script_pub_keys) {
+ if (!have_solving_data || !::IsMine(*this, script)) { // Always call AddWatchOnly for non-solvable watch-only, so that watch timestamp gets updated
+ if (!AddWatchOnlyWithDB(batch, script, timestamp)) {
+ return false;
+ }
+ }
+ CTxDestination dest;
+ ExtractDestination(script, dest);
+ if (!internal && IsValidDestination(dest)) {
+ SetAddressBookWithDB(batch, dest, label, "receive");
+ }
+ }
+ return true;
+}
+
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, bool use_max_sig)
{
std::vector<CTxOut> txouts;
@@ -1721,7 +1845,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
uint256 start_block;
{
auto locked_chain = chain().lock();
- const Optional<int> start_height = locked_chain->findFirstBlockWithTime(startTime - TIMESTAMP_WINDOW, &start_block);
+ const Optional<int> start_height = locked_chain->findFirstBlockWithTimeAndHeight(startTime - TIMESTAMP_WINDOW, 0, &start_block);
const Optional<int> tip_height = locked_chain->getHeight();
WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, tip_height && start_height ? *tip_height - *start_height + 1 : 0);
}
@@ -1764,6 +1888,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, const uint256& stop_block, const WalletRescanReserver& reserver, bool fUpdate)
{
int64_t nNow = GetTime();
+ int64_t start_time = GetTimeMillis();
assert(reserver.isReserved());
@@ -1772,101 +1897,100 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
+ fAbortRescan = false;
+ ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
+ uint256 tip_hash;
+ // The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
+ Optional<int> block_height = MakeOptional(false, int());
+ double progress_begin;
+ double progress_end;
{
- fAbortRescan = false;
- ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
- uint256 tip_hash;
- // The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
- Optional<int> block_height = MakeOptional(false, int());
- double progress_begin;
- double progress_end;
- {
- auto locked_chain = chain().lock();
- if (Optional<int> tip_height = locked_chain->getHeight()) {
- tip_hash = locked_chain->getBlockHash(*tip_height);
- }
- block_height = locked_chain->getBlockHeight(block_hash);
- progress_begin = chain().guessVerificationProgress(block_hash);
- progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
- }
- double progress_current = progress_begin;
- while (block_height && !fAbortRescan && !ShutdownRequested()) {
- if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
- ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
- }
- if (GetTime() >= nNow + 60) {
- nNow = GetTime();
- WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", *block_height, progress_current);
- }
+ auto locked_chain = chain().lock();
+ if (Optional<int> tip_height = locked_chain->getHeight()) {
+ tip_hash = locked_chain->getBlockHash(*tip_height);
+ }
+ block_height = locked_chain->getBlockHeight(block_hash);
+ progress_begin = chain().guessVerificationProgress(block_hash);
+ progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
+ }
+ double progress_current = progress_begin;
+ while (block_height && !fAbortRescan && !chain().shutdownRequested()) {
+ m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin);
+ if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
+ ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100))));
+ }
+ if (GetTime() >= nNow + 60) {
+ nNow = GetTime();
+ WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", *block_height, progress_current);
+ }
- CBlock block;
- if (chain().findBlock(block_hash, &block) && !block.IsNull()) {
- auto locked_chain = chain().lock();
- LOCK(cs_wallet);
- if (!locked_chain->getBlockHeight(block_hash)) {
- // Abort scan if current block is no longer active, to prevent
- // marking transactions as coming from the wrong block.
- // TODO: This should return success instead of failure, see
- // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518
- result.last_failed_block = block_hash;
- result.status = ScanResult::FAILURE;
- break;
- }
- for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
- SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate);
- }
- // scan succeeded, record block as most recent successfully scanned
- result.last_scanned_block = block_hash;
- result.last_scanned_height = *block_height;
- } else {
- // could not scan block, keep scanning but record this block as the most recent failure
+ CBlock block;
+ if (chain().findBlock(block_hash, &block) && !block.IsNull()) {
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
+ if (!locked_chain->getBlockHeight(block_hash)) {
+ // Abort scan if current block is no longer active, to prevent
+ // marking transactions as coming from the wrong block.
+ // TODO: This should return success instead of failure, see
+ // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518
result.last_failed_block = block_hash;
result.status = ScanResult::FAILURE;
+ break;
}
- if (block_hash == stop_block) {
+ for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
+ SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate);
+ }
+ // scan succeeded, record block as most recent successfully scanned
+ result.last_scanned_block = block_hash;
+ result.last_scanned_height = *block_height;
+ } else {
+ // could not scan block, keep scanning but record this block as the most recent failure
+ result.last_failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
+ }
+ if (block_hash == stop_block) {
+ break;
+ }
+ {
+ auto locked_chain = chain().lock();
+ Optional<int> tip_height = locked_chain->getHeight();
+ if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) {
+ // break successfully when rescan has reached the tip, or
+ // previous block is no longer on the chain due to a reorg
break;
}
- {
- auto locked_chain = chain().lock();
- Optional<int> tip_height = locked_chain->getHeight();
- if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) {
- // break successfully when rescan has reached the tip, or
- // previous block is no longer on the chain due to a reorg
- break;
- }
- // increment block and verification progress
- block_hash = locked_chain->getBlockHash(++*block_height);
- progress_current = chain().guessVerificationProgress(block_hash);
+ // increment block and verification progress
+ block_hash = locked_chain->getBlockHash(++*block_height);
+ progress_current = chain().guessVerificationProgress(block_hash);
- // handle updated tip hash
- const uint256 prev_tip_hash = tip_hash;
- tip_hash = locked_chain->getBlockHash(*tip_height);
- if (stop_block.IsNull() && prev_tip_hash != tip_hash) {
- // in case the tip has changed, update progress max
- progress_end = chain().guessVerificationProgress(tip_hash);
- }
+ // handle updated tip hash
+ const uint256 prev_tip_hash = tip_hash;
+ tip_hash = locked_chain->getBlockHash(*tip_height);
+ if (stop_block.IsNull() && prev_tip_hash != tip_hash) {
+ // in case the tip has changed, update progress max
+ progress_end = chain().guessVerificationProgress(tip_hash);
}
}
- ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
- if (block_height && fAbortRescan) {
- WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current);
- result.status = ScanResult::USER_ABORT;
- } else if (block_height && ShutdownRequested()) {
- WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current);
- result.status = ScanResult::USER_ABORT;
- }
+ }
+ ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
+ if (block_height && fAbortRescan) {
+ WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current);
+ result.status = ScanResult::USER_ABORT;
+ } else if (block_height && chain().shutdownRequested()) {
+ WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", *block_height, progress_current);
+ result.status = ScanResult::USER_ABORT;
+ } else {
+ WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - start_time);
}
return result;
}
-void CWallet::ReacceptWalletTransactions()
+void CWallet::ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain)
{
// If transactions aren't being broadcasted, don't let them into local mempool either
if (!fBroadcastTransactions)
return;
- auto locked_chain = chain().lock();
- LOCK(cs_wallet);
std::map<int64_t, CWalletTx*> mapSorted;
// Sort pending wallet transactions based on their initial wallet insertion order
@@ -1876,7 +2000,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = item.second;
assert(wtx.GetHash() == wtxid);
- int nDepth = wtx.GetDepthInMainChain(*locked_chain);
+ int nDepth = wtx.GetDepthInMainChain(locked_chain);
if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
@@ -1887,26 +2011,31 @@ void CWallet::ReacceptWalletTransactions()
for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) {
CWalletTx& wtx = *(item.second);
CValidationState state;
- wtx.AcceptToMemoryPool(*locked_chain, state);
+ wtx.AcceptToMemoryPool(locked_chain, state);
}
}
bool CWalletTx::RelayWalletTransaction(interfaces::Chain::Lock& locked_chain)
{
- assert(pwallet->GetBroadcastTransactions());
- if (!IsCoinBase() && !isAbandoned() && GetDepthInMainChain(locked_chain) == 0)
- {
- CValidationState state;
- /* GetDepthInMainChain already catches known conflicts. */
- if (InMempool() || AcceptToMemoryPool(locked_chain, state)) {
- pwallet->WalletLogPrintf("Relaying wtx %s\n", GetHash().ToString());
- if (pwallet->chain().p2pEnabled()) {
- pwallet->chain().relayTransaction(GetHash());
- return true;
- }
- }
- }
- return false;
+ // Can't relay if wallet is not broadcasting
+ if (!pwallet->GetBroadcastTransactions()) return false;
+ // Don't relay coinbase transactions outside blocks
+ if (IsCoinBase()) return false;
+ // Don't relay abandoned transactions
+ if (isAbandoned()) return false;
+ // Don't relay conflicted or already confirmed transactions
+ if (GetDepthInMainChain(locked_chain) != 0) return false;
+ // Don't relay transactions that aren't accepted to the mempool
+ CValidationState unused_state;
+ if (!InMempool() && !AcceptToMemoryPool(locked_chain, unused_state)) return false;
+ // Don't try to relay if the node is not connected to the p2p network
+ if (!pwallet->chain().p2pEnabled()) return false;
+
+ // Try to relay the transaction
+ pwallet->WalletLogPrintf("Relaying wtx %s\n", GetHash().ToString());
+ pwallet->chain().relayTransaction(GetHash());
+
+ return true;
}
std::set<uint256> CWalletTx::GetConflicts() const
@@ -1921,33 +2050,26 @@ std::set<uint256> CWalletTx::GetConflicts() const
return result;
}
+CAmount CWalletTx::GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate) const
+{
+ auto& amount = m_amounts[type];
+ if (recalculate || !amount.m_cached[filter]) {
+ amount.Set(filter, type == DEBIT ? pwallet->GetDebit(*tx, filter) : pwallet->GetCredit(*tx, filter));
+ }
+ return amount.m_value[filter];
+}
+
CAmount CWalletTx::GetDebit(const isminefilter& filter) const
{
if (tx->vin.empty())
return 0;
CAmount debit = 0;
- if(filter & ISMINE_SPENDABLE)
- {
- if (fDebitCached)
- debit += nDebitCached;
- else
- {
- nDebitCached = pwallet->GetDebit(*tx, ISMINE_SPENDABLE);
- fDebitCached = true;
- debit += nDebitCached;
- }
+ if (filter & ISMINE_SPENDABLE) {
+ debit += GetCachableAmount(DEBIT, ISMINE_SPENDABLE);
}
- if(filter & ISMINE_WATCH_ONLY)
- {
- if(fWatchDebitCached)
- debit += nWatchDebitCached;
- else
- {
- nWatchDebitCached = pwallet->GetDebit(*tx, ISMINE_WATCH_ONLY);
- fWatchDebitCached = true;
- debit += nWatchDebitCached;
- }
+ if (filter & ISMINE_WATCH_ONLY) {
+ debit += GetCachableAmount(DEBIT, ISMINE_WATCH_ONLY);
}
return debit;
}
@@ -1959,28 +2081,12 @@ CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const ismine
return 0;
CAmount credit = 0;
- if (filter & ISMINE_SPENDABLE)
- {
+ if (filter & ISMINE_SPENDABLE) {
// GetBalance can assume transactions in mapWallet won't change
- if (fCreditCached)
- credit += nCreditCached;
- else
- {
- nCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
- fCreditCached = true;
- credit += nCreditCached;
- }
+ credit += GetCachableAmount(CREDIT, ISMINE_SPENDABLE);
}
- if (filter & ISMINE_WATCH_ONLY)
- {
- if (fWatchCreditCached)
- credit += nWatchCreditCached;
- else
- {
- nWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
- fWatchCreditCached = true;
- credit += nWatchCreditCached;
- }
+ if (filter & ISMINE_WATCH_ONLY) {
+ credit += GetCachableAmount(CREDIT, ISMINE_WATCH_ONLY);
}
return credit;
}
@@ -1988,11 +2094,7 @@ CAmount CWalletTx::GetCredit(interfaces::Chain::Lock& locked_chain, const ismine
CAmount CWalletTx::GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache) const
{
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
- if (fUseCache && fImmatureCreditCached)
- return nImmatureCreditCached;
- nImmatureCreditCached = pwallet->GetCredit(*tx, ISMINE_SPENDABLE);
- fImmatureCreditCached = true;
- return nImmatureCreditCached;
+ return GetCachableAmount(IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
}
return 0;
@@ -2003,31 +2105,23 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
if (pwallet == nullptr)
return 0;
+ // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
+ bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
+
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsImmatureCoinBase(locked_chain))
return 0;
- CAmount* cache = nullptr;
- bool* cache_used = nullptr;
-
- if (filter == ISMINE_SPENDABLE) {
- cache = &nAvailableCreditCached;
- cache_used = &fAvailableCreditCached;
- } else if (filter == ISMINE_WATCH_ONLY) {
- cache = &nAvailableWatchCreditCached;
- cache_used = &fAvailableWatchCreditCached;
- }
-
- if (fUseCache && cache_used && *cache_used) {
- return *cache;
+ if (fUseCache && allow_cache && m_amounts[AVAILABLE_CREDIT].m_cached[filter]) {
+ return m_amounts[AVAILABLE_CREDIT].m_value[filter];
}
+ bool allow_used_addresses = (filter & ISMINE_USED) || !pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
CAmount nCredit = 0;
uint256 hashTx = GetHash();
for (unsigned int i = 0; i < tx->vout.size(); i++)
{
- if (!pwallet->IsSpent(locked_chain, hashTx, i))
- {
+ if (!pwallet->IsSpent(locked_chain, hashTx, i) && (allow_used_addresses || !pwallet->IsUsedDestination(hashTx, i))) {
const CTxOut &txout = tx->vout[i];
nCredit += pwallet->GetCredit(txout, filter);
if (!MoneyRange(nCredit))
@@ -2035,22 +2129,17 @@ CAmount CWalletTx::GetAvailableCredit(interfaces::Chain::Lock& locked_chain, boo
}
}
- if (cache) {
- *cache = nCredit;
- assert(cache_used);
- *cache_used = true;
+ if (allow_cache) {
+ m_amounts[AVAILABLE_CREDIT].Set(filter, nCredit);
}
+
return nCredit;
}
CAmount CWalletTx::GetImmatureWatchOnlyCredit(interfaces::Chain::Lock& locked_chain, const bool fUseCache) const
{
if (IsImmatureCoinBase(locked_chain) && IsInMainChain(locked_chain)) {
- if (fUseCache && fImmatureWatchCreditCached)
- return nImmatureWatchCreditCached;
- nImmatureWatchCreditCached = pwallet->GetCredit(*tx, ISMINE_WATCH_ONLY);
- fImmatureWatchCreditCached = true;
- return nImmatureWatchCreditCached;
+ return GetCachableAmount(IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
}
return 0;
@@ -2111,185 +2200,96 @@ bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const
return CTransaction(tx1) == CTransaction(tx2);
}
-std::vector<uint256> CWallet::ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime)
+// Rebroadcast transactions from the wallet. We do this on a random timer
+// to slightly obfuscate which transactions come from our wallet.
+//
+// Ideally, we'd only resend transactions that we think should have been
+// mined in the most recent block. Any transaction that wasn't in the top
+// blockweight of transactions in the mempool shouldn't have been mined,
+// and so is probably just sitting in the mempool waiting to be confirmed.
+// Rebroadcasting does nothing to speed up confirmation and only damages
+// privacy.
+void CWallet::ResendWalletTransactions()
{
- std::vector<uint256> result;
-
- LOCK(cs_wallet);
-
- // Sort them in chronological order
- std::multimap<unsigned int, CWalletTx*> mapSorted;
- for (std::pair<const uint256, CWalletTx>& item : mapWallet)
- {
- CWalletTx& wtx = item.second;
- // Don't rebroadcast if newer than nTime:
- if (wtx.nTimeReceived > nTime)
- continue;
- mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx));
- }
- for (const std::pair<const unsigned int, CWalletTx*>& item : mapSorted)
- {
- CWalletTx& wtx = *item.second;
- if (wtx.RelayWalletTransaction(locked_chain)) {
- result.push_back(wtx.GetHash());
- }
- }
- return result;
-}
+ // During reindex, importing and IBD, old wallet transactions become
+ // unconfirmed. Don't resend them as that would spam other nodes.
+ if (!chain().isReadyToBroadcast()) return;
-void CWallet::ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman)
-{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
- if (GetTime() < nNextResend || !fBroadcastTransactions)
- return;
+ if (GetTime() < nNextResend || !fBroadcastTransactions) return;
bool fFirst = (nNextResend == 0);
nNextResend = GetTime() + GetRand(30 * 60);
- if (fFirst)
- return;
+ if (fFirst) return;
// Only do it if there's been a new block since last time
- if (nBestBlockTime < nLastResend)
- return;
+ if (m_best_block_time < nLastResend) return;
nLastResend = GetTime();
- // Rebroadcast unconfirmed txes older than 5 minutes before the last
- // block was found:
- auto locked_chain = chain().assumeLocked(); // Temporary. Removed in upcoming lock cleanup
- std::vector<uint256> relayed = ResendWalletTransactionsBefore(*locked_chain, nBestBlockTime-5*60);
- if (!relayed.empty())
- WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size());
-}
-
-/** @} */ // end of mapWallet
-
-
-
-
-/** @defgroup Actions
- *
- * @{
- */
-
+ int relayed_tx_count = 0;
-CAmount CWallet::GetBalance(const isminefilter& filter, const int min_depth) const
-{
- CAmount nTotal = 0;
- {
+ { // locked_chain and cs_wallet scope
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- for (const auto& entry : mapWallet)
- {
- const CWalletTx* pcoin = &entry.second;
- if (pcoin->IsTrusted(*locked_chain) && pcoin->GetDepthInMainChain(*locked_chain) >= min_depth) {
- nTotal += pcoin->GetAvailableCredit(*locked_chain, true, filter);
- }
- }
- }
- return nTotal;
-}
-
-CAmount CWallet::GetUnconfirmedBalance() const
-{
- CAmount nTotal = 0;
- {
- auto locked_chain = chain().lock();
- LOCK(cs_wallet);
- for (const auto& entry : mapWallet)
- {
- const CWalletTx* pcoin = &entry.second;
- if (!pcoin->IsTrusted(*locked_chain) && pcoin->GetDepthInMainChain(*locked_chain) == 0 && pcoin->InMempool())
- nTotal += pcoin->GetAvailableCredit(*locked_chain);
+ // Relay transactions
+ for (std::pair<const uint256, CWalletTx>& item : mapWallet) {
+ CWalletTx& wtx = item.second;
+ // only rebroadcast unconfirmed txes older than 5 minutes before the
+ // last block was found
+ if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue;
+ if (wtx.RelayWalletTransaction(*locked_chain)) ++relayed_tx_count;
}
- }
- return nTotal;
-}
+ } // locked_chain and cs_wallet
-CAmount CWallet::GetImmatureBalance() const
-{
- CAmount nTotal = 0;
- {
- auto locked_chain = chain().lock();
- LOCK(cs_wallet);
- for (const auto& entry : mapWallet)
- {
- const CWalletTx* pcoin = &entry.second;
- nTotal += pcoin->GetImmatureCredit(*locked_chain);
- }
+ if (relayed_tx_count > 0) {
+ WalletLogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed_tx_count);
}
- return nTotal;
}
-CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
+/** @} */ // end of mapWallet
+
+void MaybeResendWalletTxs()
{
- CAmount nTotal = 0;
- {
- auto locked_chain = chain().lock();
- LOCK(cs_wallet);
- for (const auto& entry : mapWallet)
- {
- const CWalletTx* pcoin = &entry.second;
- if (!pcoin->IsTrusted(*locked_chain) && pcoin->GetDepthInMainChain(*locked_chain) == 0 && pcoin->InMempool())
- nTotal += pcoin->GetAvailableCredit(*locked_chain, true, ISMINE_WATCH_ONLY);
- }
+ for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
+ pwallet->ResendWalletTransactions();
}
- return nTotal;
}
-CAmount CWallet::GetImmatureWatchOnlyBalance() const
+
+/** @defgroup Actions
+ *
+ * @{
+ */
+
+
+CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) const
{
- CAmount nTotal = 0;
+ Balance ret;
+ isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
{
auto locked_chain = chain().lock();
LOCK(cs_wallet);
for (const auto& entry : mapWallet)
{
- const CWalletTx* pcoin = &entry.second;
- nTotal += pcoin->GetImmatureWatchOnlyCredit(*locked_chain);
- }
- }
- return nTotal;
-}
-
-// Calculate total balance in a different way from GetBalance. The biggest
-// difference is that GetBalance sums up all unspent TxOuts paying to the
-// wallet, while this sums up both spent and unspent TxOuts paying to the
-// wallet, and then subtracts the values of TxIns spending from the wallet. This
-// also has fewer restrictions on which unconfirmed transactions are considered
-// trusted.
-CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const
-{
- auto locked_chain = chain().lock();
- LOCK(cs_wallet);
-
- CAmount balance = 0;
- for (const auto& entry : mapWallet) {
- const CWalletTx& wtx = entry.second;
- const int depth = wtx.GetDepthInMainChain(*locked_chain);
- if (depth < 0 || !locked_chain->checkFinalTx(*wtx.tx) || wtx.IsImmatureCoinBase(*locked_chain)) {
- continue;
- }
-
- // Loop through tx outputs and add incoming payments. For outgoing txs,
- // treat change outputs specially, as part of the amount debited.
- CAmount debit = wtx.GetDebit(filter);
- const bool outgoing = debit > 0;
- for (const CTxOut& out : wtx.tx->vout) {
- if (outgoing && IsChange(out)) {
- debit -= out.nValue;
- } else if (IsMine(out) & filter && depth >= minDepth) {
- balance += out.nValue;
+ const CWalletTx& wtx = entry.second;
+ const bool is_trusted{wtx.IsTrusted(*locked_chain)};
+ const int tx_depth{wtx.GetDepthInMainChain(*locked_chain)};
+ const CAmount tx_credit_mine{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)};
+ const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(*locked_chain, /* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)};
+ if (is_trusted && tx_depth >= min_depth) {
+ ret.m_mine_trusted += tx_credit_mine;
+ ret.m_watchonly_trusted += tx_credit_watchonly;
}
- }
-
- // For outgoing txs, subtract amount debited.
- if (outgoing) {
- balance -= debit;
+ if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
+ ret.m_mine_untrusted_pending += tx_credit_mine;
+ ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
+ }
+ ret.m_mine_immature += wtx.GetImmatureCredit(*locked_chain);
+ ret.m_watchonly_immature += wtx.GetImmatureWatchOnlyCredit(*locked_chain);
}
}
-
- return balance;
+ return ret;
}
CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
@@ -2310,34 +2310,36 @@ CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const
void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<COutput> &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount, const int nMinDepth, const int nMaxDepth) const
{
- AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
vCoins.clear();
CAmount nTotal = 0;
+ // Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where
+ // a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses
+ bool allow_used_addresses = !IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) || (coinControl && !coinControl->m_avoid_address_reuse);
for (const auto& entry : mapWallet)
{
const uint256& wtxid = entry.first;
- const CWalletTx* pcoin = &entry.second;
+ const CWalletTx& wtx = entry.second;
- if (!locked_chain.checkFinalTx(*pcoin->tx)) {
+ if (!locked_chain.checkFinalTx(*wtx.tx)) {
continue;
}
- if (pcoin->IsImmatureCoinBase(locked_chain))
+ if (wtx.IsImmatureCoinBase(locked_chain))
continue;
- int nDepth = pcoin->GetDepthInMainChain(locked_chain);
+ int nDepth = wtx.GetDepthInMainChain(locked_chain);
if (nDepth < 0)
continue;
// We should not consider coins which aren't at least in our mempool
// It's possible for these to be conflicted via ancestors which we may never be able to detect
- if (nDepth == 0 && !pcoin->InMempool())
+ if (nDepth == 0 && !wtx.InMempool())
continue;
- bool safeTx = pcoin->IsTrusted(locked_chain);
+ bool safeTx = wtx.IsTrusted(locked_chain);
// We should not consider coins from transactions that are replacing
// other transactions.
@@ -2354,7 +2356,7 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
// be a 1-block reorg away from the chain where transactions A and C
// were accepted to another chain where B, B', and C were all
// accepted.
- if (nDepth == 0 && pcoin->mapValue.count("replaces_txid")) {
+ if (nDepth == 0 && wtx.mapValue.count("replaces_txid")) {
safeTx = false;
}
@@ -2366,7 +2368,7 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
// intending to replace A', but potentially resulting in a scenario
// where A, A', and D could all be accepted (instead of just B and
// D, or just A and A' like the user would want).
- if (nDepth == 0 && pcoin->mapValue.count("replaced_by_txid")) {
+ if (nDepth == 0 && wtx.mapValue.count("replaced_by_txid")) {
safeTx = false;
}
@@ -2377,8 +2379,8 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
if (nDepth < nMinDepth || nDepth > nMaxDepth)
continue;
- for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
- if (pcoin->tx->vout[i].nValue < nMinimumAmount || pcoin->tx->vout[i].nValue > nMaximumAmount)
+ for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
+ if (wtx.tx->vout[i].nValue < nMinimumAmount || wtx.tx->vout[i].nValue > nMaximumAmount)
continue;
if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs && !coinControl->IsSelected(COutPoint(entry.first, i)))
@@ -2390,20 +2392,24 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
if (IsSpent(locked_chain, wtxid, i))
continue;
- isminetype mine = IsMine(pcoin->tx->vout[i]);
+ isminetype mine = IsMine(wtx.tx->vout[i]);
if (mine == ISMINE_NO) {
continue;
}
- bool solvable = IsSolvable(*this, pcoin->tx->vout[i].scriptPubKey);
+ if (!allow_used_addresses && IsUsedDestination(wtxid, i)) {
+ continue;
+ }
+
+ bool solvable = IsSolvable(*this, wtx.tx->vout[i].scriptPubKey);
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
- vCoins.push_back(COutput(pcoin, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly)));
+ vCoins.push_back(COutput(&wtx, i, nDepth, spendable, solvable, safeTx, (coinControl && coinControl->fAllowWatchOnly)));
// Checks the sum amount of all UTXO's.
if (nMinimumSumAmount != MAX_MONEY) {
- nTotal += pcoin->tx->vout[i].nValue;
+ nTotal += wtx.tx->vout[i].nValue;
if (nTotal >= nMinimumSumAmount) {
return;
@@ -2420,7 +2426,6 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector<
std::map<CTxDestination, std::vector<COutput>> CWallet::ListCoins(interfaces::Chain::Lock& locked_chain) const
{
- AssertLockHeld(cs_main);
AssertLockHeld(cs_wallet);
std::map<CTxDestination, std::vector<COutput>> result;
@@ -2562,13 +2567,13 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
if (it != mapWallet.end())
{
- const CWalletTx* pcoin = &it->second;
+ const CWalletTx& wtx = it->second;
// Clearly invalid input, fail
- if (pcoin->tx->vout.size() <= outpoint.n)
+ if (wtx.tx->vout.size() <= outpoint.n)
return false;
// Just to calculate the marginal byte size
- nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue;
- setPresetCoins.insert(CInputCoin(pcoin->tx, outpoint.n));
+ nValueFromPresetInputs += wtx.tx->vout[outpoint.n].nValue;
+ setPresetCoins.insert(CInputCoin(wtx.tx, outpoint.n));
} else
return false; // TODO: Allow non-wallet inputs
}
@@ -2614,9 +2619,9 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
return res;
}
-bool CWallet::SignTransaction(CMutableTransaction &tx)
+bool CWallet::SignTransaction(CMutableTransaction& tx)
{
- AssertLockHeld(cs_wallet); // mapWallet
+ AssertLockHeld(cs_wallet);
// sign the new tx
int nIn = 0;
@@ -2689,16 +2694,21 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
}
}
+ if (nFeeRet > this->m_default_max_tx_fee) {
+ strFailReason = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ return false;
+ }
+
return true;
}
-static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
+static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain)
{
- if (IsInitialBlockDownload()) {
+ if (chain.isInitialBlockDownload()) {
return false;
}
constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds
- if (chainActive.Tip()->GetBlockTime() < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
+ if (locked_chain.getBlockTime(*locked_chain.getHeight()) < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
return false;
}
return true;
@@ -2708,7 +2718,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
* Return a height-based locktime for new transactions (uses the height of the
* current chain tip unless we are not synced with the current chain
*/
-static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
+static uint32_t GetLocktimeForNewTransaction(interfaces::Chain& chain, interfaces::Chain::Lock& locked_chain)
{
uint32_t const height = locked_chain.getHeight().get_value_or(-1);
uint32_t locktime;
@@ -2732,7 +2742,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// enough, that fee sniping isn't a problem yet, but by implementing a fix
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
- if (IsCurrentForAntiFeeSniping(locked_chain)) {
+ if (IsCurrentForAntiFeeSniping(chain, locked_chain)) {
locktime = height;
// Secondly occasionally randomly pick a nLockTime even further back, so
@@ -2806,7 +2816,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
CMutableTransaction txNew;
- txNew.nLockTime = GetLocktimeForNewTransaction(locked_chain);
+ txNew.nLockTime = GetLocktimeForNewTransaction(chain(), locked_chain);
FeeCalculation feeCalc;
CAmount nFeeNeeded;
@@ -2817,7 +2827,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
LOCK(cs_wallet);
{
std::vector<COutput> vAvailableCoins;
- AvailableCoins(*locked_chain, vAvailableCoins, true, &coin_control);
+ AvailableCoins(*locked_chain, vAvailableCoins, true, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0, coin_control.m_min_depth);
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
// Create change script that will be used if we need change
@@ -2902,7 +2912,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
// Include the fee cost for outputs. Note this is only used for BnB right now
coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION);
- if (IsDust(txout, ::dustRelayFee))
+ if (IsDust(txout, chain().relayDustFee()))
{
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{
@@ -3003,7 +3013,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
- if (nFeeNeeded < ::minRelayTxFee.GetFee(nBytes))
+ if (nFeeNeeded < chain().relayMinFee().GetFee(nBytes))
{
strFailReason = _("Transaction too large for fee policy");
return false;
@@ -3197,7 +3207,6 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{
- auto locked_chain = chain().lock();
LOCK(cs_wallet);
fFirstRunRet = false;
@@ -3230,8 +3239,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
- AssertLockHeld(cs_wallet); // mapWallet
- DBErrors nZapSelectTxRet = WalletBatch(*database,"cr+").ZapSelectTx(vHashIn, vHashOut);
+ AssertLockHeld(cs_wallet);
+ DBErrors nZapSelectTxRet = WalletBatch(*database, "cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut) {
const auto& it = mapWallet.find(hash);
wtxOrdered.erase(it->second.m_it_wtxOrdered);
@@ -3257,7 +3266,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
MarkDirty();
return DBErrors::LOAD_OK;
-
}
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
@@ -3283,8 +3291,7 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
return DBErrors::LOAD_OK;
}
-
-bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
+bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
{
bool fUpdated = false;
{
@@ -3297,9 +3304,15 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
}
NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != ISMINE_NO,
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
- if (!strPurpose.empty() && !WalletBatch(*database).WritePurpose(EncodeDestination(address), strPurpose))
+ if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
return false;
- return WalletBatch(*database).WriteName(EncodeDestination(address), strName);
+ return batch.WriteName(EncodeDestination(address), strName);
+}
+
+bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
+{
+ WalletBatch batch(*database);
+ return SetAddressBookWithDB(batch, address, strName, strPurpose);
}
bool CWallet::DelAddressBook(const CTxDestination& address)
@@ -3377,7 +3390,7 @@ bool CWallet::NewKeyPool()
size_t CWallet::KeypoolCountExternalKeys()
{
- AssertLockHeld(cs_wallet); // setExternalKeyPool
+ AssertLockHeld(cs_wallet);
return setExternalKeyPool.size() + set_pre_split_keypool.size();
}
@@ -3449,13 +3462,6 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
return true;
}
-void CWallet::AddKeypoolPubkey(const CPubKey& pubkey, const bool internal)
-{
- WalletBatch batch(*database);
- AddKeypoolPubkeyWithDB(pubkey, internal, batch);
- NotifyCanGetAddressesChanged();
-}
-
void CWallet::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch)
{
LOCK(cs_wallet);
@@ -3607,27 +3613,27 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances(interfaces::Chain:
LOCK(cs_wallet);
for (const auto& walletEntry : mapWallet)
{
- const CWalletTx *pcoin = &walletEntry.second;
+ const CWalletTx& wtx = walletEntry.second;
- if (!pcoin->IsTrusted(locked_chain))
+ if (!wtx.IsTrusted(locked_chain))
continue;
- if (pcoin->IsImmatureCoinBase(locked_chain))
+ if (wtx.IsImmatureCoinBase(locked_chain))
continue;
- int nDepth = pcoin->GetDepthInMainChain(locked_chain);
- if (nDepth < (pcoin->IsFromMe(ISMINE_ALL) ? 0 : 1))
+ int nDepth = wtx.GetDepthInMainChain(locked_chain);
+ if (nDepth < (wtx.IsFromMe(ISMINE_ALL) ? 0 : 1))
continue;
- for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++)
+ for (unsigned int i = 0; i < wtx.tx->vout.size(); i++)
{
CTxDestination addr;
- if (!IsMine(pcoin->tx->vout[i]))
+ if (!IsMine(wtx.tx->vout[i]))
continue;
- if(!ExtractDestination(pcoin->tx->vout[i].scriptPubKey, addr))
+ if(!ExtractDestination(wtx.tx->vout[i].scriptPubKey, addr))
continue;
- CAmount n = IsSpent(locked_chain, walletEntry.first, i) ? 0 : pcoin->tx->vout[i].nValue;
+ CAmount n = IsSpent(locked_chain, walletEntry.first, i) ? 0 : wtx.tx->vout[i].nValue;
if (!balances.count(addr))
balances[addr] = 0;
@@ -3641,19 +3647,19 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances(interfaces::Chain:
std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
{
- AssertLockHeld(cs_wallet); // mapWallet
+ AssertLockHeld(cs_wallet);
std::set< std::set<CTxDestination> > groupings;
std::set<CTxDestination> grouping;
for (const auto& walletEntry : mapWallet)
{
- const CWalletTx *pcoin = &walletEntry.second;
+ const CWalletTx& wtx = walletEntry.second;
- if (pcoin->tx->vin.size() > 0)
+ if (wtx.tx->vin.size() > 0)
{
bool any_mine = false;
// group all input addresses with each other
- for (const CTxIn& txin : pcoin->tx->vin)
+ for (const CTxIn& txin : wtx.tx->vin)
{
CTxDestination address;
if(!IsMine(txin)) /* If this input isn't mine, ignore it */
@@ -3667,7 +3673,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
// group change with input addresses
if (any_mine)
{
- for (const CTxOut& txout : pcoin->tx->vout)
+ for (const CTxOut& txout : wtx.tx->vout)
if (IsChange(txout))
{
CTxDestination txoutAddr;
@@ -3684,7 +3690,7 @@ std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings()
}
// group lone addrs by themselves
- for (const auto& txout : pcoin->tx->vout)
+ for (const auto& txout : wtx.tx->vout)
if (IsMine(txout))
{
CTxDestination address;
@@ -3809,25 +3815,25 @@ void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id)
void CWallet::LockCoin(const COutPoint& output)
{
- AssertLockHeld(cs_wallet); // setLockedCoins
+ AssertLockHeld(cs_wallet);
setLockedCoins.insert(output);
}
void CWallet::UnlockCoin(const COutPoint& output)
{
- AssertLockHeld(cs_wallet); // setLockedCoins
+ AssertLockHeld(cs_wallet);
setLockedCoins.erase(output);
}
void CWallet::UnlockAllCoins()
{
- AssertLockHeld(cs_wallet); // setLockedCoins
+ AssertLockHeld(cs_wallet);
setLockedCoins.clear();
}
bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
{
- AssertLockHeld(cs_wallet); // setLockedCoins
+ AssertLockHeld(cs_wallet);
COutPoint outpt(hash, n);
return (setLockedCoins.count(outpt) > 0);
@@ -3835,7 +3841,7 @@ bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
{
- AssertLockHeld(cs_wallet); // setLockedCoins
+ AssertLockHeld(cs_wallet);
for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
it != setLockedCoins.end(); it++) {
COutPoint outpt = (*it);
@@ -3845,8 +3851,8 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) const
/** @} */ // end of Actions
-void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t> &mapKeyBirth) const {
- AssertLockHeld(cs_wallet); // mapKeyMetadata
+void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CKeyID, int64_t>& mapKeyBirth) const {
+ AssertLockHeld(cs_wallet);
mapKeyBirth.clear();
// get birth times for keys with metadata
@@ -4062,7 +4068,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
if (salvage_wallet) {
// Recover readable keypairs:
- CWallet dummyWallet(chain, WalletLocation(), WalletDatabase::CreateDummy());
+ CWallet dummyWallet(&chain, WalletLocation(), WalletDatabase::CreateDummy());
std::string backup_filename;
if (!WalletBatch::Recover(wallet_path, (void *)&dummyWallet, WalletBatch::RecoverKeysOnlyFilter, backup_filename)) {
return false;
@@ -4074,7 +4080,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, uint64_t wallet_creation_flags)
{
- const std::string& walletFile = location.GetName();
+ const std::string& walletFile = WalletDataFilePath(location.GetPath()).string();
// needed to restore wallet transaction meta data after -zapwallettxes
std::vector<CWalletTx> vWtx;
@@ -4082,7 +4088,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.GetBoolArg("-zapwallettxes", false)) {
chain.initMessage(_("Zapping all transactions from wallet..."));
- std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(chain, location, WalletDatabase::Create(location.GetPath()));
+ std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, WalletDatabase::Create(location.GetPath()));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DBErrors::LOAD_OK) {
chain.initError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile));
@@ -4096,7 +4102,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
bool fFirstRun = true;
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
- std::shared_ptr<CWallet> walletInstance(new CWallet(chain, location, WalletDatabase::Create(location.GetPath())), ReleaseWallet);
+ std::shared_ptr<CWallet> walletInstance(new CWallet(&chain, location, WalletDatabase::Create(location.GetPath())), ReleaseWallet);
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK)
{
@@ -4125,7 +4131,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
}
- int prev_version = walletInstance->nWalletVersion;
+ int prev_version = walletInstance->GetVersion();
if (gArgs.GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = gArgs.GetArg("-upgradewallet", 0);
@@ -4150,8 +4156,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
LOCK(walletInstance->cs_wallet);
// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
- int max_version = walletInstance->nWalletVersion;
- if (!walletInstance->CanSupportFeature(FEATURE_HD_SPLIT) && max_version >=FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
+ int max_version = walletInstance->GetVersion();
+ if (!walletInstance->CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
chain.initError(_("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified."));
return nullptr;
}
@@ -4191,16 +4197,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
walletInstance->SetMinVersion(FEATURE_LATEST);
- if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- //selective allow to set flags
- walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
- } else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) {
- walletInstance->SetWalletFlag(WALLET_FLAG_BLANK_WALLET);
- } else {
+ walletInstance->SetWalletFlags(wallet_creation_flags, false);
+ if (!(wallet_creation_flags & (WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET))) {
// generate a new seed
CPubKey seed = walletInstance->GenerateNewSeed();
walletInstance->SetHDSeed(seed);
- } // Otherwise, do not generate a new seed
+ }
// Top up the keypool
if (walletInstance->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) {
@@ -4208,7 +4210,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
return nullptr;
}
- auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup
+ auto locked_chain = chain.lock();
walletInstance->ChainStateFlushed(locked_chain->getTipLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
@@ -4281,12 +4283,35 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
_("This is the transaction fee you will pay if you send a transaction."));
}
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
- if (walletInstance->m_pay_tx_fee < ::minRelayTxFee) {
+ if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
chain.initError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
- gArgs.GetArg("-paytxfee", ""), ::minRelayTxFee.ToString()));
+ gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString()));
+ return nullptr;
+ }
+ }
+
+ if (gArgs.IsArgSet("-maxtxfee"))
+ {
+ CAmount nMaxFee = 0;
+ if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) {
+ chain.initError(AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")));
return nullptr;
}
+ if (nMaxFee > HIGH_MAX_TX_FEE) {
+ chain.initWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
+ }
+ if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) {
+ chain.initError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
+ gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString()));
+ return nullptr;
+ }
+ walletInstance->m_default_max_tx_fee = nMaxFee;
}
+
+ if (chain.relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB)
+ chain.initWarning(AmountHighWarn("-minrelaytxfee") + " " +
+ _("The wallet will avoid paying less than the minimum relay fee."));
+
walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
walletInstance->m_spend_zero_conf_change = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
walletInstance->m_signal_rbf = gArgs.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
@@ -4320,10 +4345,13 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (tip_height && *tip_height != rescan_height)
{
- //We can't rescan beyond non-pruned blocks, stop and throw an error
- //this might happen if a user uses an old wallet within a pruned node
- // or if he ran -disablewallet for a longer time, then decided to re-enable
- if (chain.getPruneMode()) {
+ // We can't rescan beyond non-pruned blocks, stop and throw an error.
+ // This might happen if a user uses an old wallet within a pruned node
+ // or if they ran -disablewallet for a longer time, then decided to re-enable
+ if (chain.havePruned()) {
+ // Exit early and print an error.
+ // If a block is pruned after this check, we will load the wallet,
+ // but fail the rescan with a generic error.
int block_height = *tip_height;
while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
--block_height;
@@ -4341,12 +4369,11 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
if (walletInstance->nTimeFirstKey) {
- if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height)) {
+ if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height, nullptr)) {
rescan_height = *first_block;
}
}
- nStart = GetTimeMillis();
{
WalletRescanReserver reserver(walletInstance.get());
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} /* stop block */, reserver, true /* update */).status)) {
@@ -4354,7 +4381,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
return nullptr;
}
}
- walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
walletInstance->ChainStateFlushed(locked_chain->getTipLocator());
walletInstance->database->IncrementUpdateCounter();
@@ -4385,8 +4411,8 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
chain.loadWallet(interfaces::MakeWallet(walletInstance));
- // Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main.
- RegisterValidationInterface(walletInstance.get());
+ // Register with the validation interface. It's ok to do this after rescan since we're still holding locked_chain.
+ walletInstance->handleNotifications();
walletInstance->SetBroadcastTransactions(gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST));
@@ -4399,11 +4425,22 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
return walletInstance;
}
+void CWallet::handleNotifications()
+{
+ m_chain_notifications_handler = m_chain->handleNotifications(*this);
+}
+
void CWallet::postInitProcess()
{
+ auto locked_chain = chain().lock();
+ LOCK(cs_wallet);
+
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
- ReacceptWalletTransactions();
+ ReacceptWalletTransactions(*locked_chain);
+
+ // Update wallet transactions with current mempool transactions.
+ chain().requestMempoolTransactions(*this);
}
bool CWallet::BackupWallet(const std::string& strDest)
@@ -4446,8 +4483,6 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
if (hashUnset())
return 0;
- AssertLockHeld(cs_main);
-
return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
}
@@ -4473,7 +4508,7 @@ bool CWalletTx::AcceptToMemoryPool(interfaces::Chain::Lock& locked_chain, CValid
// user could call sendmoney in a loop and hit spurious out of funds errors
// because we think that this newly generated transaction's change is
// unavailable as we're not yet aware that it is in the mempool.
- bool ret = locked_chain.submitToMemoryPool(tx, pwallet->chain().maxTxFee(), state);
+ bool ret = locked_chain.submitToMemoryPool(tx, pwallet->m_default_max_tx_fee, state);
fInMempool |= ret;
return ret;
}
@@ -4544,12 +4579,12 @@ bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const
return true;
}
-bool CWallet::AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info)
+bool CWallet::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info)
{
LOCK(cs_wallet);
std::copy(info.fingerprint, info.fingerprint + 4, mapKeyMetadata[pubkey.GetID()].key_origin.fingerprint);
mapKeyMetadata[pubkey.GetID()].key_origin.path = info.path;
mapKeyMetadata[pubkey.GetID()].has_key_origin = true;
mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path);
- return WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
+ return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 51e3edac34..7b5465c219 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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.
@@ -8,18 +8,19 @@
#include <amount.h>
#include <interfaces/chain.h>
+#include <interfaces/handler.h>
#include <outputtype.h>
#include <policy/feerate.h>
+#include <script/sign.h>
#include <streams.h>
#include <tinyformat.h>
#include <ui_interface.h>
#include <util/strencodings.h>
-#include <validationinterface.h>
-#include <script/ismine.h>
-#include <script/sign.h>
#include <util/system.h>
-#include <wallet/crypter.h>
+#include <validationinterface.h>
#include <wallet/coinselection.h>
+#include <wallet/crypter.h>
+#include <wallet/ismine.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
@@ -34,26 +35,6 @@
#include <utility>
#include <vector>
-//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
-//! This function will perform salvage on the wallet if requested, as long as only one wallet is
-//! being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
-bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
-
-//! Load wallet databases.
-bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files);
-
-//! Complete startup of wallets.
-void StartWallets(CScheduler& scheduler);
-
-//! Flush all wallets in preparation for shutdown.
-void FlushWallets();
-
-//! Stop all wallets. Wallets will be flushed first.
-void StopWallets();
-
-//! Close all wallets.
-void UnloadWallets();
-
//! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all
//! wallet clients release the wallet.
@@ -92,6 +73,12 @@ static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
static const bool DEFAULT_WALLET_RBF = false;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
+//! -maxtxfee default
+constexpr CAmount DEFAULT_TRANSACTION_MAXFEE{COIN / 10};
+//! Discourage users to set fees higher than this amount (in satoshis) per kB
+constexpr CAmount HIGH_TX_FEE_PER_KB{COIN / 100};
+//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
+constexpr CAmount HIGH_MAX_TX_FEE{100 * HIGH_TX_FEE_PER_KB};
//! Pre-calculated constants for input size estimation in *virtual size*
static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;
@@ -133,6 +120,10 @@ enum WalletFlags : uint64_t {
// wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown
// unknown wallet flags in the lower section <= (1 << 31) will be tolerated
+ // will categorize coins as clean (not reused) and dirty (reused), and handle
+ // them with privacy considerations in mind
+ WALLET_FLAG_AVOID_REUSE = (1ULL << 0),
+
// Indicates that the metadata has already been upgraded to contain key origins
WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
@@ -152,16 +143,79 @@ enum WalletFlags : uint64_t {
WALLET_FLAG_BLANK_WALLET = (1ULL << 33),
};
-static constexpr uint64_t g_known_wallet_flags = WALLET_FLAG_DISABLE_PRIVATE_KEYS | WALLET_FLAG_BLANK_WALLET | WALLET_FLAG_KEY_ORIGIN_METADATA;
+static constexpr uint64_t KNOWN_WALLET_FLAGS =
+ WALLET_FLAG_AVOID_REUSE
+ | WALLET_FLAG_BLANK_WALLET
+ | WALLET_FLAG_KEY_ORIGIN_METADATA
+ | WALLET_FLAG_DISABLE_PRIVATE_KEYS;
+
+static constexpr uint64_t MUTABLE_WALLET_FLAGS =
+ WALLET_FLAG_AVOID_REUSE;
+
+static const std::map<std::string,WalletFlags> WALLET_FLAG_MAP{
+ {"avoid_reuse", WALLET_FLAG_AVOID_REUSE},
+ {"blank", WALLET_FLAG_BLANK_WALLET},
+ {"key_origin_metadata", WALLET_FLAG_KEY_ORIGIN_METADATA},
+ {"disable_private_keys", WALLET_FLAG_DISABLE_PRIVATE_KEYS},
+};
-/** A key pool entry */
+extern const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS;
+
+/** A key from a CWallet's keypool
+ *
+ * The wallet holds one (for pre HD-split wallets) or several keypools. These
+ * are sets of keys that have not yet been used to provide addresses or receive
+ * change.
+ *
+ * The Bitcoin Core wallet was originally a collection of unrelated private
+ * keys with their associated addresses. If a non-HD wallet generated a
+ * key/address, gave that address out and then restored a backup from before
+ * that key's generation, then any funds sent to that address would be
+ * lost definitively.
+ *
+ * The keypool was implemented to avoid this scenario (commit: 10384941). The
+ * wallet would generate a set of keys (100 by default). When a new public key
+ * was required, either to give out as an address or to use in a change output,
+ * it would be drawn from the keypool. The keypool would then be topped up to
+ * maintain 100 keys. This ensured that as long as the wallet hadn't used more
+ * than 100 keys since the previous backup, all funds would be safe, since a
+ * restored wallet would be able to scan for all owned addresses.
+ *
+ * A keypool also allowed encrypted wallets to give out addresses without
+ * having to be decrypted to generate a new private key.
+ *
+ * With the introduction of HD wallets (commit: f1902510), the keypool
+ * essentially became an address look-ahead pool. Restoring old backups can no
+ * longer definitively lose funds as long as the addresses used were from the
+ * wallet's HD seed (since all private keys can be rederived from the seed).
+ * However, if many addresses were used since the backup, then the wallet may
+ * not know how far ahead in the HD chain to look for its addresses. The
+ * keypool is used to implement a 'gap limit'. The keypool maintains a set of
+ * keys (by default 1000) ahead of the last used key and scans for the
+ * addresses of those keys. This avoids the risk of not seeing transactions
+ * involving the wallet's addresses, or of re-using the same address.
+ *
+ * The HD-split wallet feature added a second keypool (commit: 02592f4c). There
+ * is an external keypool (for addresses to hand out) and an internal keypool
+ * (for change addresses).
+ *
+ * Keypool keys are stored in the wallet/keystore's keymap. The keypool data is
+ * stored as sets of indexes in the wallet (setInternalKeyPool,
+ * setExternalKeyPool and set_pre_split_keypool), and a map from the key to the
+ * index (m_pool_key_to_index). The CKeyPool object is used to
+ * serialize/deserialize the pool data to/from the database.
+ */
class CKeyPool
{
public:
+ //! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB
int64_t nTime;
+ //! The public key
CPubKey vchPubKey;
- bool fInternal; // for change outputs
- bool m_pre_split; // For keys generated before keypool split upgrade
+ //! Whether this keypool entry is in the internal keypool (for change outputs)
+ bool fInternal;
+ //! Whether this key was generated for a keypool before the wallet was upgraded to HD-split
+ bool m_pre_split;
CKeyPool();
CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn);
@@ -200,6 +254,57 @@ public:
}
};
+/** A wrapper to reserve a key from a wallet keypool
+ *
+ * CReserveKey is used to reserve a key from the keypool. It is passed around
+ * during the CreateTransaction/CommitTransaction procedure.
+ *
+ * Instantiating a CReserveKey does not reserve a keypool key. To do so,
+ * GetReservedKey() needs to be called on the object. Once a key has been
+ * reserved, call KeepKey() on the CReserveKey object to make sure it is not
+ * returned to the keypool. Call ReturnKey() to return the key to the keypool
+ * so it can be re-used (for example, if the key was used in a new transaction
+ * and that transaction was not completed and needed to be aborted).
+ *
+ * If a key is reserved and KeepKey() is not called, then the key will be
+ * returned to the keypool when the CReserveObject goes out of scope.
+ */
+class CReserveKey
+{
+protected:
+ //! The wallet to reserve the keypool key from
+ CWallet* pwallet;
+ //! The index of the key in the keypool
+ int64_t nIndex{-1};
+ //! The public key
+ CPubKey vchPubKey;
+ //! Whether this is from the internal (change output) keypool
+ bool fInternal{false};
+
+public:
+ //! Construct a CReserveKey object. This does NOT reserve a key from the keypool yet
+ explicit CReserveKey(CWallet* pwalletIn)
+ {
+ pwallet = pwalletIn;
+ }
+
+ CReserveKey(const CReserveKey&) = delete;
+ CReserveKey& operator=(const CReserveKey&) = delete;
+
+ //! Destructor. If a key has been reserved and not KeepKey'ed, it will be returned to the keypool
+ ~CReserveKey()
+ {
+ ReturnKey();
+ }
+
+ //! Reserve a key from the keypool
+ bool GetReservedKey(CPubKey &pubkey, bool internal = false);
+ //! Return a key to the keypool
+ void ReturnKey();
+ //! Keep the key. Do not return it to the keypool when this object goes out of scope
+ void KeepKey();
+};
+
/** Address book data */
class CAddressBookData
{
@@ -388,24 +493,11 @@ public:
std::multimap<int64_t, CWalletTx*>::const_iterator m_it_wtxOrdered;
// memory only
- mutable bool fDebitCached;
- mutable bool fCreditCached;
- mutable bool fImmatureCreditCached;
- mutable bool fAvailableCreditCached;
- mutable bool fWatchDebitCached;
- mutable bool fWatchCreditCached;
- mutable bool fImmatureWatchCreditCached;
- mutable bool fAvailableWatchCreditCached;
+ enum AmountType { DEBIT, CREDIT, IMMATURE_CREDIT, AVAILABLE_CREDIT, AMOUNTTYPE_ENUM_ELEMENTS };
+ CAmount GetCachableAmount(AmountType type, const isminefilter& filter, bool recalculate = false) const;
+ mutable CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS];
mutable bool fChangeCached;
mutable bool fInMempool;
- mutable CAmount nDebitCached;
- mutable CAmount nCreditCached;
- mutable CAmount nImmatureCreditCached;
- mutable CAmount nAvailableCreditCached;
- mutable CAmount nWatchDebitCached;
- mutable CAmount nWatchCreditCached;
- mutable CAmount nImmatureWatchCreditCached;
- mutable CAmount nAvailableWatchCreditCached;
mutable CAmount nChangeCached;
CWalletTx(const CWallet* pwalletIn, CTransactionRef arg) : CMerkleTx(std::move(arg))
@@ -422,24 +514,8 @@ public:
nTimeReceived = 0;
nTimeSmart = 0;
fFromMe = false;
- fDebitCached = false;
- fCreditCached = false;
- fImmatureCreditCached = false;
- fAvailableCreditCached = false;
- fWatchDebitCached = false;
- fWatchCreditCached = false;
- fImmatureWatchCreditCached = false;
- fAvailableWatchCreditCached = false;
fChangeCached = false;
fInMempool = false;
- nDebitCached = 0;
- nCreditCached = 0;
- nImmatureCreditCached = 0;
- nAvailableCreditCached = 0;
- nWatchDebitCached = 0;
- nWatchCreditCached = 0;
- nAvailableWatchCreditCached = 0;
- nImmatureWatchCreditCached = 0;
nChangeCached = 0;
nOrderPos = -1;
}
@@ -483,14 +559,10 @@ public:
//! make sure balances are recalculated
void MarkDirty()
{
- fCreditCached = false;
- fAvailableCreditCached = false;
- fImmatureCreditCached = false;
- fWatchDebitCached = false;
- fWatchCreditCached = false;
- fAvailableWatchCreditCached = false;
- fImmatureWatchCreditCached = false;
- fDebitCached = false;
+ m_amounts[DEBIT].Reset();
+ m_amounts[CREDIT].Reset();
+ m_amounts[IMMATURE_CREDIT].Reset();
+ m_amounts[AVAILABLE_CREDIT].Reset();
fChangeCached = false;
}
@@ -505,7 +577,7 @@ public:
CAmount GetCredit(interfaces::Chain::Lock& locked_chain, const isminefilter& filter) const;
CAmount GetImmatureCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true) const;
// TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct
- // annotation "EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet)". The
+ // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The
// annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid
// having to resolve the issue of member access into incomplete type CWallet.
CAmount GetAvailableCredit(interfaces::Chain::Lock& locked_chain, bool fUseCache=true, const isminefilter& filter=ISMINE_SPENDABLE) const NO_THREAD_SAFETY_ANALYSIS;
@@ -534,7 +606,7 @@ public:
int64_t GetTxTime() const;
- // RelayWalletTransaction may only be called if fBroadcastTransactions!
+ // Pass this transaction to the node to relay to its peers
bool RelayWalletTransaction(interfaces::Chain::Lock& locked_chain);
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
@@ -637,18 +709,20 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
-class CWallet final : public CCryptoKeyStore, public CValidationInterface
+class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications
{
private:
std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
+ std::atomic<int64_t> m_scanning_start{0};
+ std::atomic<double> m_scanning_progress{0};
std::mutex mutexScanning;
friend class WalletRescanReserver;
WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr;
//! the current wallet version: clients below this version are not able to load the wallet
- int nWalletVersion = FEATURE_BASE;
+ int nWalletVersion GUARDED_BY(cs_wallet){FEATURE_BASE};
//! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded
int nWalletMaxVersion GUARDED_BY(cs_wallet) = FEATURE_BASE;
@@ -656,6 +730,8 @@ private:
int64_t nNextResend = 0;
int64_t nLastResend = 0;
bool fBroadcastTransactions = false;
+ // Local time that the tip block was received. Used to schedule wallet rebroadcasts.
+ std::atomic<int64_t> m_best_block_time {0};
/**
* Used to keep track of spent outpoints, and
@@ -698,11 +774,11 @@ private:
CHDChain hdChain;
/* HD derive new child key (on internal or external chain) */
- void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void DeriveNewChildKey(WalletBatch& batch, CKeyMetadata& metadata, CKey& secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- std::set<int64_t> setInternalKeyPool;
+ std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_wallet);
std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_wallet);
- std::set<int64_t> set_pre_split_keypool;
+ std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_wallet);
int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0;
std::map<CKeyID, int64_t> m_pool_key_to_index;
std::atomic<uint64_t> m_wallet_flags{0};
@@ -719,9 +795,29 @@ private:
* nTimeFirstKey more intelligently for more efficient rescans.
*/
bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ /** Add a KeyOriginInfo to the wallet */
+ bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info);
+
+ //! Adds a key to the store, and saves it to disk.
+ bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ //! Adds a watch-only address to the store, and saves it to disk.
+ bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
+
+ bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose);
+
+ //! Adds a script to the store and saves it to disk
+ bool AddCScriptWithDB(WalletBatch& batch, const CScript& script);
+
+ //! Unsets a wallet flag and saves it to disk
+ void UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag);
/** Interface for accessing chain state. */
- interfaces::Chain& m_chain;
+ interfaces::Chain* m_chain;
/** Wallet location which includes wallet name (see WalletLocation). */
WalletLocation m_location;
@@ -737,7 +833,7 @@ private:
* to have seen all transactions in the chain, but is only used to track
* live BlockConnected callbacks.
*/
- uint256 m_last_block_processed;
+ uint256 m_last_block_processed GUARDED_BY(cs_wallet);
public:
/*
@@ -777,14 +873,15 @@ public:
// Map from Script ID to key metadata (for watch-only keys).
std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_wallet);
- bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, bool overwrite);
-
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID = 0;
/** Construct wallet with specified name and database implementation. */
- CWallet(interfaces::Chain& chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database) : m_chain(chain), m_location(location), database(std::move(database))
+ CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr<WalletDatabase> database)
+ : m_chain(chain),
+ m_location(location),
+ database(std::move(database))
{
}
@@ -808,8 +905,14 @@ public:
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
+ /** Registered interfaces::Chain::Notifications handler. */
+ std::unique_ptr<interfaces::Handler> m_chain_notifications_handler;
+
+ /** Register the wallet for chain notifications */
+ void handleNotifications();
+
/** Interface for accessing chain state. */
- interfaces::Chain& chain() const { return m_chain; }
+ interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }
const CWalletTx* GetWalletTx(const uint256& hash) const;
@@ -841,6 +944,12 @@ public:
std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params, bool& bnb_used) const;
bool IsSpent(interfaces::Chain::Lock& locked_chain, const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
+ // Whether this or any UTXO with the same CTxDestination has been spent.
+ bool IsUsedDestination(const CTxDestination& dst) const;
+ bool IsUsedDestination(const uint256& hash, unsigned int n) const;
+ void SetUsedDestinationState(const uint256& hash, unsigned int n, bool used);
+
std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -855,6 +964,8 @@ public:
void AbortRescan() { fAbortRescan = true; }
bool IsAbortingRescan() { return fAbortRescan; }
bool IsScanning() { return fScanningWallet; }
+ int64_t ScanningDuration() const { return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0; }
+ double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
/**
* keystore implementation
@@ -863,7 +974,6 @@ public:
CPubKey GenerateNewKey(WalletBatch& batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- bool AddKeyPubKeyWithDB(WalletBatch &batch,const CKey& key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet)
@@ -906,7 +1016,7 @@ public:
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
- void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CTxDestination, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<CKeyID, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
/**
@@ -920,8 +1030,9 @@ public:
bool AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose=true);
void LoadToWallet(const CWalletTx& wtxIn) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void TransactionAddedToMempool(const CTransactionRef& tx) override;
- void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex *pindex, const std::vector<CTransactionRef>& vtxConflicted) override;
- void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
+ void BlockConnected(const CBlock& block, const std::vector<CTransactionRef>& vtxConflicted) override;
+ void BlockDisconnected(const CBlock& block) override;
+ void UpdatedBlockTip() override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
struct ScanResult {
@@ -941,16 +1052,17 @@ public:
};
ScanResult ScanForWalletTransactions(const uint256& first_block, const uint256& last_block, const WalletRescanReserver& reserver, bool fUpdate);
void TransactionRemovedFromMempool(const CTransactionRef &ptx) override;
- void ReacceptWalletTransactions();
- void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- // ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!
- std::vector<uint256> ResendWalletTransactionsBefore(interfaces::Chain::Lock& locked_chain, int64_t nTime);
- CAmount GetBalance(const isminefilter& filter=ISMINE_SPENDABLE, const int min_depth=0) const;
- CAmount GetUnconfirmedBalance() const;
- CAmount GetImmatureBalance() const;
- CAmount GetUnconfirmedWatchOnlyBalance() const;
- CAmount GetImmatureWatchOnlyBalance() const;
- CAmount GetLegacyBalance(const isminefilter& filter, int minDepth) const;
+ void ReacceptWalletTransactions(interfaces::Chain::Lock& locked_chain) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ void ResendWalletTransactions();
+ struct Balance {
+ CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more
+ CAmount m_mine_untrusted_pending{0}; //!< Untrusted, but in mempool (pending)
+ CAmount m_mine_immature{0}; //!< Immature coinbases in the main chain
+ CAmount m_watchonly_trusted{0};
+ CAmount m_watchonly_untrusted_pending{0};
+ CAmount m_watchonly_immature{0};
+ };
+ Balance GetBalance(int min_depth = 0, bool avoid_reuse = true) const;
CAmount GetAvailableBalance(const CCoinControl* coinControl = nullptr) const;
OutputType TransactionChangeType(OutputType change_type, const std::vector<CRecipient>& vecSend);
@@ -980,6 +1092,11 @@ public:
bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const;
bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig = false) const;
+ bool ImportScripts(const std::set<CScript> scripts) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+
CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
@@ -995,12 +1112,12 @@ public:
CFeeRate m_discard_rate{DEFAULT_DISCARD_FEE};
OutputType m_default_address_type{DEFAULT_ADDRESS_TYPE};
OutputType m_default_change_type{DEFAULT_CHANGE_TYPE};
+ /** Absolute maximum transaction fee (in satoshis) used by default for the wallet */
+ CAmount m_default_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
bool NewKeyPool();
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0);
- void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal);
- void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
/**
* Reserves a key from the keypool and sets nIndex to its index
@@ -1065,7 +1182,7 @@ public:
unsigned int GetKeyPoolSize() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
{
- AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
+ AssertLockHeld(cs_wallet);
return setInternalKeyPool.size() + setExternalKeyPool.size();
}
@@ -1197,7 +1314,7 @@ public:
void UnsetWalletFlag(uint64_t flag);
/** check if a certain wallet flag is set */
- bool IsWalletFlagSet(uint64_t flag);
+ bool IsWalletFlagSet(uint64_t flag) const;
/** overwrite all flags by the given uint64_t
returns false if unknown, non-tolerable flags are present */
@@ -1217,39 +1334,13 @@ public:
/** Implement lookup of key origin information through wallet key metadata. */
bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
-
- /** Add a KeyOriginInfo to the wallet */
- bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info);
};
-/** A key allocated from the key pool. */
-class CReserveKey final : public CReserveScript
-{
-protected:
- CWallet* pwallet;
- int64_t nIndex{-1};
- CPubKey vchPubKey;
- bool fInternal{false};
-
-public:
- explicit CReserveKey(CWallet* pwalletIn)
- {
- pwallet = pwalletIn;
- }
-
- CReserveKey(const CReserveKey&) = delete;
- CReserveKey& operator=(const CReserveKey&) = delete;
-
- ~CReserveKey()
- {
- ReturnKey();
- }
-
- void ReturnKey();
- bool GetReservedKey(CPubKey &pubkey, bool internal = false);
- void KeepKey();
- void KeepScript() override { KeepKey(); }
-};
+/**
+ * Called periodically by the schedule thread. Prompts individual wallets to resend
+ * their transactions. Actual rebroadcast schedule is managed by the wallets themselves.
+ */
+void MaybeResendWalletTxs();
/** RAII object to check and reserve a wallet rescan */
class WalletRescanReserver
@@ -1267,6 +1358,8 @@ public:
if (m_wallet->fScanningWallet) {
return false;
}
+ m_wallet->m_scanning_start = GetTimeMillis();
+ m_wallet->m_scanning_progress = 0;
m_wallet->fScanningWallet = true;
m_could_reserve = true;
return true;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 2783f83fd6..ece97e2a75 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1,11 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-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 <wallet/walletdb.h>
-#include <consensus/tx_verify.h>
+#include <consensus/tx_check.h>
#include <consensus/validation.h>
#include <fs.h>
#include <key_io.h>
@@ -422,8 +422,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
strType != "minversion" && strType != "acentry") {
wss.m_unknown_records++;
}
- } catch (...)
- {
+ } catch (const std::exception& e) {
+ if (strErr.empty()) {
+ strErr = e.what();
+ }
+ return false;
+ } catch (...) {
+ if (strErr.empty()) {
+ strErr = "Caught unknown exception in ReadKeyValue";
+ }
return false;
}
return true;
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index 0532a55ff5..d4a3bba97a 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -143,9 +143,11 @@ public:
};
/** Access to the wallet database.
- * This represents a single transaction at the
- * database. It will be committed when the object goes out of scope.
- * Optionally (on by default) it will flush to disk as well.
+ * Opens the database and provides read and write access to it. Each read and write is its own transaction.
+ * Multiple operation transactions can be started using TxnBegin() and committed using TxnCommit()
+ * Otherwise the transaction will be committed when the object goes out of scope.
+ * Optionally (on by default) it will flush to disk on close.
+ * Every 1000 writes will automatically trigger a flush to disk.
*/
class WalletBatch
{
@@ -157,6 +159,9 @@ private:
return false;
}
m_database.IncrementUpdateCounter();
+ if (m_database.nUpdateCounter % 1000 == 0) {
+ m_batch.Flush();
+ }
return true;
}
@@ -167,6 +172,9 @@ private:
return false;
}
m_database.IncrementUpdateCounter();
+ if (m_database.nUpdateCounter % 1000 == 0) {
+ m_batch.Flush();
+ }
return true;
}
diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp
index 797f051189..0843194511 100644
--- a/src/wallet/wallettool.cpp
+++ b/src/wallet/wallettool.cpp
@@ -1,10 +1,8 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016-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 <base58.h>
#include <fs.h>
-#include <interfaces/chain.h>
#include <util/system.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>
@@ -24,16 +22,15 @@ static void WalletToolReleaseWallet(CWallet* wallet)
static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::path& path)
{
if (fs::exists(path)) {
- fprintf(stderr, "Error: File exists already\n");
+ tfm::format(std::cerr, "Error: File exists already\n");
return nullptr;
}
// dummy chain interface
- auto chain = interfaces::MakeChain();
- std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
+ std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
bool first_run = true;
DBErrors load_wallet_ret = wallet_instance->LoadWallet(first_run);
if (load_wallet_ret != DBErrors::LOAD_OK) {
- fprintf(stderr, "Error creating %s", name.c_str());
+ tfm::format(std::cerr, "Error creating %s", name.c_str());
return nullptr;
}
@@ -43,7 +40,7 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
CPubKey seed = wallet_instance->GenerateNewSeed();
wallet_instance->SetHDSeed(seed);
- fprintf(stdout, "Topping up keypool...\n");
+ tfm::format(std::cout, "Topping up keypool...\n");
wallet_instance->TopUpKeyPool();
return wallet_instance;
}
@@ -51,40 +48,39 @@ static std::shared_ptr<CWallet> CreateWallet(const std::string& name, const fs::
static std::shared_ptr<CWallet> LoadWallet(const std::string& name, const fs::path& path)
{
if (!fs::exists(path)) {
- fprintf(stderr, "Error: Wallet files does not exist\n");
+ tfm::format(std::cerr, "Error: Wallet files does not exist\n");
return nullptr;
}
// dummy chain interface
- auto chain = interfaces::MakeChain();
- std::shared_ptr<CWallet> wallet_instance(new CWallet(*chain, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
+ std::shared_ptr<CWallet> wallet_instance(new CWallet(nullptr /* chain */, WalletLocation(name), WalletDatabase::Create(path)), WalletToolReleaseWallet);
DBErrors load_wallet_ret;
try {
bool first_run;
load_wallet_ret = wallet_instance->LoadWallet(first_run);
- } catch (const std::runtime_error) {
- fprintf(stderr, "Error loading %s. Is wallet being used by another process?\n", name.c_str());
+ } catch (const std::runtime_error&) {
+ tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name.c_str());
return nullptr;
}
if (load_wallet_ret != DBErrors::LOAD_OK) {
wallet_instance = nullptr;
if (load_wallet_ret == DBErrors::CORRUPT) {
- fprintf(stderr, "Error loading %s: Wallet corrupted", name.c_str());
+ tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name.c_str());
return nullptr;
} else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
- fprintf(stderr, "Error reading %s! All keys read correctly, but transaction data"
+ tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
" or address book entries might be missing or incorrect.",
name.c_str());
} else if (load_wallet_ret == DBErrors::TOO_NEW) {
- fprintf(stderr, "Error loading %s: Wallet requires newer version of %s",
+ tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
name.c_str(), PACKAGE_NAME);
return nullptr;
} else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
- fprintf(stderr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
+ tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
return nullptr;
} else {
- fprintf(stderr, "Error loading %s", name.c_str());
+ tfm::format(std::cerr, "Error loading %s", name.c_str());
return nullptr;
}
}
@@ -96,12 +92,12 @@ static void WalletShowInfo(CWallet* wallet_instance)
{
LOCK(wallet_instance->cs_wallet);
- fprintf(stdout, "Wallet info\n===========\n");
- fprintf(stdout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
- fprintf(stdout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes");
- fprintf(stdout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
- fprintf(stdout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
- fprintf(stdout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
+ tfm::format(std::cout, "Wallet info\n===========\n");
+ tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
+ tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->GetHDChain().seed_id.IsNull() ? "no" : "yes");
+ tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
+ tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
+ tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
}
bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
@@ -116,12 +112,12 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
}
} else if (command == "info") {
if (!fs::exists(path)) {
- fprintf(stderr, "Error: no wallet file at %s\n", name.c_str());
+ tfm::format(std::cerr, "Error: no wallet file at %s\n", name.c_str());
return false;
}
std::string error;
if (!WalletBatch::VerifyEnvironment(path, error)) {
- fprintf(stderr, "Error loading %s. Is wallet being used by other process?\n", name.c_str());
+ tfm::format(std::cerr, "Error loading %s. Is wallet being used by other process?\n", name.c_str());
return false;
}
std::shared_ptr<CWallet> wallet_instance = LoadWallet(name, path);
@@ -129,7 +125,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
WalletShowInfo(wallet_instance.get());
wallet_instance->Flush(true);
} else {
- fprintf(stderr, "Invalid command: %s\n", command.c_str());
+ tfm::format(std::cerr, "Invalid command: %s\n", command.c_str());
return false;
}
diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h
index 5b06fd1792..7ee2505631 100644
--- a/src/wallet/wallettool.h
+++ b/src/wallet/wallettool.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2016-2018 The Bitcoin Core developers
+// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLET_WALLETTOOL_H
#define BITCOIN_WALLET_WALLETTOOL_H
-#include <script/ismine.h>
+#include <wallet/ismine.h>
#include <wallet/wallet.h>
namespace WalletTool {
diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp
index d779251d56..04c2407a89 100644
--- a/src/wallet/walletutil.cpp
+++ b/src/wallet/walletutil.cpp
@@ -1,9 +1,10 @@
-// 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.
#include <wallet/walletutil.h>
+#include <logging.h>
#include <util/system.h>
fs::path GetWalletDir()
@@ -30,10 +31,14 @@ fs::path GetWalletDir()
static bool IsBerkeleyBtree(const fs::path& path)
{
+ if (!fs::exists(path)) return false;
+
// A Berkeley DB Btree file has at least 4K.
// This check also prevents opening lock files.
boost::system::error_code ec;
- if (fs::file_size(path, ec) < 4096) return false;
+ auto size = fs::file_size(path, ec);
+ if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), path.string());
+ if (size < 4096) return false;
fsbridge::ifstream file(path, std::ios::binary);
if (!file.is_open()) return false;
@@ -54,8 +59,14 @@ std::vector<fs::path> ListWalletDir()
const fs::path wallet_dir = GetWalletDir();
const size_t offset = wallet_dir.string().size() + 1;
std::vector<fs::path> paths;
+ boost::system::error_code ec;
+
+ for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) {
+ if (ec) {
+ LogPrintf("%s: %s %s\n", __func__, ec.message(), it->path().string());
+ continue;
+ }
- for (auto it = fs::recursive_directory_iterator(wallet_dir); it != fs::recursive_directory_iterator(); ++it) {
// Get wallet path relative to walletdir by removing walletdir from the wallet path.
// This can be replaced by boost::filesystem::lexically_relative once boost is bumped to 1.60.
const fs::path path = it->path().string().substr(offset);
diff --git a/src/warnings.cpp b/src/warnings.cpp
index 1c6ba13f60..5542412a7f 100644
--- a/src/warnings.cpp
+++ b/src/warnings.cpp
@@ -4,14 +4,13 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <sync.h>
-#include <clientversion.h>
#include <util/system.h>
#include <warnings.h>
-CCriticalSection cs_warnings;
-std::string strMiscWarning GUARDED_BY(cs_warnings);
-bool fLargeWorkForkFound GUARDED_BY(cs_warnings) = false;
-bool fLargeWorkInvalidChainFound GUARDED_BY(cs_warnings) = false;
+static RecursiveMutex cs_warnings;
+static std::string strMiscWarning GUARDED_BY(cs_warnings);
+static bool fLargeWorkForkFound GUARDED_BY(cs_warnings) = false;
+static bool fLargeWorkInvalidChainFound GUARDED_BY(cs_warnings) = false;
void SetMiscWarning(const std::string& strWarning)
{
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
index 6a9661e3e8..a5f3be8f5b 100644
--- a/src/zmq/zmqabstractnotifier.cpp
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -3,7 +3,6 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <zmq/zmqabstractnotifier.h>
-#include <util/system.h>
const int CZMQAbstractNotifier::DEFAULT_ZMQ_SNDHWM;
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 6826cf62d6..de59b71b8f 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -7,7 +7,6 @@
#include <version.h>
#include <validation.h>
-#include <streams.h>
#include <util/system.h>
void zmqError(const char *str)
diff --git a/test/README.md b/test/README.md
index 9d4351b1de..ecea3213ab 100644
--- a/test/README.md
+++ b/test/README.md
@@ -13,8 +13,7 @@ bitcoin-tx.
- [lint](/test/lint/) which perform various static analysis checks.
The util tests are run as part of `make check` target. The functional
-tests and lint scripts are run by the travis continuous build process whenever a pull
-request is opened. All sets of tests can also be run locally.
+tests and lint scripts can be run as explained in the sections below.
# Running tests locally
diff --git a/test/config.ini.in b/test/config.ini.in
index 6b7ef70659..060c553da2 100644
--- a/test/config.ini.in
+++ b/test/config.ini.in
@@ -6,6 +6,7 @@
# test/functional/test_runner.py and test/util/bitcoin-util-test.py
[environment]
+PACKAGE_NAME=@PACKAGE_NAME@
SRCDIR=@abs_top_srcdir@
BUILDDIR=@abs_top_builddir@
EXEEXT=@EXEEXT@
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index 5bb3b5c094..45ecaabe14 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -11,6 +11,7 @@ from collections import defaultdict, namedtuple
import heapq
import itertools
import os
+import pathlib
import re
import sys
import tempfile
@@ -51,9 +52,23 @@ def main():
if not args.testdir:
print("Opening latest test directory: {}".format(testdir), file=sys.stderr)
+ colors = defaultdict(lambda: '')
+ if args.color:
+ colors["test"] = "\033[0;36m" # CYAN
+ colors["node0"] = "\033[0;34m" # BLUE
+ colors["node1"] = "\033[0;32m" # GREEN
+ colors["node2"] = "\033[0;31m" # RED
+ colors["node3"] = "\033[0;33m" # YELLOW
+ colors["reset"] = "\033[0m" # Reset font color
+
log_events = read_logs(testdir)
- print_logs(log_events, color=args.color, html=args.html)
+ if args.html:
+ print_logs_html(log_events)
+ else:
+ print_logs_plain(log_events, colors)
+ print_node_warnings(testdir, colors)
+
def read_logs(tmp_dir):
"""Reads log files.
@@ -71,6 +86,26 @@ def read_logs(tmp_dir):
return heapq.merge(*[get_log_events(source, f) for source, f in files])
+def print_node_warnings(tmp_dir, colors):
+ """Print nodes' errors and warnings"""
+
+ warnings = []
+ for stream in ['stdout', 'stderr']:
+ for i in itertools.count():
+ folder = "{}/node{}/{}".format(tmp_dir, i, stream)
+ if not os.path.isdir(folder):
+ break
+ for (_, _, fns) in os.walk(folder):
+ for fn in fns:
+ warning = pathlib.Path('{}/{}'.format(folder, fn)).read_text().strip()
+ if warning:
+ warnings.append(("node{} {}".format(i, stream), warning))
+
+ print()
+ for w in warnings:
+ print("{} {} {} {}".format(colors[w[0].split()[0]], w[0], w[1], colors["reset"]))
+
+
def find_latest_test_dir():
"""Returns the latest tmpfile test directory prefix."""
tmpdir = tempfile.gettempdir()
@@ -127,18 +162,9 @@ def get_log_events(source, logfile):
except FileNotFoundError:
print("File %s could not be opened. Continuing without it." % logfile, file=sys.stderr)
-def print_logs(log_events, color=False, html=False):
- """Renders the iterator of log events into text or html."""
- if not html:
- colors = defaultdict(lambda: '')
- if color:
- colors["test"] = "\033[0;36m" # CYAN
- colors["node0"] = "\033[0;34m" # BLUE
- colors["node1"] = "\033[0;32m" # GREEN
- colors["node2"] = "\033[0;31m" # RED
- colors["node3"] = "\033[0;33m" # YELLOW
- colors["reset"] = "\033[0m" # Reset font color
+def print_logs_plain(log_events, colors):
+ """Renders the iterator of log events into text."""
for event in log_events:
lines = event.event.splitlines()
print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
@@ -146,7 +172,9 @@ def print_logs(log_events, color=False, html=False):
for line in lines[1:]:
print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
- else:
+
+def print_logs_html(log_events):
+ """Renders the iterator of log events into html."""
try:
import jinja2
except ImportError:
diff --git a/test/functional/data/invalid_txs.py b/test/functional/data/invalid_txs.py
index 02deae92f3..454eb583f7 100644
--- a/test/functional/data/invalid_txs.py
+++ b/test/functional/data/invalid_txs.py
@@ -58,7 +58,7 @@ class BadTxTemplate:
class OutputMissing(BadTxTemplate):
reject_reason = "bad-txns-vout-empty"
- expect_disconnect = False
+ expect_disconnect = True
def get_tx(self):
tx = CTransaction()
@@ -69,11 +69,15 @@ class OutputMissing(BadTxTemplate):
class InputMissing(BadTxTemplate):
reject_reason = "bad-txns-vin-empty"
- expect_disconnect = False
+ expect_disconnect = True
+ # We use a blank transaction here to make sure
+ # it is interpreted as a non-witness transaction.
+ # Otherwise the transaction will fail the
+ # "surpufluous witness" check during deserialization
+ # rather than the input count check.
def get_tx(self):
tx = CTransaction()
- tx.vout.append(CTxOut(0, sc.CScript([sc.OP_TRUE] * 100)))
tx.calc_sha256()
return tx
diff --git a/test/functional/data/rpc_getblockstats.json b/test/functional/data/rpc_getblockstats.json
index b8cabe1e5e..16dbc5fe60 100644
--- a/test/functional/data/rpc_getblockstats.json
+++ b/test/functional/data/rpc_getblockstats.json
@@ -1,109 +1,109 @@
{
"blocks": [
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",
- "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f1cd16b94f20a8a3dda91027c888025f2ec1a07ddcb2786bdff5916e66c00406f194ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002014341131c18d3b3aa30056a0f7a97c9ac852d3fd0ec9c76f7a25e83c01e7f821bf83574fb606f25c59200c844443201faf923ef5284fd4401f3104a323c601491a4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03520101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002078616da95299bd42cd8f813c8043816ec5741de466be3162e16bfff471808461f671e694afaf534d37df484f1990fc19a65fc26964b38141b7f8ecf61b8a50241a4ae75affff7f200500000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03530101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020a08613f37d305835a3a1553e77a479eba0f34c06c52e429ece54f5973cd77a7086a1efcaf75f1cd5be2c9deb6a7850225757a2cfc3031a91cc1330b3af4acc891b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03540101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000203b304fa1ce0505c2366982939ac148d9124c5ac747cc9aea133cea9916484966305de0e8d049f2be65c68d64d2c45746def5a9b4fcb8e298692b53b83b4690241b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03550101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020fbdf49978ec4f0b23704b6772a614336872587e29c463f375836ffd775248837fed9f3fdfc33f076c6663ae78070fad7263c1e24161f3ee1a4857b8931815e2c1b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03560101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020c37548b9ca256b9ff17187d4d4309cf3143845b0a5811d3ca5427b2fddf000731a10985dfd473561c070c3527c3fe3941834cf51b3dfbacb501b44c69c9745ce1b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03570101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020383dd3766c0675440f26370ad62d687e335ea3a650dec9b02fe544107cc1823a13b98696d41562945457d655f4c6921f736068f7a72afd1ad6b335f2857d16631c4ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03580101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000207476dd96d81f53e63934ce28c9e89022e0f24d040ec3c838443e925fc3a2f230a94d0cbcefb4a151191dd7664153944d9eee3b7b46d4ba997f397ed2b72c3afe1c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03590101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000209e425c73eea16cce98c0d47d6070aca29f0524eab4b97af84c386aa5322dd43055002f097e929bc6ad88ce869968e1b049aab7f6e45a5b869cf4349afd5d43e01c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000202090e16a514fad40386413a100bbaa4fc14086a8d3501ac64c91fdef922e834a369e409444d0ec496eb0dd9a47f1fe81a7ab974bab28c50a912b994acf13b5f91c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020777b767e42624c52775b331f19e81ba03be2f51a0608166cd5388c1a47d5e776473570bb9bba553a7db4a9a3083533027c54af1fea3ef6ef67757ef2255d64631c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002076bb2bf3251a51ec367a42f8584043171a5d53157394cd776ebd017e2982127653d953aca3e2217f56533c043c07b9a926a30672ebce2562f1d06a6dc5044e7b1c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020e6d7f02292655b73fc1f1958b09633ba07265d71d2a2784060b354cbbf1900202e9c9b02b63170002a94a0c9d8d787e2faa4c074a1ebdeb2855555347321dd101d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020d61f077b0ed326e17f0a3d5af3fa876b72b434a252c9c3248d20130ed744287fcb10da470222dd29c7a07e2da7eb25d6499ed3919676df89cc630bd1b23fbb411d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205efa9741cf51533ed6e07a97c71768372f53ca9c6df83894d64fe94c718eee23a207441e79ecdcf99ef3326385f5f675e2dea84c85ab8973219c63f92847ed5b1d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03600101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020368386b0a0f46b2a2c4648eb9cb5dd1380c4f22e437e0bd49420670993361e5b9026632c2ddbb4b31b3c3118c51e43ea4d78e05c0aca0956278ead26a263d1521d4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401110101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020dd0a1594bbff6345a3e34f326e5ee605c855f5e0a5c363fc39615a8b1539b736200b51297dbee4aadf9b536cd2afe7617651e0a1d0f0610f436518a2a4dc54621d4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401120101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020f302a1092709dc27a32d7229d391b90824a75828692c4bb2ca8f0ca5c88b3613c2e18797ffe8b367336338f90b2cf8c3f66277eb1e1ddbe18c052977294f10691d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401130101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000203dcc77aac703a8cd0e799384b74383c1d5f236426f77d516694607fc88fe85581276a20ceb98d02e6355c9dba4312e2fdc9832f4302cc307e1263f2df0aadd6a1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401140101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020dfe109704a0b2801aee4232c31fb744145a7c80dd91a7727e16d4057719d5c3730f8296243521d82d96ed75c5af800a722fc9dde2e02af95c8c9822190ba07b21e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401150101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000201ef9ef2699bc36fd646bb9ba8629644bc98396122f6753710caf0315d7539f751382d3d85f17eb8b42cf17e54baa327886dcf6fa63207e097df8f9b84cc5422f1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401160101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020834c91f23cd91b727be08b892f1c1a2f33c1e66d66f35607925fa1be4bca2c25b4145a73b1c71b945f5bb9ede3d8d95c9a3b12a0a81b7b14f440ec5146dd4ec71e4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401170101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205743202bf1e543a9be2a59b62be6a5a494511fab96968007b8d7199ea60a524697227ba473ceaf48d4f48ee17f8ee6cd2f1f5ddff03a641642ece240e7872f8f1e4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401180101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000207469f5c1841bf57275d82db23e5a8f0e8512af1eb10119c238519cdd6cdced34fd96dc659a874b3f5d30fbe6ea421a6b9791dfce8450f8851e4b90d80f0f794e1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401190101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020b6338f55fcc473b744d53d675b4a83dcd80ddec9d02ad3323cf1ff50ac0412239d986ec20885d772fdc67803273aaec43871426ac93d3815846a8cd13dea5af11f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020a19d9edf2d22415cf226b4e1416c8a3097e0af222efac2bfeab15fa1f07b3f24c18580c4004de6d6244a30ce431c4be3ca44731509fc6b11710c792efed5e9191f4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000208f9f29a27424ec01ce77485617088506ca8faeef69300f0a474ad63ca5d32972d6049609fa3588d6ffab4d9d89a90636ac94c0ca1995f7768163abeb25dbf2bc1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020fbd87d530a9ec3835ab579337fd16e512cec6c4779ab4d84e7256b3333dece28de1065c8c3d3d166e057139ac59af6f4f2c0d241b6269bbea6f61c5eff3dba431f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020dc6ef4f436baab2d6880f242a2588313a2739ac694e30319344045ee318c9524d0ec7fbcaca30ce85392cb03b64015ece769afb50fd07db05c15ec49abf7d71c1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020386bf4cbb3708ae6345b9f2459bdd99d07422b05f9b005d2d4d1d3bf87d47359ebb22b3a15c8e94ddd8129527873b9bebfa10c54d11196961376efbcaad3c4681f4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020600e892f12ad82a23ce12684d3ffa0887eab5e3e97804fa651050b23366cc55ef2468e65c3d3cf49650657eb47d0b0b7949c71dcc0922eb824523157b7eff478204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401200101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002068e4aec52a3f4e44279e3a65cd476237bdfcc2328390bb31b8a903f89ddfa70e8d669f61b469acb31b1d4ecdc238e6616a83a30644a5d06fc2ca1aad6449d09b204ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401210101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020cf2428ae9a5014b910275807f54a8bbbeec47d462f9d284ada60329b4955ff10cf83c44ddde39a709aef54fb302c7f1cb36db8fe7c3befce20dcc3729767518c204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401220101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205801eef8cca082407ce4798648c4d3ba0fc4dd2d4459eccfe5300c7960760d16cb3dd78a2f22fb88717a175e45c53d34f970b94ef9f7cd1b6c279294d427d163204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401230101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002088320983a4bcb95b9f342994c6943c227f3102d3b16282f048ceb8e15748662a52d1207591a0a364bc9245a76e36530f147ec4d1b4e1917676b4071f542c3b19204ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401240101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020acd85b6d8087d3b6bd2a208a2e39b75da459c0e0eb14088075a23a2e043e8a4ed5a1754491f8180d293b42e6c04ec3f82e29c1f2600dc8607616f69a4a464e6e204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401250101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204873bcb379f78da4497ce1e22f6bfb63537b89c8c522257a7b7bef74e515ed1b6b235faab048fa73a76c68fdbdde6a4ee7ebe0a3b7b23df24ce75dbd2cf49c33214ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401260101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020a87f6d13bae8e2e07996c3316e8e0da6aec7d1aee6b80aa5883018e4d136db3e9a498ff7d322ad93863e0a5318af7e7d0ed683fd2e4ecf523f2b7369106dbe4a214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401270101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020d9b0618450a51c08f43187c479e20d351f0466464409bb3071dc0af7c51d65498a198cef23dddd2c4b93d9d3288ae922584e221a9ef1ded3dba5a2ad494d9237214ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401280101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020167dff31847b8dcad472bb6bb7d0af53b245f0f1d4c9f83d4ce14a0f05d42d7f0f2638ffc0e6896230f28df1865ef133dccb1f027545c6a1177dffd1fecf8a01214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401290101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000208236c04424573692504e777e179b9247e54622b118239311413812f13cefbf6e39a639143f599dc76208b2014de12a364716df2918af9186453e3676dca743d7214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020fab7b55aeb59f63315dbc10784c55e55635a7600cc4f3b94a00003007e7fc90b4af016248e9908882f8a7f0bd8743c8da82da119446e8b02e4d3b8d1d938a3aa214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020794b4160d8fd4ebe7611d0fc9d3e04f3038a485669f74075aa153852ed181121c577f4c0b7151f6d78a16e3c21ab291b53ced8a5c4f05a22caf24a25ed029d56224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204a8acdb549d2ed922360ae0e81de6c913c3fd84b0de51abacbf97162a99f7c26c656b252d3259c33ffc7e5d403843accc6ace9b7e60e911e2347a6a0b0abd122224ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020dee6d00c7058b3422e4273c98c16181e04ea93116496a8442de546c2ee9fd86b550013f39e004b3829dc3717b17fcfedc87de9450315fcca540963119cb264c1224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000202ebca471f5fb2226a790233c3d0bc323f73d935872f3e15b66bd5fdcb822101d7b68788ed61d3fb8cb746f627e09db2fc09d8a07672747709d92ae400e053e78224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020ee500470fc1c71a82f2cbb9f8d5723bcdf57b8051fc458a8dbd8d0dbf60d0e40d1a0be0e50f3312d4830e3900186e5a6760d44006c164b4f0758218ef2b2de8e224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401300101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205057e8d8a7451d79325851dc8e0f4dfdb1dfaaab637509d9e61f0e064af5ee5c185221c53c0cf43261b3c238c0e8117da5d6ac60085615f7a3d8027726cb2143224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401310101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000200907f01d9c5c872296796ca77feb62eb414cc080e13a93e59e181528bc19c336eaabacb1ebcbd20b26f6bacdc712ffe17d4c8131e7f99b9cac309c0683737c04234ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401320101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000209bd6a4ec962d9e6199c0a2f39481a7ecc322fedbd2320cbe7dc984c6ab958421fe7a5c7f2513a3c3de9ddf7b211f5bfe85675b31183c4bb98ae79ab28cd055ac234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401330101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000202b8a6381b7c9476fd77be379a929863db6b7edd9858d6eca0f68a430dc87cc3a9c6c8b34bfadfdacbe95cb1d4ae5ce4e4f4ccf0300171d7a91cdc97f620c7b37234ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401340101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000203d3e9a0b4decf12b4402a2178b60599311c8a9c7d50ece365a61ca29530da7056754ddf7d77a11cc8ce680a74fae01d851bda024fc9c51712c55b4a190caef24234ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401350101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002067fa05082d4f7a29a3985f30798940cd854c76a2b20e9560b2047f7753193f71ac61b8df17a8a63f099c8f55869301fc2a0aa37355a4a2f89078135ee72a1362234ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401360101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020249684272865fec3ad62ecb73dfd930500e32e475306c9e5d4b6d545e3687b0a48deaeebfafa213f0a560994b3f4000d5e2b93951d7e5be40073503877292dc7234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401370101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204671db1df91098669bb03c3e8504d432da99853601366c7de7585bb8f23a6e1e2996a16c11a0f9ae87d937f566c8bbd919040528c1bf8dae4e22a8f0ac5f935a244ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401380101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000203046500cabfee552ed114c505279cd75c28faa811adcb5010c53c14df5de3216d265321a4168c70fff1c85fd83bd976cc03c8c1fb6567398cc24053e343ad137244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401390101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020591533cf8dd1fa1872c7e6d62ef714b28886f38f7921ee614e13b748eaf923282a96287277f18b1113a9c3ac384fd7b43bccd0e45114908ca5396a76cbd736fd244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205286b5747d0244a55e1dce435fdbb9f300d7138fff3b16767bc09196eb00256c6795e3f372a2d5d137244a4fd72fd799e8de913f868f22269eaa628d7d2970a1244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000209649b55f6a5ff0d5db73aeb7089fcce605fb9dd23971e577b73747ffab586f4edf84581240223e2d8912a6eca049e06aa46ddbf271af08e9ac9605505311418b244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020fe7ff82c11ad3a3db3dc11a03a67e0b86b727d232c80f37209b028bc2689296c0da76fb756e1c9833f38b198cfe843ab820fbc0c38e30f8f858f6ffdbd64e834244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020c02e6109b6aaf6643cac109ad5b5be7f7ec47c7993335bdceea6e0e490ae9067eb1fcee49ecc40a61477f934e3b9821f2cc7ada429fcca2cd645866742854c40254ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020956c46fce0adfc8a30d91c7b7f328f17c2a90771083884c4fdb7f24640598f6fa69c4e5971bd3b6cdc7e3ee98e03a969b28c3220fdc685cc2eb77293763ca4ba254ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000203eec7d0ea9c539f47e684eec9dba900e27c805b8200f237924c7df8065957726c83caf659fa341bf45f733a92cf76daf2cfb6bccbf969a2753f5f7d9cda4bd1e254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401400101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000203c022b42283bf651ee4d536fe71b7e5382e9783d4a85f8bc159f00b97f16d82d312ac4f89f1b1496de576811f2ff17de44b512db0beddae59e030e2ce3eba4df254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401410101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205da9709dea4bea4f3229d0eed439a4820a0e817f9fbbcd8bb355cd8052702973403358080a2881b823a740f58b6b0c922b42189e06326478cc33390f2c704743254ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401420101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020447c49f664916cc13a839e27f7cbe0b09dea990dec71dd479b537ecfb771c7159ae6241727c2645ce00817909ba97d43447fe2e146bce55b7dccd5bcd27d2e3d254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401430101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020ae3b214b1495953eea3b99af7ade4b8d22d615d598dd6c790c6576d6453ef35d37fbd3446f8431f00052f278c3e0359beba54a2f5064bc6be4990478fcf4e086264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401440101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204cc68f9f571f59145e1f7505550d56da13a797fbc7e5a178dd7f6f9241d91f007f2400f7aa1b32b30bf869e4da86f75eaf2baae182efc45c42c6245f06aba675264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401450101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002096d55714a83c3d030cc72141eac3577b8a394b8366b2c93354fcecdafeab025022f5e26de7e4eba3f8e4a09f243b55ea6f08bfd013e2051cf1d5df20dcb3331b264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401460101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000202ccf49665bd46e4915dcc9221f5fc72124bb73fb11fed8869dc5862a47950c0d654693a1d86098212d68fa9a27f9df0faafea4aecebd8b203f2ab8f3f0b86196264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401470101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000205d0be5aea546eab7734cbee757ea5f4983ab3a3f202323c1c88590bdbc8b561974cb0de6549bfdec92322ad53d8a4192433edab0e33a10e7561d2e27c7759f8a264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401480101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020fc3d70d4f690d7d7da90b1c832a51c2a92940cdd9fccda6a909c7256ad567160550e1089b48fe75f0f1e6f712cc2a1d4aad384a4ceacf1c71576420fe8e7de46264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401490101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020995ab1f2293e3aa1e7bef418919bdce60032e89e60223b8c12b17488c50af83b3a360b4f89551aa0ced646a6210b0c3d3f7d0464faa248b9d252c89615babc9f274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020e02dd5e1201ebe7ef453e77df3021cffde1b5447b9eced017963489e005ac247e1f2b80e91180cd9744c3e126eb8a0fb34ced45587da6b0fa9fd1c6946f049bf274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002081b265800d61feb37525c58aacc7e6d32cfc6b6579784f9952dca51c3addeb37da900ae4ec1b2075056001a361c0fc8f9ac1ca018bde2a2bd8fc587424dfe18f274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000207daba0dc6fccc067a19dec46770d1443fc715b50540242ff26073a6748bcd9583804c315b783d4f9aac4dc8f109fa60bcbf1c3cf98a7e1e593fcb969e88aafae274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204a35ab2d9c4656c4992d2445ee566e4f5cd0468358292c94839de2b270ba0628de9148db03da59ca2eb727a4f7a03f2b9ee1e4045f37bdaa4b75a89de56b63ee274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020215ed7b31d118a45a06407133e41f3f9d25c913ff98f3e798144f981d9145305266efc9274f7c836aa0f8b831732aec2c1d85c5bb9176af4c889a707cca380fc274ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020425321a1f12ed4613b63b3cc5b4c7674242c3de67ea86984f2d9bb2766f6220a5c460ce6840832b7ef05f206c5d255bc2d8ea83753a7f5ef5c0bf3dbcbc7c74a284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401500101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204e088cfd312091bf589f0fc24131dba20ed83f716530a7b033356e9ec803be23a73c4af5b64fc631d20aa1f646c7c61c4cc5d4be6e2fa29570030d72219726a0284ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401510101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204287a2bf40300e39b45d6667d6e17abba37d98c41efc7023fd21b643fb2f6b76d915d10e1f9e224d3bfdf5203da57173f0b8d8eedc92ed9ff23372927e86073b284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401520101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002083137929ca902f409a1f35385b4d31e0f5163d488d71b00ade724d7831986a280a187c13fe0db45aed5fa4f5089d544a617da9f4f80fe6ce1d0711b228f3a6bd284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401530101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020b38c074d78cbcc8bbbf20c48e30639c2dcf444488efee59f5aa01c48322a30418009c11df7e14de6a6d0d72cc22f20ff5fdba3a7dbe409409ff92b1302340fb8284ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401540101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020a6865148220c7f5ac3259f57fa381676d6be5fdab56eed8e060808fcce4118492476fe6d5ecc681e7a18c20a04239143de1c2cddefbb08f15153b8e9b0c22f62284ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401550101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020ae146263f4087106b8c51ffb5cdddb03a4e593ea1a22a8f6580eaa374185126db2187dbe694a1b17b7c5664115307965407274c25bf6ae02049817685f923256294ae75affff7f200600000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401560101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020718abe22705f33134812b56d04c129d453da890e27caf6e77d2bfb3f9be460083634f35fc8ea4a29b0f30d6c6b4926455a31de62d2f763bc95c8cd1a7a425599294ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401570101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002084537c50520f4e6b0173926320c3193f6b4259c9a724fe202337d3d5cf7da70b1104e1d6f25c411165a856a0bfdd5ddbe168238425c05271962aa6e5ebb676fb294ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401580101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204bae65b948c9790468cfc8fbf78a81e7aec5407dbab18c18ef1ab37a13f0c257792cd1246dac5ce265a8439e539db1aebe4776535d422315bac8e57a51605aa6294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401590101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000201e68985b2a15920524c3c2da77354c0ccfb202c3ab4005128eb2743aa33f0a5b0527a624a6d1f808c896d8cd1552c251a4ae5310e6c62493977b0965d17f580d294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015a0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020ab1d90854505caa1ee748c1987f4cb6674844b84d17224bc3983fdd6e44a930b2edf3e5a90be7a9080ad15014ce796b38b6c19ddd3754443243fc277bcd2368a294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015b0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002062242f316efa083c17e2173d9f9831afc1465f3fe84431d8e52fec71ae358b243e29246e0db770708987f2cff380920321636926d9c66c2c808d2d5f0ed27d672a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015c0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020258c1a9b0ca17819d8d7fea5178e9c72c2e7c6769696f70098e0d5d2a9dc0e5cf039f5f686d727c6158ef5405ee8794ec2f89c641093a1dff0f5240263a441bc2a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015d0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020434ce26cddae99571a1d663419d715f88e6ff0e413c45f21c44b1991d041fd2745534db221054e2233052aaffe7d7232a91b3f0918c14eac74b2f704b37bfb8e2a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015e0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020ec94475f112ea37dddd84f066e61446b431d28d2d9b6fbb336d16295e7eece52f1dc01abb3b27e71d8a25c3ed2d6fbbc5900bf954738ed63d57689ba5e68f6532a4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015f0101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000206188cca18a2be3b7f0b500a724f1b73312873488f04c5082abd81ca0b2250a75ec0efb2fa994ad23e1f39416e69976e66fc4ef9f101bd4f60fcee1f8c45a2b802a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401600101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000202384b91bd0bfb1385ef42bda9b2fa43930aa8889214bb14f63c61a74f380dc7f9d547f2925ad39b9161fa55b9cd258463fd058234778a7c7b3061113d64179812a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401610101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204c266a3008c3bd95ae4bc8228bf878595cabf76cc2ef3fed32936777fe37833a1a13ea016868b2352a8d6d1eb35d0aee784cef06ed50655b8d84c089324351df2b4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401620101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "00000020ab2c78d1249de8482cf26bfb1616ac04f7b8404eafcae3e0654f398943fd41571b4d7549862be0b06ed1408ddc3e7c01b07af24c203a18fe9744e214b14d2d652b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401630101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "0000002031aa0fc5e0242a9c9d91024b6b7e67544da72c4773537f881ee5caacd45a3c38c650ff5fa0ffd080b3e5f9752527b718e8c6b731467028e14b0b009d4e7406ee2b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401640101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000200418c57609fc6ea3f24f569dc3afe163538a6aab940fe8c3d73c72cd781221380482c6f8ef2c19429da2f7a842bb811496aa86247c55f7ecb3337718b694d9472b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0200f2052a01000000232103836d350d84c3782a7579c5f542c7e70fe628d3062c6bac563d2264c21e56f70eac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
- "000000204f36abaf10d6a8b3113103f3413475db0640c89a39f02a718e8bd2190fe87f1d6ffaf2b9fdbed67ebae4b36c97f9582814c99c90d0b5123f14da4861bf3e4f742b4ae75affff7f200100000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff02b000062a01000000232102f6869601b2b9980b07fc047e309c1fc1433e08c5bf0498115c5c0e117ef59bfdac0000000000000000266a24aa21a9ed5896cd6a40cd126b09e317cbd179f39e2bcef2f9d423751d980258396416e671012000000000000000000000000000000000000000000000000000000000000000000000000002000000011cd16b94f20a8a3dda91027c888025f2ec1a07ddcb2786bdff5916e66c00406f0000000048473044022046d00465c4508cfd02fcb878b19d120e28be28e40658b1f15458828891ed1541022036aac054f36a42666dfb7b42a20506315a0b72232ce7704406e23c7a9515178701feffffff0200286bee0000000017a91481ddd4a9708ba8088cdcfeab9583ede8d83a298c8750bb9a3b0000000017a91484e16967722289584257803688aae36cd64480688765000000",
- "00000020cc7c39992f2dae21e0ebd958f6ba77a6d0bcc568e044b9b61ca4d77536a4214e7b4ade79dd733ea72d97993aaac27f2263b91b1500467350ff35ea40c2850d392b4ae75affff7f200100000004020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff0230d0062a01000000232102f58ba54b2d51c4e2a6096f9d266261b45f1026a86ba88c29ed8070dfe3f5ec6bac0000000000000000266a24aa21a9edb824d92cb231c2366f0726aedf8bfc2705239a40ae6b10a106534e8b5395a09d01200000000000000000000000000000000000000000000000000000000000000000000000000200000000010196bac2a0f6212b8e5710f8c7214dd32c393d38d20b7703cf0b7b25276bb6ab8001000000171600144f8a6c8d4c6c309b1e2b725b7496859e172ea367feffffff02781ef5050000000017a9149f00bafb542049fe32d532b0ea7494ebb7ae41398750daa4350000000017a9147794e6dc43de332ca7a095e582478c331446686d8702483045022100bd85ed3954f1151c2fde32c4021a32c96d7defa4a57c14b1a056be9b361a8e49022054947bf6fdb535c46cbee62efc1262cc0389a6eaa19afbcfa98fb1fb30c3ef230121031b2371df07fb88dddf590b246dc74defc265fdbfe258e4b168250859b806f5ce660000000200000001bf83574fb606f25c59200c844443201faf923ef5284fd4401f3104a323c601490000000049483045022100d1c4b09b488f6375ee4540a531a13b5549e88e2459bd88c84867e293c54862740220222e8af70c8d8b1139c2a7b616d9132bde94244edca7eee3c7a783b12839dadc01feffffff0250196bee0000000017a91490e5e33cfedf18d5cf911d6f853770c62e1f5d028700ca9a3b0000000017a91422311ee58518edf3a2289012461dc66bc8739d2687660000000200000000010196bac2a0f6212b8e5710f8c7214dd32c393d38d20b7703cf0b7b25276bb6ab800000000017160014b81faaafa52f7723f539f8d595147b1a112b38ecfeffffff0208bd9a3b0000000017a9146b2e611708a94d9c674dd08c7c4c1fbb97bcdba987005ed0b20000000017a914933a20f07bab1d8f341f391819466a271f0cfd648702483045022100dfa8b0052c7825e6abcea05d10fc82550a8d6538681ffc8188d48ba789e4d9b40220697371cdf527a6ecd1887f87da3c87dca3419e4a1aa2683e5c4e035199084d100121021cc37c2ec090f30ea0b49508ae8a7d65d9759903932666da56671c1faa445d5d53000000"
+ "0000002006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f28394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3194ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020e959d05cac787d7f82d1348326a4ca25ead09589befcd4b4513163e5acb5af6612d2f07672102dc6f099c4be308f598e4c4da1a7e0cb462ae14f0444525a13321a4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03520101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204401ebd07d42f8f18e80ede81795f728a9eb2a63073274ad92ccb9eda593ff3c5f17ca91704a014c6f68ca623ace6c542950f2e1d2d02ece08fbd440e33af53a1a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03530101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020eab1809c3e750647f588c027df5c9d5735bb8cb2a1a5f182d7b35524b0b8595f9d59f165de689fd9a4b6954b4394d40d7899eef078e6ddb9f7eb036b7b15af2b1b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03540101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020bbe445e86bf69865a0c816690c0e470338bf9d692d388f8186613830afe2f54c07ae38ccc6fd49e7098d6e3149e459a234f30970c6c9a9894df992e3caf97ce31b4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03550101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020f5b84b4e3b7e84720a83dae76aad6657c06ec6bbf85d9158c575de09c34631035b263b763b955c4c6d1a97b23e6b4bc5e6ee96d75910845557aaca233fe777fe1b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03560101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002028d52759ccb342b81f2e8d574d8cf116178949f8a595d577098bae70e6969326119c83444b75d63bbe98d8b3a937f0de3a459bda5fdc0fd66c7acd752d19496d1b4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03570101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020f461e9c8981911f5180e9a8e28be1d34146460ae4e7583935949f43f6252bb3cb287270caf2d4e735caf0d9888f998b8d7c79443e97933976930919e6dbc0b471c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03580101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020d3328d99edb99583b478969aea57e378c2840bfc1df0341963fde16f75636e34a6c85df88c2800c54565eb2e6579b729def99fa9b8ca347ec649b8d4f8db78de1c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03590101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000206b88980f5b713605233c1c8806639717f753c4aad93617d5e37872a43188af6c8dabd724a42288139a21186c855f23c4fe1d12337ec7b97f87c48389983239651c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002030fd29b0e0e54a5eec463f93dac2fd9d73f383b7467d146a882bee4700f79832a343b1b1867b07ba30134ae555db5816ccd971232b78a9d596e2711d02251c521c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000201845eacaca9b23798f32c22414015655035d4918be70e26f56b56e730e195e220bf32e9a8af59ce9264884b0690bb26709616ccf4bfb85812faf87144b2fb8131c4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020353ff17bd0d66a6ee1e784bfbb2497691f49e27c3822aced5125fda6ff09892fe72239d73e75b82916e8eef04a4963e6b500de80a7fdcd89952e23c6d249c5931c4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020c6c359d1b891b0a6afa7e0fb685b9c21afe41c8dddd80cd6331ecd856650af3803953a9bf6fc675eb2856718bac5362a12168e7b1baa7dc6b46a4eacd2e8baf61d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020291a8a183e7ebb538030bc791b0f995a2ac0a766add84d83d3fa9f6fad50075a0857e76b64648e82fd4341931116efccaf147f0bc6e8c107cee68f400530c17d1d4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff035f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002081f804c3afb976efbaf9f62d50ca43402fd5a09571cfd93ddaf77d78952ebb3e3db790f598f68da5e0514b03902de787ff0d2457c05a59bfb22547d8ee6f7ed91d4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03600101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204d559298cc1db4c70f422519822a850603ec250f4ab705f51423d67bb2d4a03abfdfd932c91a77b0065183cf1a575e73b9d1322804f869cc640747e7fa36c0531d4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401110101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020b49a26625c5d5210a3dbd1aeba62718b828a29dab035b6e028073c3679053c02ee7b702c74ece9d04af3aca5f745aad5d4142d6a15ae12d16157c1449b62b1b31d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401120101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020655a431b076a153aa7d9d3731b42b4213995f92299a56e6270860be4005d584d33b5d4b94367acd8ef20e10678a75de3c02e143a3f9bb0b0f0c31ed0396454c31d4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401130101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020a96f9ad3e058c097d63488627158e074f759a73ae3292b8d8e3e979edcb4e33f0ccd7e3208e9cf08375f36a34f3d71da039e6a33cb8621a67bb484cedc5fb4f31e4ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401140101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000202ec3fddee36cdcfa564d29eafe073ba79120ecdf8740f62600293b0aad6039419047bdc522883061665549cacc029b05713ad4ae24281eeaf0a041cec3c7d0d31e4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401150101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020d2985cee6e78b525c61ad111b0e9a6ad8c222ca793eff2121c23cf06462fd930bfe97d3f071f45d95467db4f5d31d8b7966c26789be3d5c1a5d53c903230abe61e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401160101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020e799bf0166a1e3e7b94d6709fa0edd5feeadac19ddb271ce8e8a6144fd52c23b1699dad3820cb2ba528c13e37550cd32a900ca14f307db9b735daddb523b1d511e4ae75affff7f200a00000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401170101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020a6e38cccd5f39851e6f1aaab690b3591ce59ed225bc4815b66ed59f9e604da4beadf823c049567a4628d7b06090ac7f51f1a854c46817a8b6fb8f069a098f8941e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401180101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002067dc38dccecab584fccbd21e1fdcaa8ce69155053eaffe082d51fedff22c26299e57f12478cab2077ac63eecad4a342082c9976addd08ea58896ab334ddf5e6d1e4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401190101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000200b71cba7f1d43034d1584c309e04bff61a7814896b3fd170f69d8757a81b114b4769be83a7993e5214c7cbb5053a142840cc180e23366cc1d52cd2ace2347a1b1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002044d38910c5362c279ee6e183c56bb2379f0d053bceea9f2c00f99adaf1a70067de8615ddd58387b2847d215fde3633242c278ef9b18ab9c70963c9060b4a3f101f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020b063fc1b09b6f9cd8207b0f9ca9f1549ce2b1de07b7f937275d96461ecacb26a3abf0a5d24c68c0b3df1a58b6128039eca6452810a374a306ac0cb96bd462df61f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002023334826cbee5a6679259a50f8e112332db9663c97a1d08d54e64319dabac73331dbae7789d23e1da14d1ee39a9dea43581ddd9c09a199253ec0bd6c819514911f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020911e28670d744a0cb23495711db6ac20576273eec7ee442b0377ea2d7564402fcc7db46bd4aa8fdf1209e649b3866f5cb79fe3f2cfaf8aadd39a3d43eb084ce21f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002038d6d41fddd3c9278884c9141096360c538d2491ffb078be006222a88a10c854366b75e0a133e1d3f4db26e1b0e9b9820db50dbfb11988e8bb8739420ce1799c1f4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04011f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204e501ddc49c462c4ca52283614e99e6379b9c6570c947a822b832804e39aee00b037b85318c2f997bd9edda927e85dc2c83f8aa1952dc67556565d141a246186204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401200101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002040cb0b50f15716374c2dc627d1fa6e3eaae67b1b4f1c90a30914e3c89a74de794a98fd86cc22c32f447477016e297c61a4e48135e658e5b5be84638f3a836ee3204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401210101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020f51dd27d82fbb9296330e7f105a69ea307303799ca986abe900f00836f181e59a34210d60eb84f3fe493845aadfe404fb4096e599a26f63453c8120257cfc8c2204ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401220101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020b696bc517ca5d36092ca1106fd8d31047552e9453a9de51d92cf9226259a491618e806cd5aa13974beb89d41c5040a48242c24bffa8e65e9fdf3bc35e2a7c1b4204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401230101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020358daeb9eef51c07f280abf17c5321023d8cf8bae26254abf25b9268d89a424fb67a604005cd713a7df2c45fbf5f761da51b9c6f21e86a3d8eb40827bbe2764b204ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401240101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000200170975c14ec6544367490c04b06294aa57fe978a1da6e5939ee6051d7602928e3676a94ad350f04f371edfe21281df51430055242082d9704030cf5317d0b81204ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401250101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002008d02d23a387a7263f5f3475bcd56b380fde9b742bbe83790dd9751701a7923038bfe35d91a9e4e5f8cc714713acfe2d1e96646e61b29b3dc072e5b182fdb45e214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401260101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000206bd75eab3dabdee5a35c0a64de2aa90fb54f2d12b4f37ee60aa28541b51b493f0e5915bc2be5d87850016a330fc36b62f6e40ad7a6d38e0ed6a4f62056ba22a9214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401270101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020a42645a785e5dd28047022b724c1af64d507d372b83f3f23899c82b317168262371693330fe6d94f33a962de50891b2f5811a066830c331a240996310b5c6280214ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401280101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020a6626233cfb7d9dd7c97f6db305ca20b6a7fc32d5e8ce9b07e35aeaaa7c0af3975cbe08a458c6fc4cd748a39427e29c2b29180293359623e30e2b5639d2d0417214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401290101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000203a5a408e1a076fdc7bfa08460932fa40aedb0471fe808e268ee5768ce173520af5dc75a6bde31efc2ba81a4ea94fe91d3b1ab1ed99975fc5b1cc725f7f20817b214ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204cc70837ef7c3804c04419260a2d65ce21515317991751117fb81596ef32c3161154931edf6dd92bb8a13231190f7c0b21bc527e188384770faa53b54aba04f8214ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002070b6275e92ff0b54df08933d70b7d933c3b534b779026630dfb2f96efb860436581cf56e07b7d7e2a377ba0e698f592e464d1ed84bf464b0dd67cb85cbf69f7a224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020a330af8e1dc93fd74b7479c626b1a77c21dec2d240fe7b7d90249da127aaea50773fe8f12bdce2a65c375082dc3db0414e68aacea57f41504cf901a7858b8cf3224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002052841b806090d1d40d221788025ba6ae3a9bb32f352cb12ce4b165be58846a12ee2ad08be6b3e693e3d53a90abe88a8426b342f19f3b271818e66eed4ed1892f224ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002095b86217b1ebf86fa345f2c605f4251b24d5a647710758cbe08340448250ef015f65e5752628c0a0131fc31fac03ed3a2ab0d2c1407414d4dfdc1680037a3b38224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04012f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020757dfdbb6f52e389a0ed997dff15de8682d55f9e241d3b53b254f19fd96b926860d0c537aaa527616248c9e50fd776e801eb5dc5d9ef034251b846359da84bc1224ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401300101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204c5ff56d6188016b722ba01c7d3b74bc530820b7dff447efbb8c5e756def2d25bdb8e2a27ead1a99e184a87195f06f858b810add552f6bf0127c0a36ec101a60224ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401310101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002064c6f9651c489cb014e8d5271e1f711b71d20d865ab7561b26bea5c85fe6957b6326b1ba78a33db0f148a07e1d49437ca70ae9d73544c183d2cfdf814fd7ff37234ae75affff7f200700000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401320101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020bc955dccd950bcd6051723e18c87ba5114103eb66c136d4bde1070b99678c12f6192856637c104e86194dc91e1550447d83b7124a230871020c37454f2ec82bf234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401330101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000200f4e7a95470e9056dda68e82b62a61cae778e88b6e35a4714bdfa3bff8b6e846c45be9fa19a24d90a3180a562bdd8b8a5b71d4c2e0a9f84b6c55c439ebf2f22a234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401340101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002044388dd29a4f16901222a7beeb49315884c0583a2c31a2f8865536931ff8ec4442553d33ba0273b54c52e589523cde509eb117046f5e63bd5e8a5a96f467c5f1234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401350101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020438366e968619730e26031d71e8208d31ab6cb7c242acb65f3d1769157cb971210b6afd88e0ce95bb14554c6dad04012fa8ce0c88a5932ad71da4d04a15d44c3234ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401360101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020c38296d021842f437d04f8515079f943f0a1c8437d8f2c329499c32c0448ae1d961fb68ada366165b25199757ce8a527f11d0744bbcbaad402815e09623dae04234ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401370101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020101cd76ca645831e3a55898707454b2405151a06f8c8cee7822d148ca1251d12fd945975eb3855e5f0cd2afafd20b169a7763bdc73b64d1c2f096425d9c902eb244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401380101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020f7735468f9b54bae6399754a1ba4b5ee620af1dc6a46261f4d8ab4d872818f35507916cc69e748edc3a9feadf7b79d1d19f16140e8f3260d7fbe9d1620e55f26244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401390101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000200bc5d881eeab42717526d45d8475fefb1940bbf03c5726174e64379e5a23bf5cbc75b97dfb5771d55e7bd108bb109705ba34952511ab96646cd2db4539fc3b2b244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002094a466199740a3c77035005e1fe5ae603df04ab18c429abfcc385b93681b75390e0d6b356161c1ccbe486a26b777ff01b1247cd6b4b9d4d5b0f958d2e887caab244ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020b5e8aad67d17f4f047da10404862703a89feab21624801f785cfe77af4a71d6b87994452ce4bfdc92a07f49ed16903e68d8d48191e31d9558dad4805718311d5244ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020b0ed4309ee1541c2dc5480b14092940b88870b9d4ca32ca448e7eaffc1d74978b9c5b6e8c1739811c932cdbecd192ae0bead4068782ca2e98805b8174d40f213244ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000205caa7f7a1817fcf6b454b156301f44edbb71cd19de098d9261305aa5731cf073faa4b4bcef4b3ed44ddf9b2b708397114484aa262a538c81b04103a02d8c033a254ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020c7ec1d68a2b4309b255ebc418cc4c8c1a57892bb3c6360a07d22b526ffba6a38436088fcdbf94cabbacefee23bb69b5ac30e3627f94500746630163249cc5029254ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04013f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002014c877261aa37fc58f703b64278f1d611b6faddd582e33cc7f1e7e63ad75df6cbd9d279982bfe391b013160a66675ed11debd83c32a9efa02351eee65ac96d09254ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401400101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000202b5cbee48cac714ff220fafa0cd4304f452e5c5b63dc5cd4f27072cc4ba7e9376f1f5aac2480c10e93e13f3be00b38523dc036eb6ae49b93f815140ee2b08a27254ae75affff7f200200000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401410101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020aebd16a2c6cf18789e213338ee08bcca42d89e7c9f9220cf80e803cf9b67205eb58e2687eae141c7bc9656b434bc95900a6935f00db43dc23ac155e380af8e9e254ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401420101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020984d2d236668762da13fcb8f811401c1928a1df9a9896a4cc382912669b0b13642ad8e61dd8e6c702869587acb0d09b3355a1be27cb20ea909f51287f9e1b010254ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401430101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020d8ca9b5782f98937be5967d0c34aabdcdddc0201e17b70e4071e320bbb2c06418d020f678641ba278d49d70430385ede2f830c46aa49ff7a3febe99d2a9896a9264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401440101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002017dad2d355421342e973abef035c18398d83dceccd6372269f6bbe6e844fcd52d9c4bce498d350184aae9af97f0aef0f366356d50b926c59bc1605ff6f41f144264ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401450101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020ab1775daac96add2d038b5046be91c90b597b8ed11038b2b9da32f47537d106556d820e14b52e6f4fd113554754f3a8d65b80e7dfab2c84c5e7bb41a30c39977264ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401460101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204dd398d0716e12f3397c9de79cc644ae3d63c6b90c579f5872d76820dd79260fc5808f07c0d1a3e6a23c9e8dc84d58c12758cd61a2f0e8ec3694a1ac08a89bda264ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401470101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020ed9c915c725956194c078ed08ad2508ec34a6b868c21226d14213904bb3c4c50f385dbbdfd18fa6f8355a89c58370c50a71f59f44e2d2e505fb861960d155705264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401480101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020b2f8525fa7a276f4a078bdad600074c49df4c237aae27cadb60ecf91eb7b8d42c21e035455f17270ff5e2a53c57c8c663f31cdb7a3a929de1499e3117358108f264ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401490101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020897b6cc09bd1b7cb5d42c648498199aba4008875614e021898b121e8e751f34cf0b8a1a4c993ffd133335d84b9aba6159bb8129384a253131d1998f28c3d371b274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000206a9836bb25994ab592060389b119cb8f7a19a64acd27f9665eab93b235803170ec6385bd31ab432ed3a13f7a6cdf0a6c87fe50c614372a58a5a3716c34456e83274ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000208202cd4938b8eef65707e3b6cbd025780f7220fdfea8bc897e802da008026d29043cd5b1662309701440c7941d61cfb95d0c98e22ff8ff8b5994149e988ab179274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002074eed60562b3fabf1cfbd4efd86acd62a470dc264b81b98c784dce4a57f56614d713809d3b1678f325563577d3b6dd9ae4f1e5b05b70c3b16abd67d7161d9002274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002072677aab7f4bb3af82841c6a7100df3ac5e8b643d9e88bb271b2da39c575222aadfd5417618dde8d0ee9191c4b110d0c76dcb65eb8adfd3f8a32a35ccceee445274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020508ed0a8978dd8a6a4e55bb5bc27dd8edae3838d4ddba461332da10f0fb901080c5a78ea3fb056e326e873cea75009c29c401fb77a415ee64ae4eca44bd617dd274ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04014f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000202004607f94d91d8eca99a860ed208c53a4fd53f38889c77dc35b31a676eef1625ee8e5c95cb2105d0b8268ed13eaac6236eb3405df3099fc52d62169d218fcdf284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401500101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204374d19a51a307de1344af36d893991965f58779adbc4b1c1045d5d8e14d6d0b034e10cf7e5158f62fe2674c89e8fc4ee94d2da62d81c0ffc8a237e8dfcb3e21284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401510101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002037320af6c9cc617be33ba517458ae4607b1c0e3e007268669cf5c799e93ebe67f182660cef31f84c0c6b384f084b243a77e2c271be610ac958124076306d9170284ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401520101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000201ea13062078bd8f70060208d6973bd55789cbf2f221e8690f1a78254a597a1434a16aa13a90a872e0dd3046458114dc745e37d2928bd9ff306ce7adb2567efb3284ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401530101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002052fe4aa74774077ea9a1c27fea59dfa12b75f7ad46746f8458eb67acaeb9803921a47de6874e6c2359af86d72abdee12b27bcebe0f1ce48751055005813d3f42284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401540101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000208ee41caa2f3076233035157fde7c5c2795a81b85d5e27ce7898e301679e91c4d2d38f595981a444c7d868166ae50e371d83b5f59802bebfed056b93aad1b971e284ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401550101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000201a0eea032f4abd74aa1bf1151e2966433175ecdf2d68b750b509305bc5663e3641f55e2175bc1d50b4d8a83f167091059a2a6e7d1a24d8223f50ca41313eef1b294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401560101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000207403c2bca2c06351f16746d3360a1a7dceb5194d57879caee03a8316ec774a608a5d44cb75516291cdf62cd51a1a9c71fd3d4879737d88216c6c4c6bffb0784a294ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401570101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020f2be7a9ba2c914d5ee97c819cb096aa9d2c715d2f74e9dcf8a12cc83ac48475e4e332a45285f3fff16e8c5cf79107ee110dc2a2f84456205f43d8f4e237a10da294ae75affff7f200400000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401580101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000205fc71ff65dd07485e26129b765937f514315487b27f0e431c5da7de97b397a4f1d984f86e81bd2c9db53c3515b6e3d6a28187b50adffb87df25608b738190bcf294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401590101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020d7befb40f244eb69f02a3253bcc9b14f5c2697261e158288e7d0b48eab34f12eeac43d0751178d2574aa20506d1b91af13af688a8dfcdf1a48806f63e53b3245294ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015a0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000204a0082f8508319d99c86cc074cfedcf26fb98f2e6d0c27d602a9d6ed6d04db042163e10278a5cc75003c52739df112f1ea4fe0ed250ace8e544ecde713f47bfe294ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015b0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000203de23751fef24f5d30565808862dd364e209fc0f7bf83874ebcc8f155e65574acda81243c6a438daeb547e1b36c9a5441e6556bf16bb9bfb839628c39a3785162a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015c0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002045addce76c20d564ac3ff6b955e8ecf2185a5aa355a0d3ac7fd29448dcfb9c1ed184bdf283ba671c76c99173e4ec87e45dd97331c9000070edc81093bc4c7c872a4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015d0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020a7e8079eccbca3b4a4a0136ef27478b45352270f2f8947ab83eea09b06cc826ab29d7b37989b6570510e368a20f4fee2ca0142044f96a027830abdf438ddf7592a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015e0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000201f28203982fc7c2fc155361d00ef7e69ac9fa9c35ff3d10e8fd1a0004e9b10528488982a149b5ac96bef6be131e0b2f0ad9269ba66c9b4216901c0b81523123e2a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff04015f0101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020435d68020c01c6088e4013cb4f349009e65c28ffa0630baf5dde1676df55481513a48742e06190847a40cabbda6d48f715802bdb3cbab7ad7a2e5c345d557b082a4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401600101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020e525dd596c4b9ca78d964ef7997063d35af98665f62e9da62ed9c7fb38c9f57f5abfb8140edec21a383e1e3e31288ee0130a86564e5c3da9764594d8365134652a4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401610101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000203d4144c4bd71aa7f71af930a98087d3786e697335fc1eb11177bedcdae72a61549aa4519391183deb58058f99a6abb7638fe81f079b31c4e090d486c49e047ac2b4ae75affff7f200500000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401620101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "00000020f44e7a48b9f221af95f3295c8dcefc5358934a68dc79e2933dc0794b350cad0a90fad2cd50b41d4ef45e76c2a456b98c180632bb4b44e0cd18ce90679fe54e552b4ae75affff7f200000000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401630101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "0000002087454276cce83f4d19e0120f6e9728ac5905f7adaf6b27e3f5bbe43ab823f85db7d1f44666531483df3d67c15f2c231718ad93b63b851dce5ff4c4a67f524ffa2b4ae75affff7f200100000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401640101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000202cdc3e99f07a80252dd6097faa0eddf3f2dde5ae390610e0bca94ecc25931551d31fceb8fe0a682f6017ca3dbb582f3a2f06e5d99ec99c42c8a744dd4c9216b82b4ae75affff7f200300000001020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401650101ffffffff0200f2052a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
+ "000000209b3ace9bd510918d20e87518c0cf5976cab3e28cc7af41259a89c6dd7668a32922808b8a082be71bcd6152cb8fd223650b5579a41344ba749e4d17b9bf211a9e2b4ae75affff7f200000000002020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401660101ffffffff026c03062a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9edb85d8f3c122c43a72f1e0dd122c8f7af040aa0b0a46001621110fb37818021510120000000000000000000000000000000000000000000000000000000000000000000000000020000000128394022bf44bff30d7399cb5a16e3b94fed67dc174c2e1d77df91bad5a51cb3000000006a47304402201c16d06a5c4353168b3881071aea7d1eb4d88eedfea53a9d6af9abb56da9060002205abf3ae535f1f1b5cfe8ba955535c2b20ac003e7d7720c5b7d2640ac2a04d19001210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0294b89a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac00286bee0000000017a91452bab4f229415d0dc5c6d30b162f93a1a0cac5958765000000",
+ "000000200fa168b50a79ad24378a6b0f96e4c9f4ccb657a2663320d5fc1efd8ee7caa10ab42a31c444f2153387530a0979d4dc3dcc134b394c821227b8abff930c03c8412b4ae75affff7f200200000004020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff0401670101ffffffff02e015072a010000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0000000000000000266a24aa21a9ed20376d4bc90f9c689850eec3603cda658ba6295241730473ceb0e970b8d594150120000000000000000000000000000000000000000000000000000000000000000000000000020000000191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a6000000006a47304402200bf62021c0a9a47ced8eba1e0998f5c71b2950763198d83ad284bd791241dbb00220446a05b7c35e7458924de88a8dcccab1ec6a106aa005345e55b482d8eb66337301210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff02acdbf405000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94d7a4350000000017a914dfa6f0b17d2c64962c94203e744a9d4179ed22c18766000000020000000112d2f07672102dc6f099c4be308f598e4c4da1a7e0cb462ae14f0444525a1332000000006a47304402200a6a2f544f3f9d299608a7c745e2326de176fb1cac03ae3e74943f4250b8896e02205023a5b4faff99865bf91f1263605a502c723628be9240c0b7bec81d2ed106f101210227d85ba011276cf25b51df6a188b75e604b38770a462b2d0e9fb2fc839ef5d3ffeffffff0200ca9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac94166bee0000000017a914152cc82f7944f5c416de7dbffb052f7081765d7987660000000200000000010191e549a6cc852bbf1d3f11144b1a34079f64305e6971d2e685d2b40cd386e8a601000000171600147cc872ad7350c37fecab9c4c6d9f08aceb53bdb8feffffff02005ed0b20000000017a914aab1c8c53fe62e283a53efa28097709f4f2ed37b87e0bc9a3b000000001976a9142b4569203694fc997e13f2c0a1383b9e16c77a0d88ac0247304402201b4476f238ed5d515bfcd6927d0d008a4993770763eca73e3ee66f69971831d902200f5215a6dfd90391dd63462cfdf69804fe31224c309ec9c38d33a04dce71c0ee0121028c9d2955a95301b699db62e97d54bf0a91feb44e5cd94bbf5b62f1df57fb643966000000"
],
"mocktime": 1525107225,
"stats": [
@@ -111,7 +111,7 @@
"avgfee": 0,
"avgfeerate": 0,
"avgtxsize": 0,
- "blockhash": "1d7fe80f19d28b8e712af0399ac84006db753441f3033111b3a8d610afab364f",
+ "blockhash": "29a36876ddc6899a2541afc78ce2b3ca7659cfc01875e8208d9110d59bce3a9b",
"feerate_percentiles": [
0,
0,
@@ -142,14 +142,13 @@
"totalfee": 0,
"txs": 1,
"utxo_increase": 2,
- "utxo_size_inc": 173
+ "utxo_size_inc": 163
},
{
- "avgfee": 3760,
+ "avgfee": 4460,
"avgfeerate": 20,
- "avgtxsize": 187,
- "blockhash": "4e21a43675d7a41cb6b944e068c5bcd0a677baf658d9ebe021ae2d2f99397ccc",
- "height": 102,
+ "avgtxsize": 223,
+ "blockhash": "0aa1cae78efd1efcd5203366a257b6ccf4c9e4960f6b8a3724ad790ab568a10f",
"feerate_percentiles": [
20,
20,
@@ -157,35 +156,36 @@
20,
20
],
+ "height": 102,
"ins": 1,
- "maxfee": 3760,
+ "maxfee": 4460,
"maxfeerate": 20,
- "maxtxsize": 187,
- "medianfee": 3760,
+ "maxtxsize": 223,
+ "medianfee": 4460,
"mediantime": 1525107242,
- "mediantxsize": 187,
- "minfee": 3760,
+ "mediantxsize": 223,
+ "minfee": 4460,
"minfeerate": 20,
- "mintxsize": 187,
+ "mintxsize": 223,
"outs": 4,
"subsidy": 5000000000,
"swtotal_size": 0,
"swtotal_weight": 0,
"swtxs": 0,
"time": 1525107243,
- "total_out": 4999996240,
- "total_size": 187,
- "total_weight": 748,
- "totalfee": 3760,
+ "total_out": 4999995540,
+ "total_size": 223,
+ "total_weight": 892,
+ "totalfee": 4460,
"txs": 2,
"utxo_increase": 3,
- "utxo_size_inc": 234
+ "utxo_size_inc": 236
},
{
- "avgfee": 18960,
- "avgfeerate": 109,
- "avgtxsize": 228,
- "blockhash": "22d9b8b9c2a37c81515f3fc84f7241f6c07dbcea85ef16b00bcc33ae400a030f",
+ "avgfee": 24906,
+ "avgfeerate": 121,
+ "avgtxsize": 231,
+ "blockhash": "53e416e2538bc783c42a7aea566e884321afed893e9e58cf356d6429759dfa46",
"feerate_percentiles": [
20,
20,
@@ -195,28 +195,28 @@
],
"height": 103,
"ins": 3,
- "maxfee": 49800,
+ "maxfee": 66900,
"maxfeerate": 300,
- "maxtxsize": 248,
- "medianfee": 3760,
+ "maxtxsize": 249,
+ "medianfee": 4460,
"mediantime": 1525107243,
- "mediantxsize": 248,
- "minfee": 3320,
+ "mediantxsize": 223,
+ "minfee": 3360,
"minfeerate": 20,
- "mintxsize": 188,
+ "mintxsize": 223,
"outs": 8,
"subsidy": 5000000000,
- "swtotal_size": 496,
- "swtotal_weight": 1324,
- "swtxs": 2,
+ "swtotal_size": 249,
+ "swtotal_weight": 669,
+ "swtxs": 1,
"time": 1525107243,
- "total_out": 9999939360,
- "total_size": 684,
- "total_weight": 2076,
- "totalfee": 56880,
+ "total_out": 9999920820,
+ "total_size": 695,
+ "total_weight": 2453,
+ "totalfee": 74720,
"txs": 4,
"utxo_increase": 5,
- "utxo_size_inc": 380
+ "utxo_size_inc": 384
}
]
} \ No newline at end of file
diff --git a/test/functional/example_test.py b/test/functional/example_test.py
index f367e4fca8..a2726763d0 100755
--- a/test/functional/example_test.py
+++ b/test/functional/example_test.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""An example functional test
@@ -117,7 +117,7 @@ class ExampleTest(BitcoinTestFramework):
# sync_all() should not include node2, since we're not expecting it to
# sync.
connect_nodes(self.nodes[0], 1)
- self.sync_all([self.nodes[0:2]])
+ self.sync_all(self.nodes[0:2])
# Use setup_nodes() to customize the node start behaviour (for example if
# you don't want to start all nodes at the start of the test).
@@ -141,7 +141,7 @@ class ExampleTest(BitcoinTestFramework):
# Generating a block on one of the nodes will get us out of IBD
blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)]
- self.sync_all([self.nodes[0:2]])
+ self.sync_all(self.nodes[0:2])
# Notice above how we called an RPC by calling a method with the same
# name on the node object. Notice also how we used a keyword argument
diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py
index 0eb3dd440b..b7814bf33e 100755
--- a/test/functional/feature_assumevalid.py
+++ b/test/functional/feature_assumevalid.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test logic for skipping signature validation on old blocks.
@@ -32,7 +32,7 @@ Start three nodes:
import time
from test_framework.blocktools import (create_block, create_coinbase)
-from test_framework.key import CECKey
+from test_framework.key import ECKey
from test_framework.messages import (
CBlockHeader,
COutPoint,
@@ -104,9 +104,9 @@ class AssumeValidTest(BitcoinTestFramework):
self.blocks = []
# Get a pubkey for the coinbase TXO
- coinbase_key = CECKey()
- coinbase_key.set_secretbytes(b"horsebattery")
- coinbase_pubkey = coinbase_key.get_pubkey()
+ coinbase_key = ECKey()
+ coinbase_key.generate()
+ coinbase_pubkey = coinbase_key.get_pubkey().get_bytes()
# Create the first block with a coinbase output to our key
height = 1
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 8466f851ca..d38eca6cbe 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-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test BIP68 implementation."""
@@ -10,7 +10,13 @@ from test_framework.blocktools import create_block, create_coinbase, add_witness
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, get_bip9_status, satoshi_round, sync_blocks
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_raises_rpc_error,
+ get_bip9_status,
+ satoshi_round,
+)
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height)
@@ -63,7 +69,7 @@ class BIP68Test(BitcoinTestFramework):
self.nodes[0].sendtoaddress(new_addr, 2) # send 2 BTC
utxos = self.nodes[0].listunspent(0, 0)
- assert(len(utxos) > 0)
+ assert len(utxos) > 0
utxo = utxos[0]
@@ -253,7 +259,7 @@ class BIP68Test(BitcoinTestFramework):
self.nodes[0].generate(1)
cur_time += 600
- assert(tx2.hash in self.nodes[0].getrawmempool())
+ assert tx2.hash in self.nodes[0].getrawmempool()
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True)
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
@@ -264,23 +270,23 @@ class BIP68Test(BitcoinTestFramework):
# Advance the time on the node so that we can test timelocks
self.nodes[0].setmocktime(cur_time+600)
self.nodes[0].generate(1)
- assert(tx2.hash not in self.nodes[0].getrawmempool())
+ assert tx2.hash not in self.nodes[0].getrawmempool()
# Now that tx2 is not in the mempool, a sequence locked spend should
# succeed
tx3 = test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
- assert(tx3.hash in self.nodes[0].getrawmempool())
+ assert tx3.hash in self.nodes[0].getrawmempool()
self.nodes[0].generate(1)
- assert(tx3.hash not in self.nodes[0].getrawmempool())
+ assert tx3.hash not in self.nodes[0].getrawmempool()
# One more test, this time using height locks
tx4 = test_nonzero_locks(tx3, self.nodes[0], self.relayfee, use_height_lock=True)
- assert(tx4.hash in self.nodes[0].getrawmempool())
+ assert tx4.hash in self.nodes[0].getrawmempool()
# Now try combining confirmed and unconfirmed inputs
tx5 = test_nonzero_locks(tx4, self.nodes[0], self.relayfee, use_height_lock=True)
- assert(tx5.hash not in self.nodes[0].getrawmempool())
+ assert tx5.hash not in self.nodes[0].getrawmempool()
utxos = self.nodes[0].listunspent()
tx5.vin.append(CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["vout"]), nSequence=1))
@@ -299,8 +305,8 @@ class BIP68Test(BitcoinTestFramework):
# If we invalidate the tip, tx3 should get added to the mempool, causing
# tx4 to be removed (fails sequence-lock).
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
- assert(tx4.hash not in self.nodes[0].getrawmempool())
- assert(tx3.hash in self.nodes[0].getrawmempool())
+ assert tx4.hash not in self.nodes[0].getrawmempool()
+ assert tx3.hash in self.nodes[0].getrawmempool()
# Now mine 2 empty blocks to reorg out the current tip (labeled tip-1 in
# diagram above).
@@ -319,8 +325,8 @@ class BIP68Test(BitcoinTestFramework):
cur_time += 1
mempool = self.nodes[0].getrawmempool()
- assert(tx3.hash not in mempool)
- assert(tx2.hash in mempool)
+ assert tx3.hash not in mempool
+ assert tx2.hash in mempool
# Reset the chain and get rid of the mocktimed-blocks
self.nodes[0].setmocktime(0)
@@ -332,7 +338,7 @@ class BIP68Test(BitcoinTestFramework):
# being run, then it's possible the test has activated the soft fork, and
# this test should be moved to run earlier, or deleted.
def test_bip68_not_consensus(self):
- assert(get_bip9_status(self.nodes[0], 'csv')['status'] != 'active')
+ assert get_bip9_status(self.nodes[0], 'csv')['status'] != 'active'
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 2)
tx1 = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid))
@@ -372,7 +378,7 @@ class BIP68Test(BitcoinTestFramework):
add_witness_commitment(block)
block.solve()
- self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
+ self.nodes[0].submitblock(block.serialize().hex())
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
def activateCSV(self):
@@ -385,7 +391,7 @@ class BIP68Test(BitcoinTestFramework):
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "locked_in")
self.nodes[0].generate(1)
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "active")
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Use self.nodes[1] to test that version 2 transactions are standard.
def test_version2_relay(self):
diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py
index 5253ff7aaa..3ad83cd2b3 100755
--- a/test/functional/feature_block.py
+++ b/test/functional/feature_block.py
@@ -14,7 +14,7 @@ from test_framework.blocktools import (
get_legacy_sigopcount_block,
MAX_BLOCK_SIGOPS,
)
-from test_framework.key import CECKey
+from test_framework.key import ECKey
from test_framework.messages import (
CBlock,
COIN,
@@ -86,9 +86,9 @@ class FullBlockTest(BitcoinTestFramework):
self.bootstrap_p2p() # Add one p2p connection to the node
self.block_heights = {}
- self.coinbase_key = CECKey()
- self.coinbase_key.set_secretbytes(b"horsebattery")
- self.coinbase_pubkey = self.coinbase_key.get_pubkey()
+ self.coinbase_key = ECKey()
+ self.coinbase_key.generate()
+ self.coinbase_pubkey = self.coinbase_key.get_pubkey().get_bytes()
self.tip = None
self.blocks = {}
self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
@@ -98,7 +98,7 @@ class FullBlockTest(BitcoinTestFramework):
# Create a new block
b0 = self.next_block(0)
self.save_spendable_output()
- self.sync_blocks([b0])
+ self.send_blocks([b0])
# These constants chosen specifically to trigger an immature coinbase spend
# at a certain time below.
@@ -110,7 +110,7 @@ class FullBlockTest(BitcoinTestFramework):
for i in range(NUM_BUFFER_BLOCKS_TO_GENERATE):
blocks.append(self.next_block("maturitybuffer.{}".format(i)))
self.save_spendable_output()
- self.sync_blocks(blocks)
+ self.send_blocks(blocks)
# collect spendable outputs now to avoid cluttering the code later on
out = []
@@ -126,7 +126,7 @@ class FullBlockTest(BitcoinTestFramework):
b2 = self.next_block(2, spend=out[1])
self.save_spendable_output()
- self.sync_blocks([b1, b2], timeout=4)
+ self.send_blocks([b1, b2], timeout=4)
# Select a txn with an output eligible for spending. This won't actually be spent,
# since we're testing submission of a series of blocks with invalid txns.
@@ -146,23 +146,9 @@ class FullBlockTest(BitcoinTestFramework):
badtx = template.get_tx()
if TxTemplate != invalid_txs.InputMissing:
self.sign_tx(badtx, attempt_spend_tx)
- else:
- # Segwit is active in regtest at this point, so to deserialize a
- # transaction without any inputs correctly, we set the outputs
- # to an empty list. This is a hack, as the serialization of an
- # empty list of outputs is deserialized as flags==0 and thus
- # deserialization of the outputs is skipped.
- # A policy check requires "loose" txs to be of a minimum size,
- # so vtx is not set to be empty in the TxTemplate class and we
- # only apply the workaround where txs are not "loose", i.e. in
- # blocks.
- #
- # The workaround has the purpose that both sides calculate
- # the same tx hash in the merkle tree
- badtx.vout = []
badtx.rehash()
badblock = self.update_block(blockname, [badtx])
- self.sync_blocks(
+ self.send_blocks(
[badblock], success=False,
reject_reason=(template.block_reject_reason or template.reject_reason),
reconnect=True, timeout=2)
@@ -179,7 +165,7 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(1)
b3 = self.next_block(3, spend=out[1])
txout_b3 = b3.vtx[1]
- self.sync_blocks([b3], False)
+ self.send_blocks([b3], False)
# Now we add another block to make the alternative chain longer.
#
@@ -187,7 +173,7 @@ class FullBlockTest(BitcoinTestFramework):
# \-> b3 (1) -> b4 (2)
self.log.info("Reorg to a longer chain")
b4 = self.next_block(4, spend=out[2])
- self.sync_blocks([b4])
+ self.send_blocks([b4])
# ... and back to the first chain.
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -195,11 +181,11 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(2)
b5 = self.next_block(5, spend=out[2])
self.save_spendable_output()
- self.sync_blocks([b5], False)
+ self.send_blocks([b5], False)
self.log.info("Reorg back to the original chain")
b6 = self.next_block(6, spend=out[3])
- self.sync_blocks([b6], True)
+ self.send_blocks([b6], True)
# Try to create a fork that double-spends
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -208,10 +194,10 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a chain with a double spend, even if it is longer")
self.move_tip(5)
b7 = self.next_block(7, spend=out[2])
- self.sync_blocks([b7], False)
+ self.send_blocks([b7], False)
b8 = self.next_block(8, spend=out[4])
- self.sync_blocks([b8], False, reconnect=True)
+ self.send_blocks([b8], False, reconnect=True)
# Try to create a block that has too much fee
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -220,7 +206,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block where the miner creates too much coinbase reward")
self.move_tip(6)
b9 = self.next_block(9, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)
+ self.send_blocks([b9], success=False, reject_reason='bad-cb-amount', reconnect=True)
# Create a fork that ends in a block with too much fee (the one that causes the reorg)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -229,10 +215,10 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a chain where the miner creates too much coinbase reward, even if the chain is longer")
self.move_tip(5)
b10 = self.next_block(10, spend=out[3])
- self.sync_blocks([b10], False)
+ self.send_blocks([b10], False)
b11 = self.next_block(11, spend=out[4], additional_coinbase_value=1)
- self.sync_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)
+ self.send_blocks([b11], success=False, reject_reason='bad-cb-amount', reconnect=True)
# Try again, but with a valid fork first
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -245,7 +231,7 @@ class FullBlockTest(BitcoinTestFramework):
b13 = self.next_block(13, spend=out[4])
self.save_spendable_output()
b14 = self.next_block(14, spend=out[5], additional_coinbase_value=1)
- self.sync_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)
+ self.send_blocks([b12, b13, b14], success=False, reject_reason='bad-cb-amount', reconnect=True)
# New tip should be b13.
assert_equal(node.getbestblockhash(), b13.hash)
@@ -259,12 +245,12 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(13)
b15 = self.next_block(15, spend=out[5], script=lots_of_checksigs)
self.save_spendable_output()
- self.sync_blocks([b15], True)
+ self.send_blocks([b15], True)
self.log.info("Reject a block with too many checksigs")
too_many_checksigs = CScript([OP_CHECKSIG] * (MAX_BLOCK_SIGOPS))
b16 = self.next_block(16, spend=out[6], script=too_many_checksigs)
- self.sync_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b16], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# Attempt to spend a transaction created on a different fork
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -273,7 +259,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with a spend from a re-org'ed out tx")
self.move_tip(15)
b17 = self.next_block(17, spend=txout_b3)
- self.sync_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b17], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a transaction created on a different fork (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -283,10 +269,10 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block with a spend from a re-org'ed out tx (on a forked chain)")
self.move_tip(13)
b18 = self.next_block(18, spend=txout_b3)
- self.sync_blocks([b18], False)
+ self.send_blocks([b18], False)
b19 = self.next_block(19, spend=out[6])
- self.sync_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b19], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to spend a coinbase at depth too low
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -295,7 +281,7 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block spending an immature coinbase.")
self.move_tip(15)
b20 = self.next_block(20, spend=out[7])
- self.sync_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
+ self.send_blocks([b20], success=False, reject_reason='bad-txns-premature-spend-of-coinbase', reconnect=True)
# Attempt to spend a coinbase at depth too low (on a fork this time)
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -305,10 +291,10 @@ class FullBlockTest(BitcoinTestFramework):
self.log.info("Reject a block spending an immature coinbase (on a forked chain)")
self.move_tip(13)
b21 = self.next_block(21, spend=out[6])
- self.sync_blocks([b21], False)
+ self.send_blocks([b21], False)
b22 = self.next_block(22, spend=out[5])
- self.sync_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase')
+ self.send_blocks([b22], success=False, reject_reason='bad-txns-premature-spend-of-coinbase', reconnect=True)
# Create a block on either side of MAX_BLOCK_BASE_SIZE and make sure its accepted/rejected
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -326,7 +312,7 @@ class FullBlockTest(BitcoinTestFramework):
b23 = self.update_block(23, [tx])
# Make sure the math above worked out to produce a max-sized block
assert_equal(len(b23.serialize()), MAX_BLOCK_BASE_SIZE)
- self.sync_blocks([b23], True)
+ self.send_blocks([b23], True)
self.save_spendable_output()
self.log.info("Reject a block of size MAX_BLOCK_BASE_SIZE + 1")
@@ -337,10 +323,10 @@ class FullBlockTest(BitcoinTestFramework):
tx.vout = [CTxOut(0, script_output)]
b24 = self.update_block(24, [tx])
assert_equal(len(b24.serialize()), MAX_BLOCK_BASE_SIZE + 1)
- self.sync_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)
+ self.send_blocks([b24], success=False, reject_reason='bad-blk-length', reconnect=True)
b25 = self.next_block(25, spend=out[7])
- self.sync_blocks([b25], False)
+ self.send_blocks([b25], False)
# Create blocks with a coinbase input script size out of range
# genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3)
@@ -355,11 +341,11 @@ class FullBlockTest(BitcoinTestFramework):
# update_block causes the merkle root to get updated, even with no new
# transactions, and updates the required state.
b26 = self.update_block(26, [])
- self.sync_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)
+ self.send_blocks([b26], success=False, reject_reason='bad-cb-length', reconnect=True)
# Extend the b26 chain to make sure bitcoind isn't accepting b26
b27 = self.next_block(27, spend=out[7])
- self.sync_blocks([b27], False)
+ self.send_blocks([b27], False)
# Now try a too-large-coinbase script
self.move_tip(15)
@@ -367,11 +353,11 @@ class FullBlockTest(BitcoinTestFramework):
b28.vtx[0].vin[0].scriptSig = b'\x00' * 101
b28.vtx[0].rehash()
b28 = self.update_block(28, [])
- self.sync_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)
+ self.send_blocks([b28], success=False, reject_reason='bad-cb-length', reconnect=True)
# Extend the b28 chain to make sure bitcoind isn't accepting b28
b29 = self.next_block(29, spend=out[7])
- self.sync_blocks([b29], False)
+ self.send_blocks([b29], False)
# b30 has a max-sized coinbase scriptSig.
self.move_tip(23)
@@ -379,7 +365,7 @@ class FullBlockTest(BitcoinTestFramework):
b30.vtx[0].vin[0].scriptSig = b'\x00' * 100
b30.vtx[0].rehash()
b30 = self.update_block(30, [])
- self.sync_blocks([b30], True)
+ self.send_blocks([b30], True)
self.save_spendable_output()
# b31 - b35 - check sigops of OP_CHECKMULTISIG / OP_CHECKMULTISIGVERIFY / OP_CHECKSIGVERIFY
@@ -395,7 +381,7 @@ class FullBlockTest(BitcoinTestFramework):
lots_of_multisigs = CScript([OP_CHECKMULTISIG] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)
b31 = self.next_block(31, spend=out[8], script=lots_of_multisigs)
assert_equal(get_legacy_sigopcount_block(b31), MAX_BLOCK_SIGOPS)
- self.sync_blocks([b31], True)
+ self.send_blocks([b31], True)
self.save_spendable_output()
# this goes over the limit because the coinbase has one sigop
@@ -403,33 +389,33 @@ class FullBlockTest(BitcoinTestFramework):
too_many_multisigs = CScript([OP_CHECKMULTISIG] * (MAX_BLOCK_SIGOPS // 20))
b32 = self.next_block(32, spend=out[9], script=too_many_multisigs)
assert_equal(get_legacy_sigopcount_block(b32), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b32], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# CHECKMULTISIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKMULTISIGVERIFY sigops")
self.move_tip(31)
lots_of_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * ((MAX_BLOCK_SIGOPS - 1) // 20) + [OP_CHECKSIG] * 19)
b33 = self.next_block(33, spend=out[9], script=lots_of_multisigs)
- self.sync_blocks([b33], True)
+ self.send_blocks([b33], True)
self.save_spendable_output()
self.log.info("Reject a block with too many OP_CHECKMULTISIGVERIFY sigops")
too_many_multisigs = CScript([OP_CHECKMULTISIGVERIFY] * (MAX_BLOCK_SIGOPS // 20))
b34 = self.next_block(34, spend=out[10], script=too_many_multisigs)
- self.sync_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b34], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# CHECKSIGVERIFY
self.log.info("Accept a block with the max number of OP_CHECKSIGVERIFY sigops")
self.move_tip(33)
lots_of_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS - 1))
b35 = self.next_block(35, spend=out[10], script=lots_of_checksigs)
- self.sync_blocks([b35], True)
+ self.send_blocks([b35], True)
self.save_spendable_output()
self.log.info("Reject a block with too many OP_CHECKSIGVERIFY sigops")
too_many_checksigs = CScript([OP_CHECKSIGVERIFY] * (MAX_BLOCK_SIGOPS))
b36 = self.next_block(36, spend=out[11], script=too_many_checksigs)
- self.sync_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b36], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# Check spending of a transaction in a block which failed to connect
#
@@ -446,12 +432,12 @@ class FullBlockTest(BitcoinTestFramework):
txout_b37 = b37.vtx[1]
tx = self.create_and_sign_transaction(out[11], 0)
b37 = self.update_block(37, [tx])
- self.sync_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b37], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid
self.move_tip(35)
b38 = self.next_block(38, spend=txout_b37)
- self.sync_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b38], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Check P2SH SigOp counting
#
@@ -501,7 +487,7 @@ class FullBlockTest(BitcoinTestFramework):
b39_outputs += 1
b39 = self.update_block(39, [])
- self.sync_blocks([b39], True)
+ self.send_blocks([b39], True)
self.save_spendable_output()
# Test sigops in P2SH redeem scripts
@@ -528,7 +514,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(b39.vtx[i].sha256, 0), b''))
# Note: must pass the redeem_script (not p2sh_script) to the signature hash function
(sighash, err) = SignatureHash(redeem_script, tx, 1, SIGHASH_ALL)
- sig = self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))
+ sig = self.coinbase_key.sign_ecdsa(sighash) + bytes(bytearray([SIGHASH_ALL]))
scriptSig = CScript([sig, redeem_script])
tx.vin[1].scriptSig = scriptSig
@@ -543,7 +529,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.rehash()
new_txs.append(tx)
self.update_block(40, new_txs)
- self.sync_blocks([b40], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b40], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# same as b40, but one less sigop
self.log.info("Accept a block with the max number of P2SH sigops")
@@ -556,7 +542,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vout.append(CTxOut(1, CScript([OP_CHECKSIG] * b41_sigops_to_fill)))
tx.rehash()
self.update_block(41, [tx])
- self.sync_blocks([b41], True)
+ self.send_blocks([b41], True)
# Fork off of b39 to create a constant base again
#
@@ -569,7 +555,7 @@ class FullBlockTest(BitcoinTestFramework):
b43 = self.next_block(43, spend=out[13])
self.save_spendable_output()
- self.sync_blocks([b42, b43], True)
+ self.send_blocks([b42, b43], True)
# Test a number of really invalid scenarios
#
@@ -591,7 +577,7 @@ class FullBlockTest(BitcoinTestFramework):
self.tip = b44
self.block_heights[b44.sha256] = height
self.blocks[44] = b44
- self.sync_blocks([b44], True)
+ self.send_blocks([b44], True)
self.log.info("Reject a block with a non-coinbase as the first tx")
non_coinbase = self.create_tx(out[15], 0, 1)
@@ -606,7 +592,7 @@ class FullBlockTest(BitcoinTestFramework):
self.block_heights[b45.sha256] = self.block_heights[self.tip.sha256] + 1
self.tip = b45
self.blocks[45] = b45
- self.sync_blocks([b45], success=False, reject_reason='bad-cb-missing', reconnect=True)
+ self.send_blocks([b45], success=False, reject_reason='bad-cb-missing', reconnect=True)
self.log.info("Reject a block with no transactions")
self.move_tip(44)
@@ -621,7 +607,7 @@ class FullBlockTest(BitcoinTestFramework):
self.tip = b46
assert 46 not in self.blocks
self.blocks[46] = b46
- self.sync_blocks([b46], success=False, reject_reason='bad-blk-length', reconnect=True)
+ self.send_blocks([b46], success=False, reject_reason='bad-blk-length', reconnect=True)
self.log.info("Reject a block with invalid work")
self.move_tip(44)
@@ -630,35 +616,35 @@ class FullBlockTest(BitcoinTestFramework):
while b47.sha256 < target:
b47.nNonce += 1
b47.rehash()
- self.sync_blocks([b47], False, force_send=True, reject_reason='high-hash')
+ self.send_blocks([b47], False, force_send=True, reject_reason='high-hash', reconnect=True)
self.log.info("Reject a block with a timestamp >2 hours in the future")
self.move_tip(44)
b48 = self.next_block(48, solve=False)
b48.nTime = int(time.time()) + 60 * 60 * 3
b48.solve()
- self.sync_blocks([b48], False, force_send=True, reject_reason='time-too-new')
+ self.send_blocks([b48], False, force_send=True, reject_reason='time-too-new')
self.log.info("Reject a block with invalid merkle hash")
self.move_tip(44)
b49 = self.next_block(49)
b49.hashMerkleRoot += 1
b49.solve()
- self.sync_blocks([b49], success=False, reject_reason='bad-txnmrklroot', reconnect=True)
+ self.send_blocks([b49], success=False, reject_reason='bad-txnmrklroot', reconnect=True)
self.log.info("Reject a block with incorrect POW limit")
self.move_tip(44)
b50 = self.next_block(50)
b50.nBits = b50.nBits - 1
b50.solve()
- self.sync_blocks([b50], False, force_send=True, reject_reason='bad-diffbits', reconnect=True)
+ self.send_blocks([b50], False, force_send=True, reject_reason='bad-diffbits', reconnect=True)
self.log.info("Reject a block with two coinbase transactions")
self.move_tip(44)
b51 = self.next_block(51)
cb2 = create_coinbase(51, self.coinbase_pubkey)
b51 = self.update_block(51, [cb2])
- self.sync_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)
+ self.send_blocks([b51], success=False, reject_reason='bad-cb-multiple', reconnect=True)
self.log.info("Reject a block with duplicate transactions")
# Note: txns have to be in the right position in the merkle tree to trigger this error
@@ -666,7 +652,7 @@ class FullBlockTest(BitcoinTestFramework):
b52 = self.next_block(52, spend=out[15])
tx = self.create_tx(b52.vtx[1], 0, 1)
b52 = self.update_block(52, [tx, tx])
- self.sync_blocks([b52], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
+ self.send_blocks([b52], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
# Test block timestamps
# -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15)
@@ -674,21 +660,21 @@ class FullBlockTest(BitcoinTestFramework):
#
self.move_tip(43)
b53 = self.next_block(53, spend=out[14])
- self.sync_blocks([b53], False)
+ self.send_blocks([b53], False)
self.save_spendable_output()
self.log.info("Reject a block with timestamp before MedianTimePast")
b54 = self.next_block(54, spend=out[15])
b54.nTime = b35.nTime - 1
b54.solve()
- self.sync_blocks([b54], False, force_send=True, reject_reason='time-too-old')
+ self.send_blocks([b54], False, force_send=True, reject_reason='time-too-old', reconnect=True)
# valid timestamp
self.move_tip(53)
b55 = self.next_block(55, spend=out[15])
b55.nTime = b35.nTime
self.update_block(55, [])
- self.sync_blocks([b55], True)
+ self.send_blocks([b55], True)
self.save_spendable_output()
# Test Merkle tree malleability
@@ -733,7 +719,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(len(b56.vtx), 3)
b56 = self.update_block(56, [tx1])
assert_equal(b56.hash, b57.hash)
- self.sync_blocks([b56], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
+ self.send_blocks([b56], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
# b57p2 - a good block with 6 tx'es, don't submit until end
self.move_tip(55)
@@ -753,13 +739,13 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(b56p2.hash, b57p2.hash)
assert_equal(len(b56p2.vtx), 6)
b56p2 = self.update_block("b56p2", [tx3, tx4])
- self.sync_blocks([b56p2], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
+ self.send_blocks([b56p2], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
self.move_tip("57p2")
- self.sync_blocks([b57p2], True)
+ self.send_blocks([b57p2], True)
self.move_tip(57)
- self.sync_blocks([b57], False) # The tip is not updated because 57p2 seen first
+ self.send_blocks([b57], False) # The tip is not updated because 57p2 seen first
self.save_spendable_output()
# Test a few invalid tx types
@@ -773,12 +759,12 @@ class FullBlockTest(BitcoinTestFramework):
self.move_tip(57)
b58 = self.next_block(58, spend=out[17])
tx = CTransaction()
- assert(len(out[17].vout) < 42)
+ assert len(out[17].vout) < 42
tx.vin.append(CTxIn(COutPoint(out[17].sha256, 42), CScript([OP_TRUE]), 0xffffffff))
tx.vout.append(CTxOut(0, b""))
tx.calc_sha256()
b58 = self.update_block(58, [tx])
- self.sync_blocks([b58], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b58], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# tx with output value > input value
self.log.info("Reject a block with a transaction with outputs > inputs")
@@ -786,12 +772,12 @@ class FullBlockTest(BitcoinTestFramework):
b59 = self.next_block(59)
tx = self.create_and_sign_transaction(out[17], 51 * COIN)
b59 = self.update_block(59, [tx])
- self.sync_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)
+ self.send_blocks([b59], success=False, reject_reason='bad-txns-in-belowout', reconnect=True)
# reset to good chain
self.move_tip(57)
b60 = self.next_block(60, spend=out[17])
- self.sync_blocks([b60], True)
+ self.send_blocks([b60], True)
self.save_spendable_output()
# Test BIP30
@@ -810,7 +796,7 @@ class FullBlockTest(BitcoinTestFramework):
b61.vtx[0].rehash()
b61 = self.update_block(61, [])
assert_equal(b60.vtx[0].serialize(), b61.vtx[0].serialize())
- self.sync_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)
+ self.send_blocks([b61], success=False, reject_reason='bad-txns-BIP30', reconnect=True)
# Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests)
#
@@ -824,10 +810,10 @@ class FullBlockTest(BitcoinTestFramework):
tx.nLockTime = 0xffffffff # this locktime is non-final
tx.vin.append(CTxIn(COutPoint(out[18].sha256, 0))) # don't set nSequence
tx.vout.append(CTxOut(0, CScript([OP_TRUE])))
- assert(tx.vin[0].nSequence < 0xffffffff)
+ assert tx.vin[0].nSequence < 0xffffffff
tx.calc_sha256()
b62 = self.update_block(62, [tx])
- self.sync_blocks([b62], success=False, reject_reason='bad-txns-nonfinal')
+ self.send_blocks([b62], success=False, reject_reason='bad-txns-nonfinal', reconnect=True)
# Test a non-final coinbase is also rejected
#
@@ -841,7 +827,7 @@ class FullBlockTest(BitcoinTestFramework):
b63.vtx[0].vin[0].nSequence = 0xDEADBEEF
b63.vtx[0].rehash()
b63 = self.update_block(63, [])
- self.sync_blocks([b63], success=False, reject_reason='bad-txns-nonfinal')
+ self.send_blocks([b63], success=False, reject_reason='bad-txns-nonfinal', reconnect=True)
# This checks that a block with a bloated VARINT between the block_header and the array of tx such that
# the block is > MAX_BLOCK_BASE_SIZE with the bloated varint, but <= MAX_BLOCK_BASE_SIZE without the bloated varint,
@@ -875,7 +861,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
b64a = self.update_block("64a", [tx])
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
- self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()')
+ self.send_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize()')
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
# resend the header message, it won't send us the getdata message again. Just
@@ -891,7 +877,7 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(len(b64.serialize()), MAX_BLOCK_BASE_SIZE)
self.blocks[64] = b64
b64 = self.update_block(64, [])
- self.sync_blocks([b64], True)
+ self.send_blocks([b64], True)
self.save_spendable_output()
# Spend an output created in the block itself
@@ -904,7 +890,7 @@ class FullBlockTest(BitcoinTestFramework):
tx1 = self.create_and_sign_transaction(out[19], out[19].vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 0)
b65 = self.update_block(65, [tx1, tx2])
- self.sync_blocks([b65], True)
+ self.send_blocks([b65], True)
self.save_spendable_output()
# Attempt to spend an output created later in the same block
@@ -917,7 +903,7 @@ class FullBlockTest(BitcoinTestFramework):
tx1 = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue)
tx2 = self.create_and_sign_transaction(tx1, 1)
b66 = self.update_block(66, [tx2, tx1])
- self.sync_blocks([b66], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b66], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Attempt to double-spend a transaction created in a block
#
@@ -932,7 +918,7 @@ class FullBlockTest(BitcoinTestFramework):
tx2 = self.create_and_sign_transaction(tx1, 1)
tx3 = self.create_and_sign_transaction(tx1, 2)
b67 = self.update_block(67, [tx1, tx2, tx3])
- self.sync_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b67], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# More tests of block subsidy
#
@@ -951,14 +937,14 @@ class FullBlockTest(BitcoinTestFramework):
b68 = self.next_block(68, additional_coinbase_value=10)
tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 9)
b68 = self.update_block(68, [tx])
- self.sync_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)
+ self.send_blocks([b68], success=False, reject_reason='bad-cb-amount', reconnect=True)
self.log.info("Accept a block claiming the correct subsidy in the coinbase transaction")
self.move_tip(65)
b69 = self.next_block(69, additional_coinbase_value=10)
tx = self.create_and_sign_transaction(out[20], out[20].vout[0].nValue - 10)
self.update_block(69, [tx])
- self.sync_blocks([b69], True)
+ self.send_blocks([b69], True)
self.save_spendable_output()
# Test spending the outpoint of a non-existent transaction
@@ -975,7 +961,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(bogus_tx.sha256, 0), b"", 0xffffffff))
tx.vout.append(CTxOut(1, b""))
b70 = self.update_block(70, [tx])
- self.sync_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b70], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
# Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks)
#
@@ -1000,10 +986,10 @@ class FullBlockTest(BitcoinTestFramework):
assert_equal(b72.sha256, b71.sha256)
self.move_tip(71)
- self.sync_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
+ self.send_blocks([b71], success=False, reject_reason='bad-txns-duplicate', reconnect=True)
self.move_tip(72)
- self.sync_blocks([b72], True)
+ self.send_blocks([b72], True)
self.save_spendable_output()
# Test some invalid scripts and MAX_BLOCK_SIGOPS
@@ -1038,7 +1024,7 @@ class FullBlockTest(BitcoinTestFramework):
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b73 = self.update_block(73, [tx])
assert_equal(get_legacy_sigopcount_block(b73), MAX_BLOCK_SIGOPS + 1)
- self.sync_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b73], success=False, reject_reason='bad-blk-sigops', reconnect=True)
# b74/75 - if we push an invalid script element, all previous sigops are counted,
# but sigops after the element are not counted.
@@ -1062,7 +1048,7 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS + 4] = 0xff
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b74 = self.update_block(74, [tx])
- self.sync_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)
+ self.send_blocks([b74], success=False, reject_reason='bad-blk-sigops', reconnect=True)
self.move_tip(72)
b75 = self.next_block(75)
@@ -1075,7 +1061,7 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS + 3] = 0xff
tx = self.create_and_sign_transaction(out[22], 1, CScript(a))
b75 = self.update_block(75, [tx])
- self.sync_blocks([b75], True)
+ self.send_blocks([b75], True)
self.save_spendable_output()
# Check that if we push an element filled with CHECKSIGs, they are not counted
@@ -1086,7 +1072,7 @@ class FullBlockTest(BitcoinTestFramework):
a[MAX_BLOCK_SIGOPS - 1] = 0x4e # PUSHDATA4, but leave the following bytes as just checksigs
tx = self.create_and_sign_transaction(out[23], 1, CScript(a))
b76 = self.update_block(76, [tx])
- self.sync_blocks([b76], True)
+ self.send_blocks([b76], True)
self.save_spendable_output()
# Test transaction resurrection
@@ -1111,40 +1097,40 @@ class FullBlockTest(BitcoinTestFramework):
b77 = self.next_block(77)
tx77 = self.create_and_sign_transaction(out[24], 10 * COIN)
b77 = self.update_block(77, [tx77])
- self.sync_blocks([b77], True)
+ self.send_blocks([b77], True)
self.save_spendable_output()
b78 = self.next_block(78)
tx78 = self.create_tx(tx77, 0, 9 * COIN)
b78 = self.update_block(78, [tx78])
- self.sync_blocks([b78], True)
+ self.send_blocks([b78], True)
b79 = self.next_block(79)
tx79 = self.create_tx(tx78, 0, 8 * COIN)
b79 = self.update_block(79, [tx79])
- self.sync_blocks([b79], True)
+ self.send_blocks([b79], True)
# mempool should be empty
assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.move_tip(77)
b80 = self.next_block(80, spend=out[25])
- self.sync_blocks([b80], False, force_send=True)
+ self.send_blocks([b80], False, force_send=True)
self.save_spendable_output()
b81 = self.next_block(81, spend=out[26])
- self.sync_blocks([b81], False, force_send=True) # other chain is same length
+ self.send_blocks([b81], False, force_send=True) # other chain is same length
self.save_spendable_output()
b82 = self.next_block(82, spend=out[27])
- self.sync_blocks([b82], True) # now this chain is longer, triggers re-org
+ self.send_blocks([b82], True) # now this chain is longer, triggers re-org
self.save_spendable_output()
# now check that tx78 and tx79 have been put back into the peer's mempool
mempool = self.nodes[0].getrawmempool()
assert_equal(len(mempool), 2)
- assert(tx78.hash in mempool)
- assert(tx79.hash in mempool)
+ assert tx78.hash in mempool
+ assert tx79.hash in mempool
# Test invalid opcodes in dead execution paths.
#
@@ -1161,7 +1147,7 @@ class FullBlockTest(BitcoinTestFramework):
tx2.rehash()
b83 = self.update_block(83, [tx1, tx2])
- self.sync_blocks([b83], True)
+ self.send_blocks([b83], True)
self.save_spendable_output()
# Reorg on/off blocks that have OP_RETURN in them (and try to spend them)
@@ -1188,30 +1174,30 @@ class FullBlockTest(BitcoinTestFramework):
tx5 = self.create_tx(tx1, 4, 0, CScript([OP_RETURN]))
b84 = self.update_block(84, [tx1, tx2, tx3, tx4, tx5])
- self.sync_blocks([b84], True)
+ self.send_blocks([b84], True)
self.save_spendable_output()
self.move_tip(83)
b85 = self.next_block(85, spend=out[29])
- self.sync_blocks([b85], False) # other chain is same length
+ self.send_blocks([b85], False) # other chain is same length
b86 = self.next_block(86, spend=out[30])
- self.sync_blocks([b86], True)
+ self.send_blocks([b86], True)
self.move_tip(84)
b87 = self.next_block(87, spend=out[30])
- self.sync_blocks([b87], False) # other chain is same length
+ self.send_blocks([b87], False) # other chain is same length
self.save_spendable_output()
b88 = self.next_block(88, spend=out[31])
- self.sync_blocks([b88], True)
+ self.send_blocks([b88], True)
self.save_spendable_output()
# trying to spend the OP_RETURN output is rejected
b89a = self.next_block("89a", spend=out[32])
tx = self.create_tx(tx1, 0, 0, CScript([OP_TRUE]))
b89a = self.update_block("89a", [tx])
- self.sync_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
+ self.send_blocks([b89a], success=False, reject_reason='bad-txns-inputs-missingorspent', reconnect=True)
self.log.info("Test a re-org of one week's worth of blocks (1088 blocks)")
@@ -1232,7 +1218,7 @@ class FullBlockTest(BitcoinTestFramework):
self.save_spendable_output()
spend = self.get_spendable_output()
- self.sync_blocks(blocks, True, timeout=480)
+ self.send_blocks(blocks, True, timeout=480)
chain1_tip = i
# now create alt chain of same length
@@ -1240,22 +1226,22 @@ class FullBlockTest(BitcoinTestFramework):
blocks2 = []
for i in range(89, LARGE_REORG_SIZE + 89):
blocks2.append(self.next_block("alt" + str(i), version=4))
- self.sync_blocks(blocks2, False, force_send=True)
+ self.send_blocks(blocks2, False, force_send=True)
# extend alt chain to trigger re-org
block = self.next_block("alt" + str(chain1_tip + 1), version=4)
- self.sync_blocks([block], True, timeout=480)
+ self.send_blocks([block], True, timeout=480)
# ... and re-org back to the first chain
self.move_tip(chain1_tip)
block = self.next_block(chain1_tip + 1, version=4)
- self.sync_blocks([block], False, force_send=True)
+ self.send_blocks([block], False, force_send=True)
block = self.next_block(chain1_tip + 2, version=4)
- self.sync_blocks([block], True, timeout=480)
+ self.send_blocks([block], True, timeout=480)
self.log.info("Reject a block with an invalid block header version")
b_v1 = self.next_block('b_v1', version=1)
- self.sync_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)')
+ self.send_blocks([b_v1], success=False, force_send=True, reject_reason='bad-version(0x00000001)', reconnect=True)
self.move_tip(chain1_tip + 2)
b_cb34 = self.next_block('b_cb34', version=4)
@@ -1263,7 +1249,7 @@ class FullBlockTest(BitcoinTestFramework):
b_cb34.vtx[0].rehash()
b_cb34.hashMerkleRoot = b_cb34.calc_merkle_root()
b_cb34.solve()
- self.sync_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True)
+ self.send_blocks([b_cb34], success=False, reject_reason='bad-cb-height', reconnect=True)
# Helper methods
################
@@ -1284,7 +1270,7 @@ class FullBlockTest(BitcoinTestFramework):
tx.vin[0].scriptSig = CScript()
return
(sighash, err) = SignatureHash(spend_tx.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL)
- tx.vin[0].scriptSig = CScript([self.coinbase_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL]))])
+ tx.vin[0].scriptSig = CScript([self.coinbase_key.sign_ecdsa(sighash) + bytes(bytearray([SIGHASH_ALL]))])
def create_and_sign_transaction(self, spend_tx, value, script=CScript([OP_TRUE])):
tx = self.create_tx(spend_tx, 0, value, script)
@@ -1372,7 +1358,7 @@ class FullBlockTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
self.bootstrap_p2p(timeout=timeout)
- def sync_blocks(self, blocks, success=True, reject_reason=None, force_send=False, reconnect=False, timeout=60):
+ def send_blocks(self, blocks, success=True, reject_reason=None, force_send=False, reconnect=False, timeout=60):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
Call with success = False if the tip shouldn't advance to the most recent block."""
diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py
index 96c5e49b0e..b16eafccca 100755
--- a/test/functional/feature_cltv.py
+++ b/test/functional/feature_cltv.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test BIP65 (CHECKLOCKTIMEVERIFY).
@@ -15,7 +15,6 @@ from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, O
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- bytes_to_hex_str,
hex_str_to_bytes,
)
@@ -114,7 +113,7 @@ class BIP65Test(BitcoinTestFramework):
# rejected from the mempool for exactly that reason.
assert_equal(
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Negative locktime)'}],
- self.nodes[0].testmempoolaccept(rawtxs=[bytes_to_hex_str(spendtx.serialize())], allowhighfees=True)
+ 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 460e664c48..f0d6bc21e6 100755
--- a/test/functional/feature_config_args.py
+++ b/test/functional/feature_config_args.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test various command line arguments and configuration file parameters."""
@@ -21,10 +21,24 @@ class ConfArgsTest(BitcoinTestFramework):
with open(os.path.join(self.nodes[0].datadir, 'bitcoin.conf'), 'a', encoding='utf-8') as conf:
conf.write('includeconf={}\n'.format(inc_conf_file_path))
+ self.nodes[0].assert_start_raises_init_error(
+ expected_msg='Error parsing command line arguments: Invalid parameter -dash_cli',
+ extra_args=['-dash_cli=1'],
+ )
+ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
+ conf.write('dash_conf=1\n')
+ with self.nodes[0].assert_debug_log(expected_msgs=['Ignoring unknown configuration value dash_conf']):
+ self.start_node(0)
+ self.stop_node(0)
+
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('-dash=1\n')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -')
+ with open(inc_conf_file_path, 'w', encoding='utf8') as conf:
+ conf.write("wallet=foo\n")
+ self.nodes[0].assert_start_raises_init_error(expected_msg='Error: Config setting for -wallet only applied on regtest network when in [regtest] section.')
+
with open(inc_conf_file_path, 'w', encoding='utf-8') as conf:
conf.write('nono\n')
self.nodes[0].assert_start_raises_init_error(expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead')
@@ -57,9 +71,16 @@ class ConfArgsTest(BitcoinTestFramework):
with open(inc_conf_file2_path, 'w', encoding='utf-8') as conf:
conf.write('') # clear
+ def test_log_buffer(self):
+ with self.nodes[0].assert_debug_log(expected_msgs=['Warning: parsed potentially confusing double-negative -connect=0']):
+ self.start_node(0, extra_args=['-noconnect=0'])
+ self.stop_node(0)
+
def run_test(self):
self.stop_node(0)
+ self.test_log_buffer()
+
self.test_config_file_parser()
# Remove the -datadir argument so it doesn't override the config file
diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py
index df79c4312c..887e9dafa3 100755
--- a/test/functional/feature_csv_activation.py
+++ b/test/functional/feature_csv_activation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test activation of the first version bits soft fork.
@@ -106,7 +106,7 @@ def send_generic_input_tx(node, coinbases, address):
def create_bip68txs(node, bip68inputs, txversion, address, locktime_delta=0):
"""Returns a list of bip68 transactions with different bits set."""
txs = []
- assert(len(bip68inputs) >= 16)
+ assert len(bip68inputs) >= 16
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
locktime = relative_locktime(sdf, srhb, stf, srlb)
tx = create_transaction(node, bip68inputs[i], address, amount=Decimal("49.98"))
@@ -121,7 +121,7 @@ def create_bip68txs(node, bip68inputs, txversion, address, locktime_delta=0):
def create_bip112txs(node, bip112inputs, varyOP_CSV, txversion, address, locktime_delta=0):
"""Returns a list of bip68 transactions with different bits set."""
txs = []
- assert(len(bip112inputs) >= 16)
+ assert len(bip112inputs) >= 16
for i, (sdf, srhb, stf, srlb) in enumerate(product(*[[True, False]] * 4)):
locktime = relative_locktime(sdf, srhb, stf, srlb)
tx = create_transaction(node, bip112inputs[i], address, amount=Decimal("49.98"))
@@ -168,7 +168,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
block.solve()
return block
- def sync_blocks(self, blocks, success=True):
+ def send_blocks(self, blocks, success=True):
"""Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block.
Call with success = False if the tip shouldn't advance to the most recent block."""
@@ -190,7 +190,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
self.log.info("Test that the csv softfork is DEFINED")
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'defined')
test_blocks = self.generate_blocks(61, 4)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
self.log.info("Advance from DEFINED to STARTED, height = 143")
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started')
@@ -202,7 +202,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
test_blocks = self.generate_blocks(20, 4, test_blocks) # 0x00000004 (signalling not)
test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready)
test_blocks = self.generate_blocks(24, 536936448, test_blocks) # 0x20010000 (signalling not)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
self.log.info("Failed to advance past STARTED, height = 287")
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'started')
@@ -214,14 +214,14 @@ class BIP68_112_113Test(BitcoinTestFramework):
test_blocks = self.generate_blocks(26, 4, test_blocks) # 0x00000004 (signalling not)
test_blocks = self.generate_blocks(50, 536871169, test_blocks) # 0x20000101 (signalling ready)
test_blocks = self.generate_blocks(10, 536936448, test_blocks) # 0x20010000 (signalling not)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
self.log.info("Advanced from STARTED to LOCKED_IN, height = 431")
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in')
# Generate 140 more version 4 blocks
test_blocks = self.generate_blocks(140, 4)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
# Inputs at height = 572
#
@@ -264,7 +264,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
# 2 more version 4 blocks
test_blocks = self.generate_blocks(2, 4)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
self.log.info("Not yet advanced to ACTIVE, height = 574 (will activate for block 576, not 575)")
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'locked_in')
@@ -318,7 +318,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
# try BIP 112 with seq=9 txs
success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v1))
success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v1))
- self.sync_blocks([self.create_test_block(success_txs)])
+ self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
self.log.info("Test version 2 txs")
@@ -337,12 +337,12 @@ class BIP68_112_113Test(BitcoinTestFramework):
# try BIP 112 with seq=9 txs
success_txs.extend(all_rlt_txs(bip112txs_vary_nSequence_9_v2))
success_txs.extend(all_rlt_txs(bip112txs_vary_OP_CSV_9_v2))
- self.sync_blocks([self.create_test_block(success_txs)])
+ self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# 1 more version 4 block to get us to height 575 so the fork should now be active for the next block
test_blocks = self.generate_blocks(1, 4)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], 'active')
self.log.info("Post-Soft Fork Tests.")
@@ -354,74 +354,74 @@ class BIP68_112_113Test(BitcoinTestFramework):
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 # = MTP of prior block (not <) but < time put on current block
bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)
for bip113tx in [bip113signed1, bip113signed2]:
- self.sync_blocks([self.create_test_block([bip113tx])], success=False)
+ self.send_blocks([self.create_test_block([bip113tx])], success=False)
# BIP 113 tests should now pass if the locktime is < MTP
bip113tx_v1.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
bip113signed1 = sign_transaction(self.nodes[0], bip113tx_v1)
bip113tx_v2.nLockTime = self.last_block_time - 600 * 5 - 1 # < MTP of prior block
bip113signed2 = sign_transaction(self.nodes[0], bip113tx_v2)
for bip113tx in [bip113signed1, bip113signed2]:
- self.sync_blocks([self.create_test_block([bip113tx])])
+ self.send_blocks([self.create_test_block([bip113tx])])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# Next block height = 580 after 4 blocks of random version
test_blocks = self.generate_blocks(4, 1234)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
self.log.info("BIP 68 tests")
self.log.info("Test version 1 txs - all should still pass")
success_txs = []
success_txs.extend(all_rlt_txs(bip68txs_v1))
- self.sync_blocks([self.create_test_block(success_txs)])
+ self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
self.log.info("Test version 2 txs")
# All txs with SEQUENCE_LOCKTIME_DISABLE_FLAG set pass
bip68success_txs = [tx['tx'] for tx in bip68txs_v2 if tx['sdf']]
- self.sync_blocks([self.create_test_block(bip68success_txs)])
+ self.send_blocks([self.create_test_block(bip68success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# All txs without flag fail as we are at delta height = 8 < 10 and delta time = 8 * 600 < 10 * 512
bip68timetxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and tx['stf']]
for tx in bip68timetxs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
bip68heighttxs = [tx['tx'] for tx in bip68txs_v2 if not tx['sdf'] and not tx['stf']]
for tx in bip68heighttxs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
# Advance one block to 581
test_blocks = self.generate_blocks(1, 1234)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
# Height txs should fail and time txs should now pass 9 * 600 > 10 * 512
bip68success_txs.extend(bip68timetxs)
- self.sync_blocks([self.create_test_block(bip68success_txs)])
+ self.send_blocks([self.create_test_block(bip68success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
for tx in bip68heighttxs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
# Advance one block to 582
test_blocks = self.generate_blocks(1, 1234)
- self.sync_blocks(test_blocks)
+ self.send_blocks(test_blocks)
# All BIP 68 txs should pass
bip68success_txs.extend(bip68heighttxs)
- self.sync_blocks([self.create_test_block(bip68success_txs)])
+ self.send_blocks([self.create_test_block(bip68success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
self.log.info("BIP 112 tests")
self.log.info("Test version 1 txs")
# -1 OP_CSV tx should fail
- self.sync_blocks([self.create_test_block([bip112tx_special_v1])], success=False)
+ self.send_blocks([self.create_test_block([bip112tx_special_v1])], success=False)
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 1 txs should still pass
success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v1 if tx['sdf']]
success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if tx['sdf']]
- self.sync_blocks([self.create_test_block(success_txs)])
+ self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV, version 1 txs should now fail
@@ -430,18 +430,18 @@ class BIP68_112_113Test(BitcoinTestFramework):
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v1 if not tx['sdf']]
for tx in fail_txs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
self.log.info("Test version 2 txs")
# -1 OP_CSV tx should fail
- self.sync_blocks([self.create_test_block([bip112tx_special_v2])], success=False)
+ self.send_blocks([self.create_test_block([bip112tx_special_v2])], success=False)
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in argument to OP_CSV, version 2 txs should pass (all sequence locks are met)
success_txs = [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if tx['sdf']]
success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if tx['sdf']]
- self.sync_blocks([self.create_test_block(success_txs)])
+ self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# SEQUENCE_LOCKTIME_DISABLE_FLAG is unset in argument to OP_CSV for all remaining txs ##
@@ -450,23 +450,23 @@ class BIP68_112_113Test(BitcoinTestFramework):
fail_txs = all_rlt_txs(bip112txs_vary_nSequence_9_v2)
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_9_v2 if not tx['sdf']]
for tx in fail_txs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
# If SEQUENCE_LOCKTIME_DISABLE_FLAG is set in nSequence, tx should fail
fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if tx['sdf']]
for tx in fail_txs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
# If sequencelock types mismatch, tx should fail
fail_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and tx['stf']]
fail_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and tx['stf']]
for tx in fail_txs:
- self.sync_blocks([self.create_test_block([tx])], success=False)
+ self.send_blocks([self.create_test_block([tx])], success=False)
# Remaining txs should pass, just test masking works properly
success_txs = [tx['tx'] for tx in bip112txs_vary_nSequence_v2 if not tx['sdf'] and not tx['stf']]
success_txs += [tx['tx'] for tx in bip112txs_vary_OP_CSV_v2 if not tx['sdf'] and not tx['stf']]
- self.sync_blocks([self.create_test_block(success_txs)])
+ self.send_blocks([self.create_test_block(success_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# Additional test, of checking that comparison of two time types works properly
@@ -476,7 +476,7 @@ class BIP68_112_113Test(BitcoinTestFramework):
signtx = sign_transaction(self.nodes[0], tx)
time_txs.append(signtx)
- self.sync_blocks([self.create_test_block(time_txs)])
+ self.send_blocks([self.create_test_block(time_txs)])
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# TODO: Test empty stack fails
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 8b06cc7372..62062926a6 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test recovery from a crash during chainstate writing.
@@ -28,18 +28,12 @@
import errno
import http.client
import random
-import sys
import time
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, ToHex
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, create_confirmed_utxos, hex_str_to_bytes
-HTTP_DISCONNECT_ERRORS = [http.client.CannotSendRequest]
-try:
- HTTP_DISCONNECT_ERRORS.append(http.client.RemoteDisconnected)
-except AttributeError:
- pass
class ChainstateWriteCrashTest(BitcoinTestFramework):
def set_test_params(self):
@@ -110,14 +104,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
try:
self.nodes[node_index].submitblock(block)
return True
- except http.client.BadStatusLine as e:
- # Prior to 3.5 BadStatusLine('') was raised for a remote disconnect error.
- if sys.version_info[0] == 3 and sys.version_info[1] < 5 and e.line == "''":
- self.log.debug("node %d submitblock raised exception: %s", node_index, e)
- return False
- else:
- raise
- except tuple(HTTP_DISCONNECT_ERRORS) as e:
+ except (http.client.CannotSendRequest, http.client.RemoteDisconnected) as e:
self.log.debug("node %d submitblock raised exception: %s", node_index, e)
return False
except OSError as e:
diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py
index 8ff9498ef3..7480e5c5ba 100755
--- a/test/functional/feature_dersig.py
+++ b/test/functional/feature_dersig.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test BIP66 (DER SIG).
@@ -14,7 +14,6 @@ from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- bytes_to_hex_str,
wait_until,
)
@@ -103,7 +102,7 @@ class BIP66Test(BitcoinTestFramework):
# rejected from the mempool for exactly that reason.
assert_equal(
[{'txid': spendtx.hash, 'allowed': False, 'reject-reason': '64: non-mandatory-script-verify-flag (Non-canonical DER signature)'}],
- self.nodes[0].testmempoolaccept(rawtxs=[bytes_to_hex_str(spendtx.serialize())], allowhighfees=True)
+ 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_fee_estimation.py b/test/functional/feature_fee_estimation.py
index b68e46adbc..a4b9f213a1 100755
--- a/test/functional/feature_fee_estimation.py
+++ b/test/functional/feature_fee_estimation.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test fee estimation code."""
@@ -15,8 +15,6 @@ from test_framework.util import (
assert_greater_than_or_equal,
connect_nodes,
satoshi_round,
- sync_blocks,
- sync_mempools,
)
# Construct 2 trivial P2SH's and the ScriptSigs that spend them
@@ -65,7 +63,7 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
# the ScriptSig that will satisfy the ScriptPubKey.
for inp in tx.vin:
inp.scriptSig = SCRIPT_SIG[inp.prevout.n]
- txid = from_node.sendrawtransaction(ToHex(tx), True)
+ txid = from_node.sendrawtransaction(hexstring=ToHex(tx), maxfeerate=0)
unconflist.append({"txid": txid, "vout": 0, "amount": total_in - amount - fee})
unconflist.append({"txid": txid, "vout": 1, "amount": amount})
@@ -95,7 +93,7 @@ def split_inputs(from_node, txins, txouts, initial_split=False):
else:
tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout["vout"]]
completetx = ToHex(tx)
- txid = from_node.sendrawtransaction(completetx, True)
+ txid = from_node.sendrawtransaction(hexstring=completetx, maxfeerate=0)
txouts.append({"txid": txid, "vout": 0, "amount": half_change})
txouts.append({"txid": txid, "vout": 1, "amount": rem_change})
@@ -162,9 +160,9 @@ class EstimateFeeTest(BitcoinTestFramework):
self.memutxo, Decimal("0.005"), min_fee, min_fee)
tx_kbytes = (len(txhex) // 2) / 1000.0
self.fees_per_kb.append(float(fee) / tx_kbytes)
- sync_mempools(self.nodes[0:3], wait=.1)
+ self.sync_mempools(self.nodes[0:3], wait=.1)
mined = mining_node.getblock(mining_node.generate(1)[0], True)["tx"]
- sync_blocks(self.nodes[0:3], wait=.1)
+ self.sync_blocks(self.nodes[0:3], wait=.1)
# update which txouts are confirmed
newmem = []
for utx in self.memutxo:
@@ -237,7 +235,7 @@ class EstimateFeeTest(BitcoinTestFramework):
while len(self.nodes[1].getrawmempool()) > 0:
self.nodes[1].generate(1)
- sync_blocks(self.nodes[0:3], wait=.1)
+ self.sync_blocks(self.nodes[0:3], wait=.1)
self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb)
diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py
index 9fb0d35a68..ba116e41f5 100755
--- a/test/functional/feature_filelock.py
+++ b/test/functional/feature_filelock.py
@@ -23,7 +23,7 @@ class FilelockTest(BitcoinTestFramework):
self.log.info("Using datadir {}".format(datadir))
self.log.info("Check that we can't start a second bitcoind instance using the same datadir")
- expected_msg = "Error: Cannot obtain a lock on data directory {}. Bitcoin Core is probably already running.".format(datadir)
+ expected_msg = "Error: Cannot obtain a lock on data directory {0}. {1} is probably already running.".format(datadir, self.config['environment']['PACKAGE_NAME'])
self.nodes[1].assert_start_raises_init_error(extra_args=['-datadir={}'.format(self.nodes[0].datadir), '-noserver'], expected_msg=expected_msg)
if self.is_wallet_compiled():
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index b98dd6d26c..13cf951550 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the -alertnotify, -blocknotify and -walletnotify options."""
diff --git a/test/functional/feature_nulldummy.py b/test/functional/feature_nulldummy.py
index eb76089d9c..60a703c48f 100755
--- a/test/functional/feature_nulldummy.py
+++ b/test/functional/feature_nulldummy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test NULLDUMMY softfork.
@@ -18,7 +18,7 @@ from test_framework.blocktools import create_coinbase, create_block, create_tran
from test_framework.messages import CTransaction
from test_framework.script import CScript
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str
+from test_framework.util import assert_equal, assert_raises_rpc_error
NULLDUMMY_ERROR = "non-mandatory-script-verify-flag (Dummy CHECKMULTISIG argument must be zero) (code 64)"
@@ -27,7 +27,7 @@ def trueDummy(tx):
newscript = []
for i in scriptSig:
if (len(newscript) == 0):
- assert(len(i) == 0)
+ assert len(i) == 0
newscript.append(b'\x51')
else:
newscript.append(i)
@@ -64,17 +64,17 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.log.info("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]")
test1txs = [create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, amount=49)]
- txid1 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[0].serialize_with_witness()), True)
+ txid1 = self.nodes[0].sendrawtransaction(test1txs[0].serialize_with_witness().hex(), 0)
test1txs.append(create_transaction(self.nodes[0], txid1, self.ms_address, amount=48))
- txid2 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[1].serialize_with_witness()), True)
+ txid2 = self.nodes[0].sendrawtransaction(test1txs[1].serialize_with_witness().hex(), 0)
test1txs.append(create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, amount=49))
- txid3 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[2].serialize_with_witness()), True)
+ txid3 = self.nodes[0].sendrawtransaction(test1txs[2].serialize_with_witness().hex(), 0)
self.block_submit(self.nodes[0], test1txs, False, True)
self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
test2tx = create_transaction(self.nodes[0], txid2, self.ms_address, amount=47)
trueDummy(test2tx)
- assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True)
+ assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test2tx.serialize_with_witness().hex(), 0)
self.log.info("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]")
self.block_submit(self.nodes[0], [test2tx], False, True)
@@ -83,19 +83,19 @@ class NULLDUMMYTest(BitcoinTestFramework):
test4tx = create_transaction(self.nodes[0], test2tx.hash, self.address, amount=46)
test6txs = [CTransaction(test4tx)]
trueDummy(test4tx)
- assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True)
+ assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test4tx.serialize_with_witness().hex(), 0)
self.block_submit(self.nodes[0], [test4tx])
self.log.info("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation")
test5tx = create_transaction(self.nodes[0], txid3, self.wit_address, amount=48)
test6txs.append(CTransaction(test5tx))
test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01'
- assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True)
+ assert_raises_rpc_error(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, test5tx.serialize_with_witness().hex(), 0)
self.block_submit(self.nodes[0], [test5tx], True)
self.log.info("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]")
for i in test6txs:
- self.nodes[0].sendrawtransaction(bytes_to_hex_str(i.serialize_with_witness()), True)
+ self.nodes[0].sendrawtransaction(i.serialize_with_witness().hex(), 0)
self.block_submit(self.nodes[0], test6txs, True, True)
def block_submit(self, node, txs, witness=False, accept=False):
@@ -108,7 +108,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
witness and add_witness_commitment(block)
block.rehash()
block.solve()
- node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ node.submitblock(block.serialize().hex())
if (accept):
assert_equal(node.getbestblockhash(), block.hash)
self.tip = block.sha256
diff --git a/test/functional/feature_proxy.py b/test/functional/feature_proxy.py
index f042adb7aa..be323d355e 100755
--- a/test/functional/feature_proxy.py
+++ b/test/functional/feature_proxy.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test bitcoind with different proxy configuration.
@@ -95,7 +95,7 @@ class ProxyTest(BitcoinTestFramework):
# Test: outgoing IPv4 connection through node
node.addnode("15.61.23.23:1234", "onetry")
cmd = proxies[0].queue.get()
- assert(isinstance(cmd, Socks5Command))
+ assert isinstance(cmd, Socks5Command)
# Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
assert_equal(cmd.addr, b"15.61.23.23")
@@ -109,7 +109,7 @@ class ProxyTest(BitcoinTestFramework):
# Test: outgoing IPv6 connection through node
node.addnode("[1233:3432:2434:2343:3234:2345:6546:4534]:5443", "onetry")
cmd = proxies[1].queue.get()
- assert(isinstance(cmd, Socks5Command))
+ assert isinstance(cmd, Socks5Command)
# Note: bitcoind's SOCKS5 implementation only sends atyp DOMAINNAME, even if connecting directly to IPv4/IPv6
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
assert_equal(cmd.addr, b"1233:3432:2434:2343:3234:2345:6546:4534")
@@ -123,7 +123,7 @@ class ProxyTest(BitcoinTestFramework):
# Test: outgoing onion connection through node
node.addnode("bitcoinostk4e4re.onion:8333", "onetry")
cmd = proxies[2].queue.get()
- assert(isinstance(cmd, Socks5Command))
+ assert isinstance(cmd, Socks5Command)
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
assert_equal(cmd.addr, b"bitcoinostk4e4re.onion")
assert_equal(cmd.port, 8333)
@@ -135,7 +135,7 @@ class ProxyTest(BitcoinTestFramework):
# Test: outgoing DNS name connection through node
node.addnode("node.noumenon:8333", "onetry")
cmd = proxies[3].queue.get()
- assert(isinstance(cmd, Socks5Command))
+ assert isinstance(cmd, Socks5Command)
assert_equal(cmd.atyp, AddressType.DOMAINNAME)
assert_equal(cmd.addr, b"node.noumenon")
assert_equal(cmd.port, 8333)
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 3e1ba88f0a..66c395d7a2 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the pruning code.
@@ -8,32 +8,80 @@ WARNING:
This test uses 4GB of disk space.
This test takes 30 mins or more (up to 2 hours)
"""
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, connect_nodes, mine_large_block, sync_blocks, wait_until
-
import os
-MIN_BLOCKS_TO_KEEP = 288
+from test_framework.blocktools import create_coinbase
+from test_framework.messages import CBlock, ToHex
+from test_framework.script import CScript, OP_RETURN, OP_NOP
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_raises_rpc_error,
+ connect_nodes,
+ disconnect_nodes,
+ wait_until,
+)
# Rescans start at the earliest block up to 2 hours before a key timestamp, so
# the manual prune RPC avoids pruning blocks in the same window to be
# compatible with pruning based on key creation time.
TIMESTAMP_WINDOW = 2 * 60 * 60
+def mine_large_blocks(node, n):
+ # Make a large scriptPubKey for the coinbase transaction. This is OP_RETURN
+ # followed by 950k of OP_NOP. This would be non-standard in a non-coinbase
+ # transaction but is consensus valid.
+
+ # Set the nTime if this is the first time this function has been called.
+ # A static variable ensures that time is monotonicly increasing and is therefore
+ # different for each block created => blockhash is unique.
+ if "nTimes" not in mine_large_blocks.__dict__:
+ mine_large_blocks.nTime = 0
+
+ # Get the block parameters for the first block
+ big_script = CScript([OP_RETURN] + [OP_NOP] * 950000)
+ best_block = node.getblock(node.getbestblockhash())
+ height = int(best_block["height"]) + 1
+ mine_large_blocks.nTime = max(mine_large_blocks.nTime, int(best_block["time"])) + 1
+ previousblockhash = int(best_block["hash"], 16)
+
+ for _ in range(n):
+ # Build the coinbase transaction (with large scriptPubKey)
+ coinbase_tx = create_coinbase(height)
+ coinbase_tx.vin[0].nSequence = 2 ** 32 - 1
+ coinbase_tx.vout[0].scriptPubKey = big_script
+ coinbase_tx.rehash()
+
+ # Build the block
+ block = CBlock()
+ block.nVersion = best_block["version"]
+ block.hashPrevBlock = previousblockhash
+ block.nTime = mine_large_blocks.nTime
+ block.nBits = int('207fffff', 16)
+ block.nNonce = 0
+ block.vtx = [coinbase_tx]
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.solve()
+
+ # Submit to the node
+ node.submitblock(ToHex(block))
+
+ previousblockhash = block.sha256
+ height += 1
+ mine_large_blocks.nTime += 1
def calc_usage(blockdir):
- return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(os.path.join(blockdir, f))) / (1024. * 1024.)
+ return sum(os.path.getsize(blockdir + f) for f in os.listdir(blockdir) if os.path.isfile(os.path.join(blockdir, f))) / (1024. * 1024.)
class PruneTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 6
- self.rpc_timeout = 900
# Create nodes 0 and 1 to mine.
# Create node 2 to test pruning.
- self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-limitdescendantcount=100", "-limitdescendantsize=5000", "-limitancestorcount=100", "-limitancestorsize=5000"]
+ self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5"]
# Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later)
# Create nodes 5 to test wallet in prune mode, but do not connect
self.extra_args = [
@@ -55,10 +103,10 @@ class PruneTest(BitcoinTestFramework):
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 2)
- connect_nodes(self.nodes[2], 0)
+ connect_nodes(self.nodes[0], 2)
connect_nodes(self.nodes[0], 3)
connect_nodes(self.nodes[0], 4)
- sync_blocks(self.nodes[0:5])
+ self.sync_blocks(self.nodes[0:5])
def setup_nodes(self):
self.add_nodes(self.num_nodes, self.extra_args)
@@ -69,23 +117,21 @@ class PruneTest(BitcoinTestFramework):
def create_big_chain(self):
# Start by creating some coinbases we can spend later
self.nodes[1].generate(200)
- sync_blocks(self.nodes[0:2])
+ self.sync_blocks(self.nodes[0:2])
self.nodes[0].generate(150)
+
# Then mine enough full blocks to create more than 550MiB of data
- for i in range(645):
- mine_large_block(self.nodes[0], self.utxo_cache_0)
+ mine_large_blocks(self.nodes[0], 645)
- sync_blocks(self.nodes[0:5])
+ self.sync_blocks(self.nodes[0:5])
def test_height_min(self):
- if not os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")):
- raise AssertionError("blk00000.dat is missing, pruning too early")
+ assert os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")), "blk00000.dat is missing, pruning too early"
self.log.info("Success")
self.log.info("Though we're already using more than 550MiB, current usage: %d" % calc_usage(self.prunedir))
self.log.info("Mining 25 more blocks should cause the first block file to be pruned")
# Pruning doesn't run until we're allocating another chunk, 20 full blocks past the height cutoff will ensure this
- for i in range(25):
- mine_large_block(self.nodes[0], self.utxo_cache_0)
+ mine_large_blocks(self.nodes[0], 25)
# Wait for blk00000.dat to be pruned
wait_until(lambda: not os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")), timeout=30)
@@ -93,8 +139,7 @@ class PruneTest(BitcoinTestFramework):
self.log.info("Success")
usage = calc_usage(self.prunedir)
self.log.info("Usage should be below target: %d" % usage)
- if (usage > 550):
- raise AssertionError("Pruning target not being met")
+ assert_greater_than(550, usage)
def create_chain_with_staleblocks(self):
# Create stale blocks in manageable sized chunks
@@ -103,90 +148,66 @@ class PruneTest(BitcoinTestFramework):
for j in range(12):
# Disconnect node 0 so it can mine a longer reorg chain without knowing about node 1's soon-to-be-stale chain
# Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects
- # Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine
- self.stop_node(0)
- self.start_node(0, extra_args=self.full_node_default_args)
+ disconnect_nodes(self.nodes[0], 1)
+ disconnect_nodes(self.nodes[0], 2)
# Mine 24 blocks in node 1
- for i in range(24):
- if j == 0:
- mine_large_block(self.nodes[1], self.utxo_cache_1)
- else:
- # Add node1's wallet transactions back to the mempool, to
- # avoid the mined blocks from being too small.
- self.nodes[1].resendwallettransactions()
- self.nodes[1].generate(1) #tx's already in mempool from previous disconnects
+ mine_large_blocks(self.nodes[1], 24)
# Reorg back with 25 block chain from node 0
- for i in range(25):
- mine_large_block(self.nodes[0], self.utxo_cache_0)
+ mine_large_blocks(self.nodes[0], 25)
# Create connections in the order so both nodes can see the reorg at the same time
- connect_nodes(self.nodes[1], 0)
- connect_nodes(self.nodes[2], 0)
- sync_blocks(self.nodes[0:3])
+ connect_nodes(self.nodes[0], 1)
+ connect_nodes(self.nodes[0], 2)
+ self.sync_blocks(self.nodes[0:3])
self.log.info("Usage can be over target because of high stale rate: %d" % calc_usage(self.prunedir))
def reorg_test(self):
# Node 1 will mine a 300 block chain starting 287 blocks back from Node 0 and Node 2's tip
# This will cause Node 2 to do a reorg requiring 288 blocks of undo data to the reorg_test chain
- # Reboot node 1 to clear its mempool (hopefully make the invalidate faster)
- # Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks)
- self.stop_node(1)
- self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxweight=20000", "-checkblocks=5"])
height = self.nodes[1].getblockcount()
self.log.info("Current block height: %d" % height)
- invalidheight = height-287
- badhash = self.nodes[1].getblockhash(invalidheight)
- self.log.info("Invalidating block %s at height %d" % (badhash,invalidheight))
- self.nodes[1].invalidateblock(badhash)
+ self.forkheight = height - 287
+ self.forkhash = self.nodes[1].getblockhash(self.forkheight)
+ self.log.info("Invalidating block %s at height %d" % (self.forkhash, self.forkheight))
+ self.nodes[1].invalidateblock(self.forkhash)
# We've now switched to our previously mined-24 block fork on node 1, but that's not what we want
# So invalidate that fork as well, until we're on the same chain as node 0/2 (but at an ancestor 288 blocks ago)
- mainchainhash = self.nodes[0].getblockhash(invalidheight - 1)
- curhash = self.nodes[1].getblockhash(invalidheight - 1)
+ mainchainhash = self.nodes[0].getblockhash(self.forkheight - 1)
+ curhash = self.nodes[1].getblockhash(self.forkheight - 1)
while curhash != mainchainhash:
self.nodes[1].invalidateblock(curhash)
- curhash = self.nodes[1].getblockhash(invalidheight - 1)
+ curhash = self.nodes[1].getblockhash(self.forkheight - 1)
- assert(self.nodes[1].getblockcount() == invalidheight - 1)
+ assert self.nodes[1].getblockcount() == self.forkheight - 1
self.log.info("New best height: %d" % self.nodes[1].getblockcount())
- # Reboot node1 to clear those giant tx's from mempool
- self.stop_node(1)
- self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxweight=20000", "-checkblocks=5"])
+ # Disconnect node1 and generate the new chain
+ disconnect_nodes(self.nodes[0], 1)
+ disconnect_nodes(self.nodes[1], 2)
self.log.info("Generating new longer chain of 300 more blocks")
self.nodes[1].generate(300)
self.log.info("Reconnect nodes")
connect_nodes(self.nodes[0], 1)
- connect_nodes(self.nodes[2], 1)
- sync_blocks(self.nodes[0:3], timeout=120)
+ connect_nodes(self.nodes[1], 2)
+ self.sync_blocks(self.nodes[0:3], timeout=120)
self.log.info("Verify height on node 2: %d" % self.nodes[2].getblockcount())
- self.log.info("Usage possibly still high bc of stale blocks in block files: %d" % calc_usage(self.prunedir))
+ self.log.info("Usage possibly still high because of stale blocks in block files: %d" % calc_usage(self.prunedir))
- self.log.info("Mine 220 more blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)")
+ self.log.info("Mine 220 more large blocks so we have requisite history")
- # Get node0's wallet transactions back in its mempool, to avoid the
- # mined blocks from being too small.
- self.nodes[0].resendwallettransactions()
-
- for i in range(22):
- # This can be slow, so do this in multiple RPC calls to avoid
- # RPC timeouts.
- self.nodes[0].generate(10) #node 0 has many large tx's in its mempool from the disconnects
- sync_blocks(self.nodes[0:3], timeout=300)
+ mine_large_blocks(self.nodes[0], 220)
usage = calc_usage(self.prunedir)
self.log.info("Usage should be below target: %d" % usage)
- if (usage > 550):
- raise AssertionError("Pruning target not being met")
-
- return invalidheight,badhash
+ assert_greater_than(550, usage)
def reorg_back(self):
# Verify that a block on the old main chain fork has been pruned away
@@ -219,17 +240,17 @@ class PruneTest(BitcoinTestFramework):
blocks_to_mine = first_reorg_height + 1 - self.mainchainheight
self.log.info("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed: %d" % blocks_to_mine)
self.nodes[0].invalidateblock(curchainhash)
- assert(self.nodes[0].getblockcount() == self.mainchainheight)
- assert(self.nodes[0].getbestblockhash() == self.mainchainhash2)
+ assert_equal(self.nodes[0].getblockcount(), self.mainchainheight)
+ assert_equal(self.nodes[0].getbestblockhash(), self.mainchainhash2)
goalbesthash = self.nodes[0].generate(blocks_to_mine)[-1]
goalbestheight = first_reorg_height + 1
self.log.info("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload")
# Wait for Node 2 to reorg to proper height
wait_until(lambda: self.nodes[2].getblockcount() >= goalbestheight, timeout=900)
- assert(self.nodes[2].getbestblockhash() == goalbesthash)
+ assert_equal(self.nodes[2].getbestblockhash(), goalbesthash)
# Verify we can now have the data for a block previously pruned
- assert(self.nodes[2].getblock(self.forkhash)["height"] == self.forkheight)
+ assert_equal(self.nodes[2].getblock(self.forkhash)["height"], self.forkheight)
def manual_test(self, node_number, use_timestamp):
# at this point, node has 995 blocks and has not yet run in prune mode
@@ -250,20 +271,9 @@ class PruneTest(BitcoinTestFramework):
else:
return index
- def prune(index, expected_ret=None):
+ def prune(index):
ret = node.pruneblockchain(height=height(index))
- # Check the return value. When use_timestamp is True, just check
- # that the return value is less than or equal to the expected
- # value, because when more than one block is generated per second,
- # a timestamp will not be granular enough to uniquely identify an
- # individual block.
- if expected_ret is None:
- expected_ret = index
- if use_timestamp:
- assert_greater_than(ret, 0)
- assert_greater_than(expected_ret + 1, ret)
- else:
- assert_equal(ret, expected_ret)
+ assert_equal(ret, node.getblockchaininfo()['pruneheight'])
def has_block(index):
return os.path.isfile(os.path.join(self.nodes[node_number].datadir, "regtest", "blocks", "blk{:05}.dat".format(index)))
@@ -287,38 +297,30 @@ class PruneTest(BitcoinTestFramework):
# height=100 too low to prune first block file so this is a no-op
prune(100)
- if not has_block(0):
- raise AssertionError("blk00000.dat is missing when should still be there")
+ assert has_block(0), "blk00000.dat is missing when should still be there"
# Does nothing
node.pruneblockchain(height(0))
- if not has_block(0):
- raise AssertionError("blk00000.dat is missing when should still be there")
+ assert has_block(0), "blk00000.dat is missing when should still be there"
# height=500 should prune first file
prune(500)
- if has_block(0):
- raise AssertionError("blk00000.dat is still there, should be pruned by now")
- if not has_block(1):
- raise AssertionError("blk00001.dat is missing when should still be there")
+ assert not has_block(0), "blk00000.dat is still there, should be pruned by now"
+ assert has_block(1), "blk00001.dat is missing when should still be there"
# height=650 should prune second file
prune(650)
- if has_block(1):
- raise AssertionError("blk00001.dat is still there, should be pruned by now")
+ assert not has_block(1), "blk00001.dat is still there, should be pruned by now"
# height=1000 should not prune anything more, because tip-288 is in blk00002.dat.
- prune(1000, 1001 - MIN_BLOCKS_TO_KEEP)
- if not has_block(2):
- raise AssertionError("blk00002.dat is still there, should be pruned by now")
+ prune(1000)
+ assert has_block(2), "blk00002.dat is still there, should be pruned by now"
# advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat)
node.generate(288)
prune(1000)
- if has_block(2):
- raise AssertionError("blk00002.dat is still there, should be pruned by now")
- if has_block(3):
- raise AssertionError("blk00003.dat is still there, should be pruned by now")
+ assert not has_block(2), "blk00002.dat is still there, should be pruned by now"
+ assert not has_block(3), "blk00003.dat is still there, should be pruned by now"
# stop node, start back up with auto-prune at 550 MiB, make sure still runs
self.stop_node(node_number)
@@ -338,22 +340,15 @@ class PruneTest(BitcoinTestFramework):
self.log.info("Syncing node 5 to test wallet")
connect_nodes(self.nodes[0], 5)
nds = [self.nodes[0], self.nodes[5]]
- sync_blocks(nds, wait=5, timeout=300)
- self.stop_node(5) #stop and start to trigger rescan
+ self.sync_blocks(nds, wait=5, timeout=300)
+ self.stop_node(5) # stop and start to trigger rescan
self.start_node(5, extra_args=["-prune=550"])
self.log.info("Success")
def run_test(self):
- self.log.info("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
- self.log.info("Mining a big blockchain of 995 blocks")
-
- # Determine default relay fee
- self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
-
- # Cache for utxos, as the listunspent may take a long time later in the test
- self.utxo_cache_0 = []
- self.utxo_cache_1 = []
+ self.log.info("Warning! This test requires 4GB of disk space")
+ self.log.info("Mining a big blockchain of 995 blocks")
self.create_big_chain()
# Chain diagram key:
# * blocks on main chain
@@ -394,11 +389,11 @@ class PruneTest(BitcoinTestFramework):
# +...+(1044) &.. $...$(1319)
# Save some current chain state for later use
- self.mainchainheight = self.nodes[2].getblockcount() #1320
+ self.mainchainheight = self.nodes[2].getblockcount() # 1320
self.mainchainhash2 = self.nodes[2].getblockhash(self.mainchainheight)
self.log.info("Check that we can survive a 288 block reorg still")
- (self.forkheight,self.forkhash) = self.reorg_test() #(1033, )
+ self.reorg_test() # (1033, )
# Now create a 288 block reorg by mining a longer chain on N1
# First disconnect N1
# Then invalidate 1033 on main chain and 1032 on fork so height is 1032 on main chain
diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py
index ff7c2b23bf..1496c5d958 100755
--- a/test/functional/feature_rbf.py
+++ b/test/functional/feature_rbf.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the RBF code."""
@@ -9,12 +9,12 @@ from decimal import Decimal
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut
from test_framework.script import CScript, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, satoshi_round
+from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round
MAX_REPLACEMENT_LIMIT = 100
def txToHex(tx):
- return bytes_to_hex_str(tx.serialize())
+ return tx.serialize().hex()
def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
"""Create a txout with a given amount and scriptPubKey
@@ -46,7 +46,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
signed_tx = node.signrawtransactionwithwallet(txToHex(tx2))
- txid = node.sendrawtransaction(signed_tx['hex'], True)
+ txid = node.sendrawtransaction(signed_tx['hex'], 0)
# If requested, ensure txouts are confirmed.
if confirmed:
@@ -56,7 +56,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
new_size = len(node.getrawmempool())
# Error out if we have something stuck in the mempool, as this
# would likely be a bug.
- assert(new_size < mempool_size)
+ assert new_size < mempool_size
mempool_size = new_size
return COutPoint(int(txid, 16), 0)
@@ -64,7 +64,7 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
class ReplaceByFeeTest(BitcoinTestFramework):
def set_test_params(self):
- self.num_nodes = 2
+ self.num_nodes = 1
self.extra_args = [
[
"-maxorphantx=1000",
@@ -74,9 +74,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
"-limitdescendantcount=200",
"-limitdescendantsize=101",
],
- [
- "-mempoolreplacement=0",
- ],
]
def skip_test_if_missing_module(self):
@@ -136,7 +133,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx1a_hex = txToHex(tx1a)
- tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
self.sync_all()
@@ -147,32 +144,23 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b_hex = txToHex(tx1b)
# This will raise an exception due to insufficient fee
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
- # This will raise an exception due to transaction replacement being disabled
- assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True)
+ assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, 0)
# Extra 0.1 BTC fee
tx1b = CTransaction()
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
tx1b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]
tx1b_hex = txToHex(tx1b)
- # Replacement still disabled even with "enough fee"
- assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True)
# Works when enabled
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
+ tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)
mempool = self.nodes[0].getrawmempool()
- assert (tx1a_txid not in mempool)
- assert (tx1b_txid in mempool)
+ assert tx1a_txid not in mempool
+ assert tx1b_txid in mempool
assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid))
- # Second node is running mempoolreplacement=0, will not replace originally-seen txn
- mempool = self.nodes[1].getrawmempool()
- assert tx1a_txid in mempool
- assert tx1b_txid not in mempool
-
def test_doublespend_chain(self):
"""Doublespend of a long chain"""
@@ -188,7 +176,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx.vin = [CTxIn(prevout, nSequence=0)]
tx.vout = [CTxOut(remaining_value, CScript([1, OP_DROP] * 15 + [1]))]
tx_hex = txToHex(tx)
- txid = self.nodes[0].sendrawtransaction(tx_hex, True)
+ txid = self.nodes[0].sendrawtransaction(tx_hex, 0)
chain_txids.append(txid)
prevout = COutPoint(int(txid, 16), 0)
@@ -200,18 +188,18 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx_hex = txToHex(dbl_tx)
# This will raise an exception due to insufficient fee
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
+ assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
# Accepted with sufficient fee
dbl_tx = CTransaction()
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
dbl_tx.vout = [CTxOut(1 * COIN, CScript([1] * 35))]
dbl_tx_hex = txToHex(dbl_tx)
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
+ self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)
mempool = self.nodes[0].getrawmempool()
for doublespent_txid in chain_txids:
- assert(doublespent_txid not in mempool)
+ assert doublespent_txid not in mempool
def test_doublespend_tree(self):
"""Doublespend of a big tree of transactions"""
@@ -236,8 +224,8 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx.vout = vout
tx_hex = txToHex(tx)
- assert(len(tx.serialize()) < 100000)
- txid = self.nodes[0].sendrawtransaction(tx_hex, True)
+ assert len(tx.serialize()) < 100000
+ txid = self.nodes[0].sendrawtransaction(tx_hex, 0)
yield tx
_total_txs[0] += 1
@@ -261,20 +249,20 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vout = [CTxOut(initial_nValue - fee * n, CScript([1] * 35))]
dbl_tx_hex = txToHex(dbl_tx)
# This will raise an exception due to insufficient fee
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
+ assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
# 1 BTC fee is enough
dbl_tx = CTransaction()
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
dbl_tx.vout = [CTxOut(initial_nValue - fee * n - 1 * COIN, CScript([1] * 35))]
dbl_tx_hex = txToHex(dbl_tx)
- self.nodes[0].sendrawtransaction(dbl_tx_hex, True)
+ self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)
mempool = self.nodes[0].getrawmempool()
for tx in tree_txs:
tx.rehash()
- assert (tx.hash not in mempool)
+ assert tx.hash not in mempool
# Try again, but with more total transactions than the "max txs
# double-spent at once" anti-DoS limit.
@@ -289,7 +277,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
dbl_tx.vout = [CTxOut(initial_nValue - 2 * fee * n, CScript([1] * 35))]
dbl_tx_hex = txToHex(dbl_tx)
# This will raise an exception
- assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, True)
+ assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
for tx in tree_txs:
tx.rehash()
@@ -303,7 +291,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx1a_hex = txToHex(tx1a)
- self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ self.nodes[0].sendrawtransaction(tx1a_hex, 0)
# Higher fee, but the fee per KB is much lower, so the replacement is
# rejected.
@@ -313,7 +301,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b_hex = txToHex(tx1b)
# This will raise an exception due to insufficient fee
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
+ assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, 0)
def test_spends_of_conflicting_outputs(self):
"""Replacements that spend conflicting tx outputs are rejected"""
@@ -324,7 +312,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a.vin = [CTxIn(utxo1, nSequence=0)]
tx1a.vout = [CTxOut(int(1.1 * COIN), CScript([b'a' * 35]))]
tx1a_hex = txToHex(tx1a)
- tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
tx1a_txid = int(tx1a_txid, 16)
@@ -336,14 +324,14 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2_hex = txToHex(tx2)
# This will raise an exception
- assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True)
+ assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, 0)
# Spend tx1a's output to test the indirect case.
tx1b = CTransaction()
tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
tx1b.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx1b_hex = txToHex(tx1b)
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
+ tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)
tx1b_txid = int(tx1b_txid, 16)
tx2 = CTransaction()
@@ -353,7 +341,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2_hex = txToHex(tx2)
# This will raise an exception
- assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True)
+ assert_raises_rpc_error(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, 0)
def test_new_unconfirmed_inputs(self):
"""Replacements that add new unconfirmed inputs are rejected"""
@@ -364,7 +352,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1.vin = [CTxIn(confirmed_utxo)]
tx1.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx1_hex = txToHex(tx1)
- self.nodes[0].sendrawtransaction(tx1_hex, True)
+ self.nodes[0].sendrawtransaction(tx1_hex, 0)
tx2 = CTransaction()
tx2.vin = [CTxIn(confirmed_utxo), CTxIn(unconfirmed_utxo)]
@@ -372,7 +360,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2_hex = txToHex(tx2)
# This will raise an exception
- assert_raises_rpc_error(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, True)
+ assert_raises_rpc_error(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, 0)
def test_too_many_replacements(self):
"""Replacements that evict too many transactions are rejected"""
@@ -394,7 +382,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
splitting_tx.vout = outputs
splitting_tx_hex = txToHex(splitting_tx)
- txid = self.nodes[0].sendrawtransaction(splitting_tx_hex, True)
+ txid = self.nodes[0].sendrawtransaction(splitting_tx_hex, 0)
txid = int(txid, 16)
# Now spend each of those outputs individually
@@ -403,7 +391,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx_i.vin = [CTxIn(COutPoint(txid, i), nSequence=0)]
tx_i.vout = [CTxOut(split_value - fee, CScript([b'a' * 35]))]
tx_i_hex = txToHex(tx_i)
- self.nodes[0].sendrawtransaction(tx_i_hex, True)
+ self.nodes[0].sendrawtransaction(tx_i_hex, 0)
# Now create doublespend of the whole lot; should fail.
# Need a big enough fee to cover all spending transactions and have
@@ -418,14 +406,14 @@ class ReplaceByFeeTest(BitcoinTestFramework):
double_tx_hex = txToHex(double_tx)
# This will raise an exception
- assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, True)
+ assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, 0)
# If we remove an input, it should pass
double_tx = CTransaction()
double_tx.vin = inputs[0:-1]
double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))]
double_tx_hex = txToHex(double_tx)
- self.nodes[0].sendrawtransaction(double_tx_hex, True)
+ self.nodes[0].sendrawtransaction(double_tx_hex, 0)
def test_opt_in(self):
"""Replacing should only work if orig tx opted in"""
@@ -436,7 +424,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx1a_hex = txToHex(tx1a)
- tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
# This transaction isn't shown as replaceable
assert_equal(self.nodes[0].getmempoolentry(tx1a_txid)['bip125-replaceable'], False)
@@ -448,7 +436,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b_hex = txToHex(tx1b)
# This will raise an exception
- assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, True)
+ assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, 0)
tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
@@ -457,7 +445,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)]
tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx2a_hex = txToHex(tx2a)
- tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, True)
+ tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, 0)
# Still shouldn't be able to double-spend
tx2b = CTransaction()
@@ -466,7 +454,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2b_hex = txToHex(tx2b)
# This will raise an exception
- assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, True)
+ assert_raises_rpc_error(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, 0)
# Now create a new transaction that spends from tx1a and tx2a
# opt-in on one of the inputs
@@ -481,7 +469,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx3a.vout = [CTxOut(int(0.9*COIN), CScript([b'c'])), CTxOut(int(0.9*COIN), CScript([b'd']))]
tx3a_hex = txToHex(tx3a)
- tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, True)
+ tx3a_txid = self.nodes[0].sendrawtransaction(tx3a_hex, 0)
# This transaction is shown as replaceable
assert_equal(self.nodes[0].getmempoolentry(tx3a_txid)['bip125-replaceable'], True)
@@ -496,10 +484,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx3c.vout = [CTxOut(int(0.5 * COIN), CScript([b'f' * 35]))]
tx3c_hex = txToHex(tx3c)
- self.nodes[0].sendrawtransaction(tx3b_hex, True)
+ self.nodes[0].sendrawtransaction(tx3b_hex, 0)
# If tx3b was accepted, tx3c won't look like a replacement,
# but make sure it is accepted anyway
- self.nodes[0].sendrawtransaction(tx3c_hex, True)
+ self.nodes[0].sendrawtransaction(tx3c_hex, 0)
def test_prioritised_transactions(self):
# Ensure that fee deltas used via prioritisetransaction are
@@ -512,7 +500,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx1a_hex = txToHex(tx1a)
- tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True)
+ tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
# Higher fee, but the actual fee per KB is much lower.
tx1b = CTransaction()
@@ -521,15 +509,15 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx1b_hex = txToHex(tx1b)
# Verify tx1b cannot replace tx1a.
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True)
+ assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, 0)
# Use prioritisetransaction to set tx1a's fee to 0.
self.nodes[0].prioritisetransaction(txid=tx1a_txid, fee_delta=int(-0.1*COIN))
# Now tx1b should be able to replace tx1a
- tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
+ tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)
- assert(tx1b_txid in self.nodes[0].getrawmempool())
+ assert tx1b_txid in self.nodes[0].getrawmempool()
# 2. Check that absolute fee checks use modified fee.
tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN))
@@ -538,7 +526,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
tx2a_hex = txToHex(tx2a)
- self.nodes[0].sendrawtransaction(tx2a_hex, True)
+ self.nodes[0].sendrawtransaction(tx2a_hex, 0)
# Lower fee, but we'll prioritise it
tx2b = CTransaction()
@@ -548,15 +536,15 @@ class ReplaceByFeeTest(BitcoinTestFramework):
tx2b_hex = txToHex(tx2b)
# Verify tx2b cannot replace tx2a.
- assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True)
+ assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, 0)
# Now prioritise tx2b to have a higher modified fee
self.nodes[0].prioritisetransaction(txid=tx2b.hash, fee_delta=int(0.1*COIN))
# tx2b should now be accepted
- tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)
+ tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, 0)
- assert(tx2b_txid in self.nodes[0].getrawmempool())
+ assert tx2b_txid in self.nodes[0].getrawmempool()
def test_rpc(self):
us0 = self.nodes[0].listunspent()[0]
diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py
index 658a8cd75e..2d4dd96a1d 100755
--- a/test/functional/feature_segwit.py
+++ b/test/functional/feature_segwit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test the SegWit changeover logic."""
@@ -18,7 +18,13 @@ from test_framework.blocktools import witness_script, send_to_witness
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, sha256, ToHex
from test_framework.script import CScript, OP_HASH160, OP_CHECKSIG, OP_0, hash160, OP_EQUAL, OP_DUP, OP_EQUALVERIFY, OP_1, OP_2, OP_CHECKMULTISIG, OP_TRUE, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes, hex_str_to_bytes, sync_blocks, try_rpc
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ connect_nodes,
+ hex_str_to_bytes,
+ try_rpc,
+)
NODE_0 = 0
NODE_2 = 2
@@ -76,13 +82,13 @@ class SegWitTest(BitcoinTestFramework):
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
block = node.generate(1)
assert_equal(len(node.getblock(block[0])["tx"]), 2)
- sync_blocks(self.nodes)
+ self.sync_blocks()
def skip_mine(self, node, txid, sign, redeem_script=""):
send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script)
block = node.generate(1)
assert_equal(len(node.getblock(block[0])["tx"]), 1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
def fail_accept(self, node, error_msg, txid, sign, redeem_script=""):
assert_raises_rpc_error(-26, error_msg, send_to_witness, use_p2wsh=1, node=node, utxo=getutxo(txid), pubkey=self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=sign, insert_redeem_script=redeem_script)
@@ -93,17 +99,17 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert(tmpl['sizelimit'] == 1000000)
- assert('weightlimit' not in tmpl)
- assert(tmpl['sigoplimit'] == 20000)
- assert(tmpl['transactions'][0]['hash'] == txid)
- assert(tmpl['transactions'][0]['sigops'] == 2)
+ assert tmpl['sizelimit'] == 1000000
+ assert 'weightlimit' not in tmpl
+ assert tmpl['sigoplimit'] == 20000
+ assert tmpl['transactions'][0]['hash'] == txid
+ assert tmpl['transactions'][0]['sigops'] == 2
tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert(tmpl['sizelimit'] == 1000000)
- assert('weightlimit' not in tmpl)
- assert(tmpl['sigoplimit'] == 20000)
- assert(tmpl['transactions'][0]['hash'] == txid)
- assert(tmpl['transactions'][0]['sigops'] == 2)
+ assert tmpl['sizelimit'] == 1000000
+ assert 'weightlimit' not in tmpl
+ assert tmpl['sigoplimit'] == 20000
+ assert tmpl['transactions'][0]['hash'] == txid
+ assert tmpl['transactions'][0]['sigops'] == 2
self.nodes[0].generate(1) # block 162
balance_presetup = self.nodes[0].getbalance()
@@ -131,7 +137,7 @@ class SegWitTest(BitcoinTestFramework):
p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999")))
self.nodes[0].generate(1) # block 163
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Make sure all nodes recognize the transactions as theirs
assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
@@ -139,7 +145,7 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))
self.nodes[0].generate(260) # block 423
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.log.info("Verify witness txs are skipped for mining before the fork")
self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) # block 424
@@ -156,7 +162,7 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify previous witness txs skipped for mining can now be mined")
assert_equal(len(self.nodes[2].getrawmempool()), 4)
blockhash = self.nodes[2].generate(1)[0] # block 432 (first block with new rules; 432 = 144 * 3)
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(len(self.nodes[2].getrawmempool()), 0)
segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"]
assert_equal(len(segwit_tx_list), 5)
@@ -172,16 +178,16 @@ class SegWitTest(BitcoinTestFramework):
self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0]))
self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
- assert(self.nodes[2].getblock(blockhash, False) != self.nodes[0].getblock(blockhash, False))
- assert(self.nodes[1].getblock(blockhash, False) == self.nodes[2].getblock(blockhash, False))
+ assert self.nodes[2].getblock(blockhash, False) != self.nodes[0].getblock(blockhash, False)
+ assert self.nodes[1].getblock(blockhash, False) == self.nodes[2].getblock(blockhash, False)
for tx_id in segwit_tx_list:
tx = FromHex(CTransaction(), self.nodes[2].gettransaction(tx_id)["hex"])
- assert(self.nodes[2].getrawtransaction(tx_id, False, blockhash) != self.nodes[0].getrawtransaction(tx_id, False, blockhash))
- assert(self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].getrawtransaction(tx_id, False, blockhash))
- assert(self.nodes[0].getrawtransaction(tx_id, False, blockhash) != self.nodes[2].gettransaction(tx_id)["hex"])
- assert(self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].gettransaction(tx_id)["hex"])
- assert(self.nodes[0].getrawtransaction(tx_id, False, blockhash) == bytes_to_hex_str(tx.serialize_without_witness()))
+ assert self.nodes[2].getrawtransaction(tx_id, False, blockhash) != self.nodes[0].getrawtransaction(tx_id, False, blockhash)
+ assert self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].getrawtransaction(tx_id, False, blockhash)
+ assert self.nodes[0].getrawtransaction(tx_id, False, blockhash) != self.nodes[2].gettransaction(tx_id)["hex"]
+ assert self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].gettransaction(tx_id)["hex"]
+ assert self.nodes[0].getrawtransaction(tx_id, False, blockhash) == tx.serialize_without_witness().hex()
self.log.info("Verify witness txs without witness data are invalid after the fork")
self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch) (code 64)', wit_ids[NODE_2][WIT_V0][2], sign=False)
@@ -198,11 +204,11 @@ class SegWitTest(BitcoinTestFramework):
self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data
- assert(tmpl['weightlimit'] == 4000000)
- assert(tmpl['sigoplimit'] == 80000)
- assert(tmpl['transactions'][0]['txid'] == txid)
- assert(tmpl['transactions'][0]['sigops'] == 8)
+ assert tmpl['sizelimit'] >= 3999577 # actual maximum size is lower due to minimum mandatory non-witness data
+ assert tmpl['weightlimit'] == 4000000
+ assert tmpl['sigoplimit'] == 80000
+ assert tmpl['transactions'][0]['txid'] == txid
+ assert tmpl['transactions'][0]['sigops'] == 8
self.nodes[0].generate(1) # Mine a block to clear the gbt cache
@@ -214,8 +220,8 @@ class SegWitTest(BitcoinTestFramework):
txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996"))
hex_tx = self.nodes[0].gettransaction(txid)['hex']
tx = FromHex(CTransaction(), hex_tx)
- assert(tx.wit.is_null()) # This should not be a segwit input
- assert(txid1 in self.nodes[0].getrawmempool())
+ assert tx.wit.is_null() # This should not be a segwit input
+ assert txid1 in self.nodes[0].getrawmempool()
# Now create tx2, which will spend from txid1.
tx = CTransaction()
@@ -224,7 +230,7 @@ class SegWitTest(BitcoinTestFramework):
tx2_hex = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))['hex']
txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
tx = FromHex(CTransaction(), tx2_hex)
- assert(not tx.wit.is_null())
+ assert not tx.wit.is_null()
# Now create tx3, which will spend from txid2
tx = CTransaction()
@@ -232,15 +238,15 @@ class SegWitTest(BitcoinTestFramework):
tx.vout.append(CTxOut(int(49.95 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))) # Huge fee
tx.calc_sha256()
txid3 = self.nodes[0].sendrawtransaction(ToHex(tx))
- assert(tx.wit.is_null())
- assert(txid3 in self.nodes[0].getrawmempool())
+ assert tx.wit.is_null()
+ assert txid3 in self.nodes[0].getrawmempool()
# Check that getblocktemplate includes all transactions.
template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
template_txids = [t['txid'] for t in template['transactions']]
- assert(txid1 in template_txids)
- assert(txid2 in template_txids)
- assert(txid3 in template_txids)
+ assert txid1 in template_txids
+ assert txid2 in template_txids
+ assert txid3 in template_txids
# Check that wtxid is properly reported in mempool entry
assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True))
@@ -392,22 +398,22 @@ class SegWitTest(BitcoinTestFramework):
v = self.nodes[0].getaddressinfo(i)
if (v['isscript']):
bare = hex_str_to_bytes(v['hex'])
- importlist.append(bytes_to_hex_str(bare))
- importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(bare)])))
+ importlist.append(bare.hex())
+ importlist.append(CScript([OP_0, sha256(bare)]).hex())
else:
pubkey = hex_str_to_bytes(v['pubkey'])
p2pk = CScript([pubkey, OP_CHECKSIG])
p2pkh = CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG])
- importlist.append(bytes_to_hex_str(p2pk))
- importlist.append(bytes_to_hex_str(p2pkh))
- importlist.append(bytes_to_hex_str(CScript([OP_0, hash160(pubkey)])))
- importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(p2pk)])))
- importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(p2pkh)])))
+ importlist.append(p2pk.hex())
+ importlist.append(p2pkh.hex())
+ importlist.append(CScript([OP_0, hash160(pubkey)]).hex())
+ importlist.append(CScript([OP_0, sha256(p2pk)]).hex())
+ importlist.append(CScript([OP_0, sha256(p2pkh)]).hex())
- importlist.append(bytes_to_hex_str(unsolvablep2pkh))
- importlist.append(bytes_to_hex_str(unsolvablep2wshp2pkh))
- importlist.append(bytes_to_hex_str(op1))
- importlist.append(bytes_to_hex_str(p2wshop1))
+ importlist.append(unsolvablep2pkh.hex())
+ importlist.append(unsolvablep2wshp2pkh.hex())
+ importlist.append(op1.hex())
+ importlist.append(p2wshop1.hex())
for i in importlist:
# import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
@@ -535,10 +541,10 @@ class SegWitTest(BitcoinTestFramework):
for i in script_list:
tx.vout.append(CTxOut(10000000, i))
tx.rehash()
- signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex']
- txid = self.nodes[0].sendrawtransaction(signresults, True)
+ signresults = self.nodes[0].signrawtransactionwithwallet(tx.serialize_without_witness().hex())['hex']
+ txid = self.nodes[0].sendrawtransaction(signresults, 0)
txs_mined[txid] = self.nodes[0].generate(1)[0]
- sync_blocks(self.nodes)
+ self.sync_blocks()
watchcount = 0
spendcount = 0
for i in self.nodes[0].listunspent():
@@ -587,10 +593,10 @@ class SegWitTest(BitcoinTestFramework):
tx.vin.append(CTxIn(COutPoint(int('0x' + i, 0), j)))
tx.vout.append(CTxOut(0, CScript()))
tx.rehash()
- signresults = self.nodes[0].signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize_without_witness()))['hex']
- self.nodes[0].sendrawtransaction(signresults, True)
+ signresults = self.nodes[0].signrawtransactionwithwallet(tx.serialize_without_witness().hex())['hex']
+ self.nodes[0].sendrawtransaction(signresults, 0)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
if __name__ == '__main__':
diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py
index 1ced618d47..0713925141 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-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test version bits warning system.
@@ -74,8 +74,8 @@ class VersionBitsWarningTest(BitcoinTestFramework):
node.generatetoaddress(VB_PERIOD - VB_THRESHOLD + 1, node_deterministic_address)
# Check that we're not getting any versionbit-related errors in get*info()
- assert(not VB_PATTERN.match(node.getmininginfo()["warnings"]))
- assert(not VB_PATTERN.match(node.getnetworkinfo()["warnings"]))
+ assert not VB_PATTERN.match(node.getmininginfo()["warnings"])
+ assert not VB_PATTERN.match(node.getnetworkinfo()["warnings"])
# Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit
self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION)
@@ -95,8 +95,8 @@ class VersionBitsWarningTest(BitcoinTestFramework):
# Generating one more block will be enough to generate an error.
node.generatetoaddress(1, node_deterministic_address)
# Check that get*info() shows the versionbits unknown rules warning
- assert(WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()["warnings"])
- assert(WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()["warnings"])
+ assert WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()["warnings"]
+ assert WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()["warnings"]
# Check that the alert file shows the versionbits unknown rules warning
wait_until(lambda: self.versionbits_in_alert_file(), timeout=60)
diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py
index aed439339f..7bb7044cc0 100755
--- a/test/functional/interface_bitcoin_cli.py
+++ b/test/functional/interface_bitcoin_cli.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test bitcoin-cli"""
@@ -16,7 +16,7 @@ class TestBitcoinCli(BitcoinTestFramework):
"""Main test logic"""
cli_response = self.nodes[0].cli("-version").send_cli()
- assert("Bitcoin Core RPC client version" in cli_response)
+ assert "{} RPC client version".format(self.config['environment']['PACKAGE_NAME']) in cli_response
self.log.info("Compare responses from getwalletinfo RPC and `bitcoin-cli getwalletinfo`")
if self.is_wallet_compiled():
@@ -57,16 +57,14 @@ class TestBitcoinCli(BitcoinTestFramework):
assert_equal(cli_get_info['version'], network_info['version'])
assert_equal(cli_get_info['protocolversion'], network_info['protocolversion'])
- if self.is_wallet_compiled():
- assert_equal(cli_get_info['walletversion'], wallet_info['walletversion'])
- assert_equal(cli_get_info['balance'], wallet_info['balance'])
assert_equal(cli_get_info['blocks'], blockchain_info['blocks'])
assert_equal(cli_get_info['timeoffset'], network_info['timeoffset'])
assert_equal(cli_get_info['connections'], network_info['connections'])
assert_equal(cli_get_info['proxy'], network_info['networks'][0]['proxy'])
assert_equal(cli_get_info['difficulty'], blockchain_info['difficulty'])
- assert_equal(cli_get_info['testnet'], blockchain_info['chain'] == "test")
+ assert_equal(cli_get_info['chain'], blockchain_info['chain'])
if self.is_wallet_compiled():
+ assert_equal(cli_get_info['walletversion'], wallet_info['walletversion'])
assert_equal(cli_get_info['balance'], wallet_info['balance'])
assert_equal(cli_get_info['keypoololdest'], wallet_info['keypoololdest'])
assert_equal(cli_get_info['keypoolsize'], wallet_info['keypoolsize'])
diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py
index 20889366e5..bb868d7115 100755
--- a/test/functional/interface_http.py
+++ b/test/functional/interface_http.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the RPC HTTP basics."""
@@ -30,14 +30,14 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1)
- assert(conn.sock is not None) #according to http/1.1 connection must still be open!
+ assert b'"error":null' in out1
+ assert conn.sock is not None #according to http/1.1 connection must still be open!
#send 2nd request without closing connection
conn.request('POST', '/', '{"method": "getchaintips"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1) #must also response with a correct json-rpc message
- assert(conn.sock is not None) #according to http/1.1 connection must still be open!
+ assert b'"error":null' in out1 #must also response with a correct json-rpc message
+ assert conn.sock is not None #according to http/1.1 connection must still be open!
conn.close()
#same should be if we add keep-alive because this should be the std. behaviour
@@ -47,14 +47,14 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1)
- assert(conn.sock is not None) #according to http/1.1 connection must still be open!
+ assert b'"error":null' in out1
+ assert conn.sock is not None #according to http/1.1 connection must still be open!
#send 2nd request without closing connection
conn.request('POST', '/', '{"method": "getchaintips"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1) #must also response with a correct json-rpc message
- assert(conn.sock is not None) #according to http/1.1 connection must still be open!
+ assert b'"error":null' in out1 #must also response with a correct json-rpc message
+ assert conn.sock is not None #according to http/1.1 connection must still be open!
conn.close()
#now do the same with "Connection: close"
@@ -64,8 +64,8 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1)
- assert(conn.sock is None) #now the connection must be closed after the response
+ assert b'"error":null' in out1
+ assert conn.sock is None #now the connection must be closed after the response
#node1 (2nd node) is running with disabled keep-alive option
urlNode1 = urllib.parse.urlparse(self.nodes[1].url)
@@ -76,7 +76,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1)
+ assert b'"error":null' in out1
#node2 (third node) is running with standard keep-alive parameters which means keep-alive is on
urlNode2 = urllib.parse.urlparse(self.nodes[2].url)
@@ -87,8 +87,8 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
out1 = conn.getresponse().read()
- assert(b'"error":null' in out1)
- assert(conn.sock is not None) #connection must be closed because bitcoind should use keep-alive by default
+ assert b'"error":null' in out1
+ assert conn.sock is not None #connection must be closed because bitcoind should use keep-alive by default
# Check excessive request size
conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port)
diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py
index f33040242c..a036dfc790 100755
--- a/test/functional/interface_rest.py
+++ b/test/functional/interface_rest.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the REST API."""
@@ -152,7 +152,7 @@ class RESTTest (BitcoinTestFramework):
bin_response = self.test_rest_request("/getutxos", http_method='POST', req_type=ReqType.BIN, body=bin_request, ret_type=RetType.BYTES)
output = BytesIO(bin_response)
chain_height, = unpack("i", output.read(4))
- response_hash = binascii.hexlify(output.read(32)[::-1]).decode('ascii')
+ response_hash = output.read(32)[::-1].hex()
assert_equal(bb_hash, response_hash) # check if getutxo's chaintip during calculation was fine
assert_equal(chain_height, 102) # chain height must be 102
@@ -252,7 +252,7 @@ class RESTTest (BitcoinTestFramework):
resp_hex = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.HEX, ret_type=RetType.OBJ)
assert_equal(resp_hex.read().decode('utf-8').rstrip(), bb_hash)
resp_bytes = self.test_rest_request("/blockhashbyheight/{}".format(block_json_obj['height']), req_type=ReqType.BIN, ret_type=RetType.BYTES)
- blockhash = binascii.hexlify(resp_bytes[::-1]).decode('utf-8')
+ blockhash = resp_bytes[::-1].hex()
assert_equal(blockhash, bb_hash)
# Check invalid blockhashbyheight requests
diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py
index b6955d4492..49ae0fb1a9 100755
--- a/test/functional/interface_rpc.py
+++ b/test/functional/interface_rpc.py
@@ -1,12 +1,22 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
"""Tests some generic aspects of the RPC interface."""
+from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than_or_equal
+def expect_http_status(expected_http_status, expected_rpc_code,
+ fcn, *args):
+ try:
+ fcn(*args)
+ raise AssertionError("Expected RPC error %d, got none" % expected_rpc_code)
+ except JSONRPCException as exc:
+ assert_equal(exc.error["code"], expected_rpc_code)
+ assert_equal(exc.http_status, expected_http_status)
+
class RPCInterfaceTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
@@ -48,9 +58,16 @@ class RPCInterfaceTest(BitcoinTestFramework):
assert_equal(result_by_id[3]['error'], None)
assert result_by_id[3]['result'] is not None
+ def test_http_status_codes(self):
+ self.log.info("Testing HTTP status codes for JSON-RPC requests...")
+
+ expect_http_status(404, -32601, self.nodes[0].invalidmethod)
+ expect_http_status(500, -8, self.nodes[0].getblockhash, 42)
+
def run_test(self):
self.test_getrpcinfo()
self.test_batch_request()
+ self.test_http_status_codes()
if __name__ == '__main__':
diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py
index 94fea37090..8e58c85c15 100755
--- a/test/functional/interface_zmq.py
+++ b/test/functional/interface_zmq.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test the ZMQ notification interface."""
@@ -10,7 +10,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.messages import CTransaction
from test_framework.util import (
assert_equal,
- bytes_to_hex_str,
hash256,
)
from io import BytesIO
@@ -94,17 +93,17 @@ class ZMQTest (BitcoinTestFramework):
tx = CTransaction()
tx.deserialize(BytesIO(hex))
tx.calc_sha256()
- assert_equal(tx.hash, bytes_to_hex_str(txid))
+ assert_equal(tx.hash, txid.hex())
# Should receive the generated block hash.
- hash = bytes_to_hex_str(self.hashblock.receive())
+ hash = self.hashblock.receive().hex()
assert_equal(genhashes[x], hash)
# The block should only have the coinbase txid.
- assert_equal([bytes_to_hex_str(txid)], self.nodes[1].getblock(hash)["tx"])
+ assert_equal([txid.hex()], self.nodes[1].getblock(hash)["tx"])
# Should receive the generated raw block.
block = self.rawblock.receive()
- assert_equal(genhashes[x], bytes_to_hex_str(hash256(block[:80])))
+ assert_equal(genhashes[x], hash256(block[:80]).hex())
if self.is_wallet_compiled():
self.log.info("Wait for tx from second node")
@@ -113,11 +112,11 @@ class ZMQTest (BitcoinTestFramework):
# Should receive the broadcasted txid.
txid = self.hashtx.receive()
- assert_equal(payment_txid, bytes_to_hex_str(txid))
+ assert_equal(payment_txid, txid.hex())
# Should receive the broadcasted raw transaction.
hex = self.rawtx.receive()
- assert_equal(payment_txid, bytes_to_hex_str(hash256(hex)))
+ assert_equal(payment_txid, hash256(hex).hex())
self.log.info("Test the getzmqnotifications RPC")
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index efe720b9b1..2bb5d8ab7d 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test mempool acceptance of raw transactions."""
@@ -27,7 +27,6 @@ from test_framework.script import (
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
- bytes_to_hex_str,
hex_str_to_bytes,
)
@@ -69,7 +68,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
inputs=[{'txid': coin['txid'], 'vout': coin['vout']}],
outputs=[{node.getnewaddress(): 0.3}, {node.getnewaddress(): 49}],
))['hex']
- txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block, allowhighfees=True)
+ txid_in_block = node.sendrawtransaction(hexstring=raw_tx_in_block, maxfeerate=0)
node.generate(1)
self.mempool_size = 0
self.check_mempool_result(
@@ -101,10 +100,10 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final)))
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': True}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
- allowhighfees=True,
+ rawtxs=[tx.serialize().hex()],
+ maxfeerate=0,
)
- node.sendrawtransaction(hexstring=raw_tx_final, allowhighfees=True)
+ node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0)
self.mempool_size += 1
self.log.info('A transaction in the mempool')
@@ -119,7 +118,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
tx.vout[0].nValue -= int(fee * COIN) # Double the fee
tx.vin[0].nSequence = BIP125_SEQUENCE_NUMBER + 1 # Now, opt out of RBF
- raw_tx_0 = node.signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize()))['hex']
+ raw_tx_0 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
txid_0 = tx.rehash()
self.check_mempool_result(
@@ -129,15 +128,15 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
self.log.info('A transaction that conflicts with an unconfirmed tx')
# Send the transaction that replaces the mempool transaction and opts out of replaceability
- node.sendrawtransaction(hexstring=bytes_to_hex_str(tx.serialize()), allowhighfees=True)
+ node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
# take original raw_tx_0
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
tx.vout[0].nValue -= int(4 * fee * COIN) # Set more fee
# skip re-signing the tx
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '18: txn-mempool-conflict'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
- allowhighfees=True,
+ rawtxs=[tx.serialize().hex()],
+ maxfeerate=0,
)
self.log.info('A transaction with missing inputs, that never existed')
@@ -146,14 +145,14 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
# skip re-signing the tx
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction with missing inputs, that existed once in the past')
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0)))
tx.vin[0].prevout.n = 1 # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
- raw_tx_1 = node.signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize()))['hex']
- txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, allowhighfees=True)
+ raw_tx_1 = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
+ txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
# Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
raw_tx_spend_both = node.signrawtransactionwithwallet(node.createrawtransaction(
inputs=[
@@ -162,7 +161,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
],
outputs=[{node.getnewaddress(): 0.1}]
))['hex']
- txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both, allowhighfees=True)
+ txid_spend_both = node.sendrawtransaction(hexstring=raw_tx_spend_both, maxfeerate=0)
node.generate(1)
self.mempool_size = 0
# Now see if we can add the coins back to the utxo set by sending the exact txs again
@@ -184,17 +183,17 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
# Reference tx should be valid on itself
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': True}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction with no outputs')
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout = []
# Skip re-signing the transaction for context independent checks from now on
- # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize()))['hex'])))
+ # tx.deserialize(BytesIO(hex_str_to_bytes(node.signrawtransactionwithwallet(tx.serialize().hex())['hex'])))
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-empty'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A really large transaction')
@@ -202,7 +201,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vin = [tx.vin[0]] * math.ceil(MAX_BLOCK_BASE_SIZE / len(tx.vin[0].serialize()))
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-oversize'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction with negative output value')
@@ -210,7 +209,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout[0].nValue *= -1
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-negative'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction with too large output value')
@@ -218,7 +217,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout[0].nValue = 21000000 * COIN + 1
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-vout-toolarge'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction with too large sum of output values')
@@ -227,7 +226,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout[0].nValue = 21000000 * COIN
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-txouttotal-toolarge'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction with duplicate inputs')
@@ -235,7 +234,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vin = [tx.vin[0]] * 2
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: bad-txns-inputs-duplicate'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A coinbase transaction')
@@ -244,7 +243,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_coinbase_spent)))
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '16: coinbase'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('Some nonstandard transactions')
@@ -252,19 +251,19 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.nVersion = 3 # A version currently non-standard
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: version'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].scriptPubKey = CScript([OP_0]) # Some non-standard script
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptpubkey'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vin[0].scriptSig = CScript([OP_HASH160]) # Some not-pushonly scriptSig
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: scriptsig-not-pushonly'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=CScript([OP_HASH160, hash160(b'burn'), OP_EQUAL]))
@@ -272,21 +271,21 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout = [output_p2sh_burn] * num_scripts
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: tx-size'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0] = output_p2sh_burn
tx.vout[0].nValue -= 1 # Make output smaller, such that it is dust for our policy
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: dust'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference)))
tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
tx.vout = [tx.vout[0]] * 2
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: multi-op-return'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A timelocked transaction')
@@ -295,7 +294,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.nLockTime = node.getblockcount() + 1
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-final'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
+ rawtxs=[tx.serialize().hex()],
)
self.log.info('A transaction that is locked by BIP68 sequence logic')
@@ -304,8 +303,8 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
# Can skip re-signing the tx because of early rejection
self.check_mempool_result(
result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': '64: non-BIP68-final'}],
- rawtxs=[bytes_to_hex_str(tx.serialize())],
- allowhighfees=True,
+ rawtxs=[tx.serialize().hex()],
+ maxfeerate=0,
)
diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py
index c0918893cd..351b27e94a 100755
--- a/test/functional/mempool_limit.py
+++ b/test/functional/mempool_limit.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test mempool limiting together/eviction with the wallet."""
@@ -47,9 +47,9 @@ class MempoolLimitTest(BitcoinTestFramework):
txids[i] = create_lots_of_big_transactions(self.nodes[0], txouts, utxos[30*i:30*i+30], 30, (i+1)*base_fee)
self.log.info('The tx should be evicted by now')
- assert(txid not in self.nodes[0].getrawmempool())
+ assert txid not in self.nodes[0].getrawmempool()
txdata = self.nodes[0].gettransaction(txid)
- assert(txdata['confirmations'] == 0) #confirmation should still be 0
+ assert txdata['confirmations'] == 0 #confirmation should still be 0
self.log.info('Check that mempoolminfee is larger than minrelytxfee')
assert_equal(self.nodes[0].getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 9336547a6b..c7d241503a 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test descendant package tracking code."""
@@ -8,7 +8,11 @@ from decimal import Decimal
from test_framework.messages import COIN
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round, sync_blocks, sync_mempools
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ satoshi_round,
+)
MAX_ANCESTORS = 25
MAX_DESCENDANTS = 25
@@ -33,7 +37,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
signedtx = node.signrawtransactionwithwallet(rawtx)
txid = node.sendrawtransaction(signedtx['hex'])
fulltx = node.getrawtransaction(txid, 1)
- assert(len(fulltx['vout']) == num_outputs) # make sure we didn't generate a change output
+ assert len(fulltx['vout']) == num_outputs # make sure we didn't generate a change output
return (txid, send_value)
def run_test(self):
@@ -58,9 +62,9 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(len(mempool), MAX_ANCESTORS)
descendant_count = 1
descendant_fees = 0
- descendant_size = 0
+ descendant_vsize = 0
- ancestor_size = sum([mempool[tx]['size'] for tx in mempool])
+ ancestor_vsize = sum([mempool[tx]['vsize'] for tx in mempool])
ancestor_count = MAX_ANCESTORS
ancestor_fees = sum([mempool[tx]['fee'] for tx in mempool])
@@ -79,15 +83,15 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x]['fees']['modified'], mempool[x]['modifiedfee'])
assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN)
assert_equal(mempool[x]['fees']['descendant'], descendant_fees)
- descendant_size += mempool[x]['size']
- assert_equal(mempool[x]['descendantsize'], descendant_size)
+ descendant_vsize += mempool[x]['vsize']
+ assert_equal(mempool[x]['descendantsize'], descendant_vsize)
descendant_count += 1
# Check that ancestor calculations are correct
assert_equal(mempool[x]['ancestorcount'], ancestor_count)
assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN)
- assert_equal(mempool[x]['ancestorsize'], ancestor_size)
- ancestor_size -= mempool[x]['size']
+ assert_equal(mempool[x]['ancestorsize'], ancestor_vsize)
+ ancestor_vsize -= mempool[x]['vsize']
ancestor_fees -= mempool[x]['fee']
ancestor_count -= 1
@@ -125,13 +129,13 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(len(v_ancestors), len(chain)-1)
for x in v_ancestors.keys():
assert_equal(mempool[x], v_ancestors[x])
- assert(chain[-1] not in v_ancestors.keys())
+ assert chain[-1] not in v_ancestors.keys()
v_descendants = self.nodes[0].getmempooldescendants(chain[0], True)
assert_equal(len(v_descendants), len(chain)-1)
for x in v_descendants.keys():
assert_equal(mempool[x], v_descendants[x])
- assert(chain[0] not in v_descendants.keys())
+ assert chain[0] not in v_descendants.keys()
# Check that ancestor modified fees includes fee deltas from
# prioritisetransaction
@@ -163,7 +167,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Check that prioritising a tx before it's added to the mempool works
# First clear the mempool by mining a block.
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(len(self.nodes[0].getrawmempool()), 0)
# Prioritise a transaction that has been mined, then add it back to the
# mempool by using invalidateblock.
@@ -228,7 +232,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Test reorg handling
# First, the basics:
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.nodes[1].invalidateblock(self.nodes[0].getbestblockhash())
self.nodes[1].reconsiderblock(self.nodes[0].getbestblockhash())
@@ -283,12 +287,12 @@ class MempoolPackagesTest(BitcoinTestFramework):
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
txid = self.nodes[0].sendrawtransaction(signedtx['hex'])
- sync_mempools(self.nodes)
+ self.sync_mempools()
# Now try to disconnect the tip on each node...
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
- sync_blocks(self.nodes)
+ self.sync_blocks()
if __name__ == '__main__':
MempoolPackagesTest().main()
diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py
index d74d4eaaf1..bb0169ee52 100755
--- a/test/functional/mempool_persist.py
+++ b/test/functional/mempool_persist.py
@@ -37,7 +37,6 @@ Test is as follows:
"""
from decimal import Decimal
import os
-import time
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error, wait_until
@@ -83,9 +82,10 @@ class MempoolPersistTest(BitcoinTestFramework):
self.start_node(1, extra_args=["-persistmempool=0"])
self.start_node(0)
self.start_node(2)
- # Give bitcoind a second to reload the mempool
- wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5, timeout=1)
- wait_until(lambda: len(self.nodes[2].getrawmempool()) == 5, timeout=1)
+ wait_until(lambda: self.nodes[0].getmempoolinfo()["loaded"], timeout=1)
+ wait_until(lambda: self.nodes[2].getmempoolinfo()["loaded"], timeout=1)
+ assert_equal(len(self.nodes[0].getrawmempool()), 5)
+ assert_equal(len(self.nodes[2].getrawmempool()), 5)
# The others have loaded their mempool. If node_1 loaded anything, we'd probably notice by now:
assert_equal(len(self.nodes[1].getrawmempool()), 0)
@@ -100,14 +100,14 @@ class MempoolPersistTest(BitcoinTestFramework):
self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
self.stop_nodes()
self.start_node(0, extra_args=["-persistmempool=0"])
- # Give bitcoind a second to reload the mempool
- time.sleep(1)
+ wait_until(lambda: self.nodes[0].getmempoolinfo()["loaded"])
assert_equal(len(self.nodes[0].getrawmempool()), 0)
self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.")
self.stop_nodes()
self.start_node(0)
- wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5)
+ wait_until(lambda: self.nodes[0].getmempoolinfo()["loaded"])
+ assert_equal(len(self.nodes[0].getrawmempool()), 5)
mempooldat0 = os.path.join(self.nodes[0].datadir, 'regtest', 'mempool.dat')
mempooldat1 = os.path.join(self.nodes[1].datadir, 'regtest', 'mempool.dat')
@@ -120,7 +120,8 @@ class MempoolPersistTest(BitcoinTestFramework):
os.rename(mempooldat0, mempooldat1)
self.stop_nodes()
self.start_node(1, extra_args=[])
- wait_until(lambda: len(self.nodes[1].getrawmempool()) == 5)
+ wait_until(lambda: self.nodes[1].getmempoolinfo()["loaded"])
+ assert_equal(len(self.nodes[1].getrawmempool()), 5)
self.log.debug("Prevent bitcoind from writing mempool.dat to disk. Verify that `savemempool` fails")
# to test the exception we are creating a tmp folder called mempool.dat.new
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 845beb551e..187c9026f6 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test resurrection of mined transactions when the blockchain is re-organized."""
@@ -45,7 +45,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
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 tx["confirmations"] > 0
# Use invalidateblock to re-org back
for node in self.nodes:
@@ -55,7 +55,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
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 tx["confirmations"] == 0
# Generate another block, they should all get mined
self.nodes[0].generate(1)
@@ -63,7 +63,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework):
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 tx["confirmations"] > 0
if __name__ == '__main__':
diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py
index d0bef48cb6..788aabc192 100755
--- a/test/functional/mining_basic.py
+++ b/test/functional/mining_basic.py
@@ -27,7 +27,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
- bytes_to_hex_str as b2x,
connect_nodes_bi,
)
from test_framework.script import CScriptNum
@@ -36,7 +35,7 @@ from test_framework.script import CScriptNum
def assert_template(node, block, expect, rehash=True):
if rehash:
block.hashMerkleRoot = block.calc_merkle_root()
- rsp = node.getblocktemplate(template_request={'data': b2x(block.serialize()), 'mode': 'proposal', 'rules': ['segwit']})
+ rsp = node.getblocktemplate(template_request={'data': block.serialize().hex(), 'mode': 'proposal', 'rules': ['segwit']})
assert_equal(rsp, expect)
@@ -64,8 +63,8 @@ class MiningTest(BitcoinTestFramework):
def assert_submitblock(block, result_str_1, result_str_2=None):
block.solve()
result_str_2 = result_str_2 or 'duplicate-invalid'
- assert_equal(result_str_1, node.submitblock(hexdata=b2x(block.serialize())))
- assert_equal(result_str_2, node.submitblock(hexdata=b2x(block.serialize())))
+ assert_equal(result_str_1, node.submitblock(hexdata=block.serialize().hex()))
+ assert_equal(result_str_2, node.submitblock(hexdata=block.serialize().hex()))
self.log.info('getmininginfo')
mining_info = node.getmininginfo()
@@ -112,7 +111,7 @@ class MiningTest(BitcoinTestFramework):
assert_template(node, block, None)
self.log.info("submitblock: Test block decode failure")
- assert_raises_rpc_error(-22, "Block decode failed", node.submitblock, b2x(block.serialize()[:-15]))
+ assert_raises_rpc_error(-22, "Block decode failed", node.submitblock, block.serialize()[:-15].hex())
self.log.info("getblocktemplate: Test bad input hash for coinbase transaction")
bad_block = copy.deepcopy(block)
@@ -121,10 +120,10 @@ class MiningTest(BitcoinTestFramework):
assert_template(node, bad_block, 'bad-cb-missing')
self.log.info("submitblock: Test invalid coinbase transaction")
- assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, b2x(bad_block.serialize()))
+ assert_raises_rpc_error(-22, "Block does not start with a coinbase", node.submitblock, bad_block.serialize().hex())
self.log.info("getblocktemplate: Test truncated final transaction")
- assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(block.serialize()[:-1]), 'mode': 'proposal', 'rules': ['segwit']})
+ assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': block.serialize()[:-1].hex(), 'mode': 'proposal', 'rules': ['segwit']})
self.log.info("getblocktemplate: Test duplicate transaction")
bad_block = copy.deepcopy(block)
@@ -153,7 +152,7 @@ class MiningTest(BitcoinTestFramework):
bad_block_sn = bytearray(block.serialize())
assert_equal(bad_block_sn[BLOCK_HEADER_SIZE], 1)
bad_block_sn[BLOCK_HEADER_SIZE] += 1
- assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': b2x(bad_block_sn), 'mode': 'proposal', 'rules': ['segwit']})
+ assert_raises_rpc_error(-22, "Block decode failed", node.getblocktemplate, {'data': bad_block_sn.hex(), 'mode': 'proposal', 'rules': ['segwit']})
self.log.info("getblocktemplate: Test bad bits")
bad_block = copy.deepcopy(block)
@@ -184,7 +183,7 @@ class MiningTest(BitcoinTestFramework):
self.log.info('submitheader tests')
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='xx' * BLOCK_HEADER_SIZE))
assert_raises_rpc_error(-22, 'Block header decode failed', lambda: node.submitheader(hexdata='ff' * (BLOCK_HEADER_SIZE-2)))
- assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata=b2x(super(CBlock, bad_block).serialize())))
+ assert_raises_rpc_error(-25, 'Must submit previous header', lambda: node.submitheader(hexdata=super(CBlock, bad_block).serialize().hex()))
block.nTime += 1
block.solve()
@@ -193,23 +192,23 @@ class MiningTest(BitcoinTestFramework):
return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status}
assert chain_tip(block.hash) not in node.getchaintips()
- node.submitheader(hexdata=b2x(block.serialize()))
+ node.submitheader(hexdata=block.serialize().hex())
assert chain_tip(block.hash) in node.getchaintips()
- node.submitheader(hexdata=b2x(CBlockHeader(block).serialize())) # Noop
+ node.submitheader(hexdata=CBlockHeader(block).serialize().hex()) # Noop
assert chain_tip(block.hash) in node.getchaintips()
bad_block_root = copy.deepcopy(block)
bad_block_root.hashMerkleRoot += 2
bad_block_root.solve()
assert chain_tip(bad_block_root.hash) not in node.getchaintips()
- node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
+ node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
assert chain_tip(bad_block_root.hash) in node.getchaintips()
# Should still reject invalid blocks, even if we have the header:
- assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot')
- assert_equal(node.submitblock(hexdata=b2x(bad_block_root.serialize())), 'bad-txnmrklroot')
+ assert_equal(node.submitblock(hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')
+ assert_equal(node.submitblock(hexdata=bad_block_root.serialize().hex()), 'bad-txnmrklroot')
assert chain_tip(bad_block_root.hash) in node.getchaintips()
# We know the header for this invalid block, so should just return early without error:
- node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
+ node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
assert chain_tip(bad_block_root.hash) in node.getchaintips()
bad_block_lock = copy.deepcopy(block)
@@ -217,19 +216,19 @@ class MiningTest(BitcoinTestFramework):
bad_block_lock.vtx[0].rehash()
bad_block_lock.hashMerkleRoot = bad_block_lock.calc_merkle_root()
bad_block_lock.solve()
- assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'bad-txns-nonfinal')
- assert_equal(node.submitblock(hexdata=b2x(bad_block_lock.serialize())), 'duplicate-invalid')
+ assert_equal(node.submitblock(hexdata=bad_block_lock.serialize().hex()), 'bad-txns-nonfinal')
+ assert_equal(node.submitblock(hexdata=bad_block_lock.serialize().hex()), 'duplicate-invalid')
# Build a "good" block on top of the submitted bad block
bad_block2 = copy.deepcopy(block)
bad_block2.hashPrevBlock = bad_block_lock.sha256
bad_block2.solve()
- assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
+ assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=CBlockHeader(bad_block2).serialize().hex()))
# Should reject invalid header right away
bad_block_time = copy.deepcopy(block)
bad_block_time.nTime = 1
bad_block_time.solve()
- assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
+ assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex()))
# Should ask for the block from a p2p node, if they announce the header as well:
node.add_p2p_connection(P2PDataStore())
@@ -240,11 +239,11 @@ class MiningTest(BitcoinTestFramework):
# Building a few blocks should give the same results
node.generatetoaddress(10, node.get_deterministic_priv_key().address)
- assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block_time).serialize())))
- assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=b2x(CBlockHeader(bad_block2).serialize())))
- node.submitheader(hexdata=b2x(CBlockHeader(block).serialize()))
- node.submitheader(hexdata=b2x(CBlockHeader(bad_block_root).serialize()))
- assert_equal(node.submitblock(hexdata=b2x(block.serialize())), 'duplicate') # valid
+ assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex()))
+ assert_raises_rpc_error(-25, 'bad-prevblk', lambda: node.submitheader(hexdata=CBlockHeader(bad_block2).serialize().hex()))
+ node.submitheader(hexdata=CBlockHeader(block).serialize().hex())
+ node.submitheader(hexdata=CBlockHeader(bad_block_root).serialize().hex())
+ assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid
if __name__ == '__main__':
diff --git a/test/functional/mining_getblocktemplate_longpoll.py b/test/functional/mining_getblocktemplate_longpoll.py
index 72cde8e811..445ec124ce 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-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test longpolling with getblocktemplate."""
@@ -38,27 +38,27 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
longpollid = template['longpollid']
# longpollid should not change between successive invocations if nothing else happens
template2 = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert(template2['longpollid'] == longpollid)
+ assert template2['longpollid'] == longpollid
# Test 1: test that the longpolling wait if we do nothing
thr = LongpollThread(self.nodes[0])
thr.start()
# check that thread still lives
thr.join(5) # wait 5 seconds or until thread exits
- assert(thr.is_alive())
+ assert thr.is_alive()
# Test 2: test that longpoll will terminate if another node generates a block
self.nodes[1].generate(1) # generate a block on another node
# check that thread will exit now that new transaction entered mempool
thr.join(5) # wait 5 seconds or until thread exits
- assert(not thr.is_alive())
+ assert not thr.is_alive()
# Test 3: test that longpoll will terminate if we generate a block ourselves
thr = LongpollThread(self.nodes[0])
thr.start()
self.nodes[0].generate(1) # generate a block on another node
thr.join(5) # wait 5 seconds or until thread exits
- assert(not thr.is_alive())
+ assert not thr.is_alive()
# Test 4: test that introducing a new transaction into the mempool will terminate the longpoll
thr = LongpollThread(self.nodes[0])
@@ -69,7 +69,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework):
(txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), min_relay_fee, Decimal("0.001"), 20)
# after one minute, every 10 seconds the mempool is probed, so in 80 seconds it should have returned
thr.join(60 + 20)
- assert(not thr.is_alive())
+ assert not thr.is_alive()
if __name__ == '__main__':
GetBlockTemplateLPTest().main()
diff --git a/test/functional/mining_prioritisetransaction.py b/test/functional/mining_prioritisetransaction.py
index ca4b621a78..b0a069be81 100755
--- a/test/functional/mining_prioritisetransaction.py
+++ b/test/functional/mining_prioritisetransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test the prioritisetransaction mining RPC."""
@@ -63,9 +63,9 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
sizes = [0, 0, 0]
for i in range(3):
for j in txids[i]:
- assert(j in mempool)
- sizes[i] += mempool[j]['size']
- assert(sizes[i] > MAX_BLOCK_BASE_SIZE) # Fail => raise utxo_count
+ assert j in mempool
+ sizes[i] += mempool[j]['vsize']
+ assert sizes[i] > MAX_BLOCK_BASE_SIZE # Fail => raise utxo_count
# add a fee delta to something in the cheapest bucket and make sure it gets mined
# also check that a different entry in the cheapest bucket is NOT mined
@@ -75,8 +75,8 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
mempool = self.nodes[0].getrawmempool()
self.log.info("Assert that prioritised transaction was mined")
- assert(txids[0][0] not in mempool)
- assert(txids[0][1] in mempool)
+ assert txids[0][0] not in mempool
+ assert txids[0][1] in mempool
high_fee_tx = None
for x in txids[2]:
@@ -84,7 +84,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
high_fee_tx = x
# Something high-fee should have been mined!
- assert(high_fee_tx is not None)
+ assert high_fee_tx is not None
# Add a prioritisation before a tx is in the mempool (de-prioritising a
# high-fee transaction so that it's now low fee).
@@ -95,7 +95,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Check to make sure our high fee rate tx is back in the mempool
mempool = self.nodes[0].getrawmempool()
- assert(high_fee_tx in mempool)
+ assert high_fee_tx in mempool
# Now verify the modified-high feerate transaction isn't mined before
# the other high fee transactions. Keep mining until our mempool has
@@ -107,14 +107,14 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# transactions should have been.
mempool = self.nodes[0].getrawmempool()
self.log.info("Assert that de-prioritised transaction is still in mempool")
- assert(high_fee_tx in mempool)
+ assert high_fee_tx in mempool
for x in txids[2]:
if (x != high_fee_tx):
- assert(x not in mempool)
+ assert x not in mempool
# Create a free transaction. Should be rejected.
utxo_list = self.nodes[0].listunspent()
- assert(len(utxo_list) > 0)
+ assert len(utxo_list) > 0
utxo = utxo_list[0]
inputs = []
@@ -127,7 +127,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# This will raise an exception due to min relay fee not being met
assert_raises_rpc_error(-26, "min relay fee not met", self.nodes[0].sendrawtransaction, tx_hex)
- assert(tx_id not in self.nodes[0].getrawmempool())
+ assert tx_id not in self.nodes[0].getrawmempool()
# This is a less than 1000-byte transaction, so just set the fee
# to be the minimum for a 1000-byte transaction and check that it is
@@ -136,7 +136,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.log.info("Assert that prioritised free transaction is accepted to mempool")
assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)
- assert(tx_id in self.nodes[0].getrawmempool())
+ assert tx_id in self.nodes[0].getrawmempool()
# Test that calling prioritisetransaction is sufficient to trigger
# getblocktemplate to (eventually) return a new block.
@@ -147,7 +147,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
self.nodes[0].setmocktime(mock_time+10)
new_template = self.nodes[0].getblocktemplate({'rules': ['segwit']})
- assert(template != new_template)
+ assert template != new_template
if __name__ == '__main__':
PrioritiseTransactionTest().main()
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
new file mode 100755
index 0000000000..12cb06a407
--- /dev/null
+++ b/test/functional/p2p_blocksonly.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# 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.
+"""Test p2p blocksonly"""
+
+from test_framework.messages import msg_tx, CTransaction, FromHex
+from test_framework.mininode import P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class P2PBlocksOnly(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 1
+ self.extra_args = [["-blocksonly"]]
+
+ def run_test(self):
+ self.nodes[0].add_p2p_connection(P2PInterface())
+
+ self.log.info('Check that txs from p2p are rejected')
+ 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']
+ assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], False)
+ with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']):
+ self.nodes[0].p2p.send_message(msg_tx(FromHex(CTransaction(), sigtx)))
+ self.nodes[0].p2p.sync_with_ping()
+ assert_equal(self.nodes[0].getmempoolinfo()['size'], 0)
+
+ self.log.info('Check that txs from rpc are not rejected and relayed to other peers')
+ assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True)
+ txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
+ with self.nodes[0].assert_debug_log(['received getdata for: tx {} peer=0'.format(txid)]):
+ self.nodes[0].sendrawtransaction(sigtx)
+ self.nodes[0].p2p.wait_for_tx(txid)
+ assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
+
+
+if __name__ == '__main__':
+ P2PBlocksOnly().main()
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index f0dee59b5c..0994857912 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test compact blocks (BIP 152).
@@ -7,19 +7,18 @@
Version 1 compact blocks are pre-segwit (txids)
Version 2 compact blocks are post-segwit (wtxids)
"""
-from decimal import Decimal
import random
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
-from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_block, msg_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_witness_block, msg_witness_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, NODE_WITNESS, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex
+from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.script import CScript, OP_TRUE, OP_DROP
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, get_bip9_status, satoshi_round, sync_blocks, wait_until
+from test_framework.util import assert_equal, get_bip9_status, wait_until
# TestP2PConn: A peer we use to send messages to bitcoind, and store responses.
class TestP2PConn(P2PInterface):
- def __init__(self):
+ def __init__(self, cmpct_version):
super().__init__()
self.last_sendcmpct = []
self.block_announced = False
@@ -27,6 +26,7 @@ class TestP2PConn(P2PInterface):
# This is for synchronizing the p2p message traffic,
# so we can eg wait until a particular block is announced.
self.announced_blockhashes = set()
+ self.cmpct_version = cmpct_version
def on_sendcmpct(self, message):
self.last_sendcmpct.append(message)
@@ -94,11 +94,7 @@ class TestP2PConn(P2PInterface):
class CompactBlocksTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- # Node0 = pre-segwit, node1 = segwit-aware
- self.num_nodes = 2
- # This test was written assuming SegWit is activated using BIP9 at height 432 (3x confirmation window).
- # TODO: Rewrite this test to support SegWit being always active.
- self.extra_args = [["-vbparams=segwit:0:0"], ["-vbparams=segwit:0:999999999999", "-txindex"]]
+ self.num_nodes = 1
self.utxos = []
def skip_test_if_missing_module(self):
@@ -117,11 +113,10 @@ class CompactBlocksTest(BitcoinTestFramework):
# Create 10 more anyone-can-spend utxo's for testing.
def make_utxos(self):
- # Doesn't matter which node we use, just use node0.
block = self.build_block_on_tip(self.nodes[0])
- self.test_node.send_and_ping(msg_block(block))
- assert(int(self.nodes[0].getbestblockhash(), 16) == block.sha256)
- self.nodes[0].generate(100)
+ self.segwit_node.send_and_ping(msg_no_witness_block(block))
+ assert int(self.nodes[0].getbestblockhash(), 16) == block.sha256
+ self.nodes[0].generatetoaddress(100, self.nodes[0].getnewaddress(address_type="bech32"))
total_value = block.vtx[0].vout[0].nValue
out_value = total_value // 10
@@ -135,10 +130,10 @@ class CompactBlocksTest(BitcoinTestFramework):
block2.vtx.append(tx)
block2.hashMerkleRoot = block2.calc_merkle_root()
block2.solve()
- self.test_node.send_and_ping(msg_block(block2))
+ self.segwit_node.send_and_ping(msg_no_witness_block(block2))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block2.sha256)
self.utxos.extend([[tx.sha256, i, out_value] for i in range(10)])
- return
+
# Test "sendcmpct" (between peers preferring the same version):
# - No compact block announcements unless sendcmpct is sent.
@@ -149,7 +144,10 @@ class CompactBlocksTest(BitcoinTestFramework):
# are made with compact blocks.
# If old_node is passed in, request compact blocks with version=preferred-1
# and verify that it receives block announcements via compact block.
- def test_sendcmpct(self, node, test_node, preferred_version, old_node=None):
+ def test_sendcmpct(self, test_node, old_node=None):
+ preferred_version = test_node.cmpct_version
+ node = self.nodes[0]
+
# Make sure we get a SENDCMPCT message from our peer
def received_sendcmpct():
return (len(test_node.last_sendcmpct) > 0)
@@ -167,7 +165,7 @@ class CompactBlocksTest(BitcoinTestFramework):
peer.clear_block_announcement()
block_hash = int(node.generate(1)[0], 16)
peer.wait_for_block_announcement(block_hash, timeout=30)
- assert(peer.block_announced)
+ assert peer.block_announced
with mininode_lock:
assert predicate(peer), (
@@ -251,23 +249,18 @@ class CompactBlocksTest(BitcoinTestFramework):
# This index will be too high
prefilled_txn = PrefilledTransaction(1, block.vtx[0])
cmpct_block.prefilled_txn = [prefilled_txn]
- self.test_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
+ self.segwit_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
# Compare the generated shortids to what we expect based on BIP 152, given
# bitcoind's choice of nonce.
- def test_compactblock_construction(self, node, test_node, version, use_witness_address):
+ def test_compactblock_construction(self, test_node, use_witness_address=True):
+ version = test_node.cmpct_version
+ node = self.nodes[0]
# Generate a bunch of transactions.
node.generate(101)
num_transactions = 25
address = node.getnewaddress()
- if use_witness_address:
- # Want at least one segwit spend, so move all funds to
- # a witness address.
- address = node.getnewaddress(address_type='bech32')
- value_to_send = node.getbalance()
- node.sendtoaddress(address, satoshi_round(value_to_send - Decimal(0.1)))
- node.generate(1)
segwit_tx_generated = False
for i in range(num_transactions):
@@ -285,7 +278,7 @@ class CompactBlocksTest(BitcoinTestFramework):
test_node.wait_for_block_announcement(tip)
# Make sure we will receive a fast-announce compact block
- self.request_cb_announcements(test_node, node, version)
+ self.request_cb_announcements(test_node)
# Now mine a block, and look at the resulting compact block.
test_node.clear_block_announcement()
@@ -303,7 +296,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Now fetch and check the compact block
header_and_shortids = None
with mininode_lock:
- assert("cmpctblock" in test_node.last_message)
+ assert "cmpctblock" in test_node.last_message
# Convert the on-the-wire representation to absolute indexes
header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
@@ -319,7 +312,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Now fetch and check the compact block
header_and_shortids = None
with mininode_lock:
- assert("cmpctblock" in test_node.last_message)
+ assert "cmpctblock" in test_node.last_message
# Convert the on-the-wire representation to absolute indexes
header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
@@ -330,7 +323,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(header_and_shortids.header.sha256, block_hash)
# Make sure the prefilled_txn appears to have included the coinbase
- assert(len(header_and_shortids.prefilled_txn) >= 1)
+ assert len(header_and_shortids.prefilled_txn) >= 1
assert_equal(header_and_shortids.prefilled_txn[0].index, 0)
# Check that all prefilled_txn entries match what's in the block.
@@ -345,7 +338,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(wtxid, block.vtx[entry.index].calc_sha256(True))
else:
# Shouldn't have received a witness
- assert(entry.tx.wit.is_null())
+ assert entry.tx.wit.is_null()
# Check that the cmpctblock message announced all the transactions.
assert_equal(len(header_and_shortids.prefilled_txn) + len(header_and_shortids.shortids), len(block.vtx))
@@ -375,7 +368,9 @@ class CompactBlocksTest(BitcoinTestFramework):
# Post-segwit: upgraded nodes would only make this request of cb-version-2,
# NODE_WITNESS peers. Unupgraded nodes would still make this request of
# any cb-version-1-supporting peer.
- def test_compactblock_requests(self, node, test_node, version, segwit):
+ def test_compactblock_requests(self, test_node, segwit=True):
+ version = test_node.cmpct_version
+ node = self.nodes[0]
# Try announcing a block with an inv or header, expect a compactblock
# request
for announce in ["inv", "header"]:
@@ -407,15 +402,15 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
# Expect a getblocktxn message.
with mininode_lock:
- assert("getblocktxn" in test_node.last_message)
+ assert "getblocktxn" in test_node.last_message
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
assert_equal(absolute_indexes, [0]) # should be a coinbase request
# Send the coinbase, and verify that the tip advances.
if version == 2:
- msg = msg_witness_blocktxn()
- else:
msg = msg_blocktxn()
+ else:
+ msg = msg_no_witness_blocktxn()
msg.block_transactions.blockhash = block.sha256
msg.block_transactions.transactions = [block.vtx[0]]
test_node.send_and_ping(msg)
@@ -440,14 +435,16 @@ class CompactBlocksTest(BitcoinTestFramework):
# Test that we only receive getblocktxn requests for transactions that the
# node needs, and that responding to them causes the block to be
# reconstructed.
- def test_getblocktxn_requests(self, node, test_node, version):
+ def test_getblocktxn_requests(self, test_node):
+ version = test_node.cmpct_version
+ node = self.nodes[0]
with_witness = (version == 2)
def test_getblocktxn_response(compact_block, peer, expected_result):
msg = msg_cmpctblock(compact_block.to_p2p())
peer.send_and_ping(msg)
with mininode_lock:
- assert("getblocktxn" in peer.last_message)
+ assert "getblocktxn" in peer.last_message
absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute()
assert_equal(absolute_indexes, expected_result)
@@ -466,9 +463,9 @@ class CompactBlocksTest(BitcoinTestFramework):
test_getblocktxn_response(comp_block, test_node, [1, 2, 3, 4, 5])
- msg_bt = msg_blocktxn()
+ msg_bt = msg_no_witness_blocktxn()
if with_witness:
- msg_bt = msg_witness_blocktxn() # serialize with witnesses
+ msg_bt = msg_blocktxn() # serialize with witnesses
msg_bt.block_transactions = BlockTransactions(block.sha256, block.vtx[1:])
test_tip_after_message(node, test_node, msg_bt, block.sha256)
@@ -487,7 +484,7 @@ class CompactBlocksTest(BitcoinTestFramework):
block = self.build_block_with_transactions(node, utxo, 5)
self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
test_node.send_and_ping(msg_tx(block.vtx[1]))
- assert(block.vtx[1].hash in node.getrawmempool())
+ assert block.vtx[1].hash in node.getrawmempool()
# Prefill 4 out of the 6 transactions, and verify that only the one
# that was not in the mempool is requested.
@@ -508,7 +505,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Make sure all transactions were accepted.
mempool = node.getrawmempool()
for tx in block.vtx[1:]:
- assert(tx.hash in mempool)
+ assert tx.hash in mempool
# Clear out last request.
with mininode_lock:
@@ -519,13 +516,13 @@ class CompactBlocksTest(BitcoinTestFramework):
test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256)
with mininode_lock:
# Shouldn't have gotten a request for any transaction
- assert("getblocktxn" not in test_node.last_message)
+ assert "getblocktxn" not in test_node.last_message
# Incorrectly responding to a getblocktxn shouldn't cause the block to be
# permanently failed.
- def test_incorrect_blocktxn_response(self, node, test_node, version):
- if (len(self.utxos) == 0):
- self.make_utxos()
+ def test_incorrect_blocktxn_response(self, test_node):
+ version = test_node.cmpct_version
+ node = self.nodes[0]
utxo = self.utxos.pop(0)
block = self.build_block_with_transactions(node, utxo, 10)
@@ -537,7 +534,7 @@ class CompactBlocksTest(BitcoinTestFramework):
# Make sure all transactions were accepted.
mempool = node.getrawmempool()
for tx in block.vtx[1:6]:
- assert(tx.hash in mempool)
+ assert tx.hash in mempool
# Send compact block
comp_block = HeaderAndShortIDs()
@@ -545,7 +542,7 @@ class CompactBlocksTest(BitcoinTestFramework):
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
absolute_indexes = []
with mininode_lock:
- assert("getblocktxn" in test_node.last_message)
+ assert "getblocktxn" in test_node.last_message
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
assert_equal(absolute_indexes, [6, 7, 8, 9, 10])
@@ -557,9 +554,9 @@ class CompactBlocksTest(BitcoinTestFramework):
# different peer provide the block further down, so that we're still
# verifying that the block isn't marked bad permanently. This is good
# enough for now.
- msg = msg_blocktxn()
+ msg = msg_no_witness_blocktxn()
if version == 2:
- msg = msg_witness_blocktxn()
+ msg = msg_blocktxn()
msg.block_transactions = BlockTransactions(block.sha256, [block.vtx[5]] + block.vtx[7:])
test_node.send_and_ping(msg)
@@ -569,17 +566,19 @@ class CompactBlocksTest(BitcoinTestFramework):
# We should receive a getdata request
wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock)
assert_equal(len(test_node.last_message["getdata"].inv), 1)
- assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2 | MSG_WITNESS_FLAG)
+ assert test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2 | MSG_WITNESS_FLAG
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
# Deliver the block
if version == 2:
- test_node.send_and_ping(msg_witness_block(block))
- else:
test_node.send_and_ping(msg_block(block))
+ else:
+ test_node.send_and_ping(msg_no_witness_block(block))
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
- def test_getblocktxn_handler(self, node, test_node, version):
+ def test_getblocktxn_handler(self, test_node):
+ version = test_node.cmpct_version
+ node = self.nodes[0]
# bitcoind will not send blocktxn responses for blocks whose height is
# more than 10 blocks deep.
MAX_GETBLOCKTXN_DEPTH = 10
@@ -606,7 +605,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(tx.sha256, block.vtx[index].sha256)
if version == 1:
# Witnesses should have been stripped
- assert(tx.wit.is_null())
+ assert tx.wit.is_null()
else:
# Check that the witness matches
assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True))
@@ -626,7 +625,8 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16))
assert "blocktxn" not in test_node.last_message
- def test_compactblocks_not_at_tip(self, node, test_node):
+ def test_compactblocks_not_at_tip(self, test_node):
+ node = self.nodes[0]
# Test that requesting old compactblocks doesn't work.
MAX_CMPCTBLOCK_DEPTH = 5
new_blocks = []
@@ -669,7 +669,7 @@ class CompactBlocksTest(BitcoinTestFramework):
assert_equal(x["status"], "headers-only")
found = True
break
- assert(found)
+ assert found
# Requesting this block via getblocktxn should silently fail
# (to avoid fingerprinting attacks).
@@ -681,11 +681,8 @@ class CompactBlocksTest(BitcoinTestFramework):
with mininode_lock:
assert "blocktxn" not in test_node.last_message
- def activate_segwit(self, node):
- node.generate(144 * 3)
- assert_equal(get_bip9_status(node, "segwit")["status"], 'active')
-
- def test_end_to_end_block_relay(self, node, listeners):
+ def test_end_to_end_block_relay(self, listeners):
+ node = self.nodes[0]
utxo = self.utxos.pop(0)
block = self.build_block_with_transactions(node, utxo, 10)
@@ -706,8 +703,9 @@ class CompactBlocksTest(BitcoinTestFramework):
# Test that we don't get disconnected if we relay a compact block with valid header,
# but invalid transactions.
- def test_invalid_tx_in_compactblock(self, node, test_node, use_segwit):
- assert(len(self.utxos))
+ def test_invalid_tx_in_compactblock(self, test_node, use_segwit=True):
+ node = self.nodes[0]
+ assert len(self.utxos)
utxo = self.utxos[0]
block = self.build_block_with_transactions(node, utxo, 5)
@@ -728,22 +726,24 @@ class CompactBlocksTest(BitcoinTestFramework):
test_node.send_and_ping(msg)
# Check that the tip didn't advance
- assert(int(node.getbestblockhash(), 16) is not block.sha256)
+ assert int(node.getbestblockhash(), 16) is not block.sha256
test_node.sync_with_ping()
# Helper for enabling cb announcements
# Send the sendcmpct request and sync headers
- def request_cb_announcements(self, peer, node, version):
+ def request_cb_announcements(self, peer):
+ node = self.nodes[0]
tip = node.getbestblockhash()
peer.get_headers(locator=[int(tip, 16)], hashstop=0)
msg = msg_sendcmpct()
- msg.version = version
+ msg.version = peer.cmpct_version
msg.announce = True
peer.send_and_ping(msg)
- def test_compactblock_reconstruction_multiple_peers(self, node, stalling_peer, delivery_peer):
- assert(len(self.utxos))
+ def test_compactblock_reconstruction_multiple_peers(self, stalling_peer, delivery_peer):
+ node = self.nodes[0]
+ assert len(self.utxos)
def announce_cmpct_block(node, peer):
utxo = self.utxos.pop(0)
@@ -764,7 +764,7 @@ class CompactBlocksTest(BitcoinTestFramework):
delivery_peer.sync_with_ping()
mempool = node.getrawmempool()
for tx in block.vtx[1:]:
- assert(tx.hash in mempool)
+ assert tx.hash in mempool
delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
@@ -783,9 +783,9 @@ class CompactBlocksTest(BitcoinTestFramework):
cmpct_block.use_witness = True
delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
- assert(int(node.getbestblockhash(), 16) != block.sha256)
+ assert int(node.getbestblockhash(), 16) != block.sha256
- msg = msg_blocktxn()
+ msg = msg_no_witness_blocktxn()
msg.block_transactions.blockhash = block.sha256
msg.block_transactions.transactions = block.vtx[1:]
stalling_peer.send_and_ping(msg)
@@ -793,126 +793,55 @@ class CompactBlocksTest(BitcoinTestFramework):
def run_test(self):
# Setup the p2p connections
- self.test_node = self.nodes[0].add_p2p_connection(TestP2PConn())
- self.segwit_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK | NODE_WITNESS)
- self.old_node = self.nodes[1].add_p2p_connection(TestP2PConn(), services=NODE_NETWORK)
+ self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
+ self.old_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=1), services=NODE_NETWORK)
+ self.additional_segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn(cmpct_version=2))
# We will need UTXOs to construct transactions in later tests.
self.make_utxos()
- self.log.info("Running tests, pre-segwit activation:")
+ assert_equal(get_bip9_status(self.nodes[0], "segwit")["status"], 'active')
self.log.info("Testing SENDCMPCT p2p message... ")
- self.test_sendcmpct(self.nodes[0], self.test_node, 1)
- sync_blocks(self.nodes)
- self.test_sendcmpct(self.nodes[1], self.segwit_node, 2, old_node=self.old_node)
- sync_blocks(self.nodes)
+ self.test_sendcmpct(self.segwit_node, old_node=self.old_node)
+ self.test_sendcmpct(self.additional_segwit_node)
self.log.info("Testing compactblock construction...")
- self.test_compactblock_construction(self.nodes[0], self.test_node, 1, False)
- sync_blocks(self.nodes)
- self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, False)
- sync_blocks(self.nodes)
-
- self.log.info("Testing compactblock requests... ")
- self.test_compactblock_requests(self.nodes[0], self.test_node, 1, False)
- sync_blocks(self.nodes)
- self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, False)
- sync_blocks(self.nodes)
-
- self.log.info("Testing getblocktxn requests...")
- self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
- sync_blocks(self.nodes)
- self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
- sync_blocks(self.nodes)
-
- self.log.info("Testing getblocktxn handler...")
- self.test_getblocktxn_handler(self.nodes[0], self.test_node, 1)
- sync_blocks(self.nodes)
- self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
- self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
- sync_blocks(self.nodes)
-
- self.log.info("Testing compactblock requests/announcements not at chain tip...")
- self.test_compactblocks_not_at_tip(self.nodes[0], self.test_node)
- sync_blocks(self.nodes)
- self.test_compactblocks_not_at_tip(self.nodes[1], self.segwit_node)
- self.test_compactblocks_not_at_tip(self.nodes[1], self.old_node)
- sync_blocks(self.nodes)
-
- self.log.info("Testing handling of incorrect blocktxn responses...")
- self.test_incorrect_blocktxn_response(self.nodes[0], self.test_node, 1)
- sync_blocks(self.nodes)
- self.test_incorrect_blocktxn_response(self.nodes[1], self.segwit_node, 2)
- sync_blocks(self.nodes)
-
- # End-to-end block relay tests
- self.log.info("Testing end-to-end block relay...")
- self.request_cb_announcements(self.test_node, self.nodes[0], 1)
- self.request_cb_announcements(self.old_node, self.nodes[1], 1)
- self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
- self.test_end_to_end_block_relay(self.nodes[0], [self.segwit_node, self.test_node, self.old_node])
- self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
-
- self.log.info("Testing handling of invalid compact blocks...")
- self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
- self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, False)
- self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, False)
-
- self.log.info("Testing reconstructing compact blocks from all peers...")
- self.test_compactblock_reconstruction_multiple_peers(self.nodes[1], self.segwit_node, self.old_node)
- sync_blocks(self.nodes)
-
- # Advance to segwit activation
- self.log.info("Advancing to segwit activation")
- self.activate_segwit(self.nodes[1])
- self.log.info("Running tests, post-segwit activation...")
-
- self.log.info("Testing compactblock construction...")
- self.test_compactblock_construction(self.nodes[1], self.old_node, 1, True)
- self.test_compactblock_construction(self.nodes[1], self.segwit_node, 2, True)
- sync_blocks(self.nodes)
-
- self.log.info("Testing compactblock requests (unupgraded node)... ")
- self.test_compactblock_requests(self.nodes[0], self.test_node, 1, True)
-
- self.log.info("Testing getblocktxn requests (unupgraded node)...")
- self.test_getblocktxn_requests(self.nodes[0], self.test_node, 1)
-
- # Need to manually sync node0 and node1, because post-segwit activation,
- # node1 will not download blocks from node0.
- self.log.info("Syncing nodes...")
- assert(self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash())
- while (self.nodes[0].getblockcount() > self.nodes[1].getblockcount()):
- block_hash = self.nodes[0].getblockhash(self.nodes[1].getblockcount() + 1)
- self.nodes[1].submitblock(self.nodes[0].getblock(block_hash, False))
- assert_equal(self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())
+ self.test_compactblock_construction(self.old_node)
+ self.test_compactblock_construction(self.segwit_node)
self.log.info("Testing compactblock requests (segwit node)... ")
- self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, True)
+ self.test_compactblock_requests(self.segwit_node)
self.log.info("Testing getblocktxn requests (segwit node)...")
- self.test_getblocktxn_requests(self.nodes[1], self.segwit_node, 2)
- sync_blocks(self.nodes)
+ self.test_getblocktxn_requests(self.segwit_node)
self.log.info("Testing getblocktxn handler (segwit node should return witnesses)...")
- self.test_getblocktxn_handler(self.nodes[1], self.segwit_node, 2)
- self.test_getblocktxn_handler(self.nodes[1], self.old_node, 1)
+ self.test_getblocktxn_handler(self.segwit_node)
+ self.test_getblocktxn_handler(self.old_node)
+
+ self.log.info("Testing compactblock requests/announcements not at chain tip...")
+ self.test_compactblocks_not_at_tip(self.segwit_node)
+ self.test_compactblocks_not_at_tip(self.old_node)
+
+ self.log.info("Testing handling of incorrect blocktxn responses...")
+ self.test_incorrect_blocktxn_response(self.segwit_node)
+
+ self.log.info("Testing reconstructing compact blocks from all peers...")
+ self.test_compactblock_reconstruction_multiple_peers(self.segwit_node, self.additional_segwit_node)
# Test that if we submitblock to node1, we'll get a compact block
# announcement to all peers.
# (Post-segwit activation, blocks won't propagate from node0 to node1
# automatically, so don't bother testing a block announced to node0.)
self.log.info("Testing end-to-end block relay...")
- self.request_cb_announcements(self.test_node, self.nodes[0], 1)
- self.request_cb_announcements(self.old_node, self.nodes[1], 1)
- self.request_cb_announcements(self.segwit_node, self.nodes[1], 2)
- self.test_end_to_end_block_relay(self.nodes[1], [self.segwit_node, self.test_node, self.old_node])
+ self.request_cb_announcements(self.old_node)
+ self.request_cb_announcements(self.segwit_node)
+ self.test_end_to_end_block_relay([self.segwit_node, self.old_node])
self.log.info("Testing handling of invalid compact blocks...")
- self.test_invalid_tx_in_compactblock(self.nodes[0], self.test_node, False)
- self.test_invalid_tx_in_compactblock(self.nodes[1], self.segwit_node, True)
- self.test_invalid_tx_in_compactblock(self.nodes[1], self.old_node, True)
+ self.test_invalid_tx_in_compactblock(self.segwit_node)
+ self.test_invalid_tx_in_compactblock(self.old_node)
self.log.info("Testing invalid index in cmpctblock message...")
self.test_invalid_cmpctblock_message()
diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py
index d589519e45..7f901b1886 100755
--- a/test/functional/p2p_feefilter.py
+++ b/test/functional/p2p_feefilter.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test processing of feefilter messages."""
@@ -10,7 +10,7 @@ import time
from test_framework.messages import msg_feefilter
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import sync_blocks, sync_mempools
+
def hashToHex(hash):
return format(hash, '064x')
@@ -50,14 +50,14 @@ class FeeFilterTest(BitcoinTestFramework):
node0 = self.nodes[0]
# Get out of IBD
node1.generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.nodes[0].add_p2p_connection(TestP2PConn())
# Test that invs are received for all txs at feerate of 20 sat/byte
node1.settxfee(Decimal("0.00020000"))
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- assert(allInvsMatch(txids, self.nodes[0].p2p))
+ assert allInvsMatch(txids, self.nodes[0].p2p)
self.nodes[0].p2p.clear_invs()
# Set a filter of 15 sat/byte
@@ -65,13 +65,13 @@ class FeeFilterTest(BitcoinTestFramework):
# Test that txs are still being received (paying 20 sat/byte)
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- assert(allInvsMatch(txids, self.nodes[0].p2p))
+ assert allInvsMatch(txids, self.nodes[0].p2p)
self.nodes[0].p2p.clear_invs()
# Change tx fee rate to 10 sat/byte and test they are no longer received
node1.settxfee(Decimal("0.00010000"))
[node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- sync_mempools(self.nodes) # must be sure node 0 has received all txs
+ self.sync_mempools() # must be sure node 0 has received all txs
# Send one transaction from node0 that should be received, so that we
# we can sync the test on receipt (if node1's txs were relayed, they'd
@@ -82,13 +82,13 @@ class FeeFilterTest(BitcoinTestFramework):
# as well.
node0.settxfee(Decimal("0.00020000"))
txids = [node0.sendtoaddress(node0.getnewaddress(), 1)]
- assert(allInvsMatch(txids, self.nodes[0].p2p))
+ assert allInvsMatch(txids, self.nodes[0].p2p)
self.nodes[0].p2p.clear_invs()
# Remove fee filter and check that txs are received again
self.nodes[0].p2p.send_and_ping(msg_feefilter(0))
txids = [node1.sendtoaddress(node1.getnewaddress(), 1) for x in range(3)]
- assert(allInvsMatch(txids, self.nodes[0].p2p))
+ assert allInvsMatch(txids, self.nodes[0].p2p)
self.nodes[0].p2p.clear_invs()
if __name__ == '__main__':
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 700fdf6e04..481d697e63 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -3,11 +3,12 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test node responses to invalid network messages."""
+import asyncio
import os
import struct
from test_framework import messages
-from test_framework.mininode import P2PDataStore
+from test_framework.mininode import P2PDataStore, NetworkThread
from test_framework.test_framework import BitcoinTestFramework
@@ -143,8 +144,15 @@ class InvalidMessagesTest(BitcoinTestFramework):
def test_magic_bytes(self):
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
- conn._on_data = lambda: None # Need to ignore all incoming messages from now, since they come with "invalid" magic bytes
- conn.magic_bytes = b'\x00\x11\x22\x32'
+
+ def swap_magic_bytes():
+ conn._on_data = lambda: None # Need to ignore all incoming messages from now, since they come with "invalid" magic bytes
+ conn.magic_bytes = b'\x00\x11\x22\x32'
+
+ # Call .result() to block until the atomic swap is complete, otherwise
+ # we might run into races later on
+ asyncio.run_coroutine_threadsafe(asyncio.coroutine(swap_magic_bytes)(), NetworkThread.network_event_loop).result()
+
with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART ping']):
conn.send_message(messages.msg_ping(nonce=0xff))
conn.wait_for_disconnect(timeout=1)
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 336d34a81d..06049db54c 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test message sending before handshake completion.
@@ -117,9 +117,9 @@ class P2PLeakTest(BitcoinTestFramework):
wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0)
# Make sure no unexpected messages came in
- assert(no_version_bannode.unexpected_msg == False)
- assert(no_version_idlenode.unexpected_msg == False)
- assert(no_verack_idlenode.unexpected_msg == False)
+ assert no_version_bannode.unexpected_msg == False
+ assert no_version_idlenode.unexpected_msg == False
+ assert no_verack_idlenode.unexpected_msg == False
if __name__ == '__main__':
diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py
index 359880506e..573d5f5a5f 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-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.
"""Tests NODE_NETWORK_LIMITED.
@@ -11,7 +11,13 @@ and that it responds to getdata requests for blocks correctly:
from test_framework.messages import CInv, msg_getdata, msg_verack, NODE_BLOOM, NODE_NETWORK_LIMITED, NODE_WITNESS
from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks, wait_until
+from test_framework.util import (
+ assert_equal,
+ disconnect_nodes,
+ connect_nodes_bi,
+ wait_until,
+)
+
class P2PIgnoreInv(P2PInterface):
firstAddrnServices = 0
@@ -60,7 +66,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.")
connect_nodes_bi(self.nodes, 0, 1)
blocks = self.nodes[1].generatetoaddress(292, self.nodes[1].get_deterministic_priv_key().address)
- sync_blocks([self.nodes[0], self.nodes[1]])
+ self.sync_blocks([self.nodes[0], self.nodes[1]])
self.log.info("Make sure we can max retrieve block at tip-288.")
node.send_getdata_for_block(blocks[1]) # last block in valid range
@@ -86,7 +92,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
# because node 2 is in IBD and node 0 is a NODE_NETWORK_LIMITED peer, sync must not be possible
connect_nodes_bi(self.nodes, 0, 2)
try:
- sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
+ self.sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
except:
pass
# node2 must remain at height 0
@@ -96,7 +102,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
connect_nodes_bi(self.nodes, 1, 2)
# sync must be possible
- sync_blocks(self.nodes)
+ self.sync_blocks()
# disconnect all peers
self.disconnect_all()
@@ -108,7 +114,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
connect_nodes_bi(self.nodes, 0, 1)
# sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED)
- sync_blocks([self.nodes[0], self.nodes[1]])
+ self.sync_blocks([self.nodes[0], self.nodes[1]])
if __name__ == '__main__':
NodeNetworkLimitedTest().main()
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 8f8e89cf15..b7fa42f593 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1,16 +1,15 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test segwit transactions and blocks on P2P network."""
-from binascii import hexlify
import math
import random
import struct
import time
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
-from test_framework.key import CECKey, CPubKey
+from test_framework.key import ECKey
from test_framework.messages import (
BIP125_SEQUENCE_NUMBER,
CBlock,
@@ -26,17 +25,18 @@ from test_framework.messages import (
MSG_WITNESS_FLAG,
NODE_NETWORK,
NODE_WITNESS,
- msg_block,
+ msg_no_witness_block,
msg_getdata,
msg_headers,
msg_inv,
msg_tx,
- msg_witness_block,
+ msg_block,
msg_witness_tx,
ser_uint256,
ser_vector,
sha256,
uint256_from_str,
+ FromHex,
)
from test_framework.mininode import (
P2PInterface,
@@ -74,13 +74,11 @@ from test_framework.script import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- bytes_to_hex_str,
connect_nodes,
disconnect_nodes,
get_bip9_status,
hex_str_to_bytes,
- sync_blocks,
- sync_mempools,
+ assert_raises_rpc_error,
)
# The versionbit bit used to signal activation of SegWit
@@ -104,7 +102,7 @@ def get_p2pkh_script(pubkeyhash):
def sign_p2pk_witness_input(script, tx_to, in_idx, hashtype, value, key):
"""Add signature for a P2PK witness program."""
tx_hash = SegwitVersion1SignatureHash(script, tx_to, in_idx, hashtype, value)
- signature = key.sign(tx_hash) + chr(hashtype).encode('latin-1')
+ signature = key.sign_ecdsa(tx_hash) + chr(hashtype).encode('latin-1')
tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script]
tx_to.rehash()
@@ -113,7 +111,7 @@ def get_virtual_size(witness_block):
Virtual size is base + witness/4."""
base_size = len(witness_block.serialize(with_witness=False))
- total_size = len(witness_block.serialize(with_witness=True))
+ total_size = len(witness_block.serialize())
# the "+3" is so we round up
vsize = int((3 * base_size + total_size + 3) / 4)
return vsize
@@ -136,7 +134,7 @@ def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=Non
- use the getbestblockhash rpc to check for acceptance."""
reason = [reason] if reason else []
with node.assert_debug_log(expected_msgs=reason):
- p2p.send_message(msg_witness_block(block) if with_witness else msg_block(block))
+ p2p.send_message(msg_block(block) if with_witness else msg_no_witness_block(block))
p2p.sync_with_ping()
assert_equal(node.getbestblockhash() == block.hash, accepted)
@@ -273,6 +271,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_non_standard_witness()
self.test_upgrade_after_activation()
self.test_witness_sigops()
+ self.test_superfluous_witness()
# Individual tests
@@ -285,7 +284,7 @@ class SegWitTest(BitcoinTestFramework):
func(self, *args, **kwargs)
# Each subtest should leave some utxos for the next subtest
assert self.utxo
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Assert segwit status is as expected at end of subtest
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], self.segwit_status)
@@ -299,7 +298,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block(version=1)
block.solve()
- self.test_node.send_message(msg_block(block))
+ self.test_node.send_message(msg_no_witness_block(block))
self.test_node.sync_with_ping() # make sure the block was processed
txid = block.vtx[0].sha256
@@ -317,7 +316,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_node.send_message(msg_witness_tx(tx))
self.test_node.sync_with_ping() # make sure the tx was processed
- assert(tx.hash in self.nodes[0].getrawmempool())
+ assert tx.hash in self.nodes[0].getrawmempool()
# Save this transaction for later
self.utxo.append(UTXO(tx.sha256, 0, 49 * 100000000))
self.nodes[0].generate(1)
@@ -335,7 +334,7 @@ class SegWitTest(BitcoinTestFramework):
# Verify the hash with witness differs from the txid
# (otherwise our testing framework must be broken!)
tx.rehash()
- assert(tx.sha256 != tx.calc_sha256(with_witness=True))
+ assert tx.sha256 != tx.calc_sha256(with_witness=True)
# Construct a segwit-signaling block that includes the transaction.
block = self.build_next_block(version=(VB_TOP_BITS | (1 << VB_WITNESS_BIT)))
@@ -346,7 +345,7 @@ class SegWitTest(BitcoinTestFramework):
# But it should not be permanently marked bad...
# Resend without witness information.
- self.test_node.send_message(msg_block(block))
+ self.test_node.send_message(msg_no_witness_block(block))
self.test_node.sync_with_ping()
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
@@ -371,20 +370,20 @@ class SegWitTest(BitcoinTestFramework):
block1.solve()
self.test_node.announce_block_and_wait_for_getdata(block1, use_header=False)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ assert self.test_node.last_message["getdata"].inv[0].type == blocktype
test_witness_block(self.nodes[0], self.test_node, block1, True)
block2 = self.build_next_block(version=4)
block2.solve()
self.test_node.announce_block_and_wait_for_getdata(block2, use_header=True)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ assert self.test_node.last_message["getdata"].inv[0].type == blocktype
test_witness_block(self.nodes[0], self.test_node, block2, True)
block3 = self.build_next_block(version=(VB_TOP_BITS | (1 << 15)))
block3.solve()
self.test_node.announce_block_and_wait_for_getdata(block3, use_header=True)
- assert(self.test_node.last_message["getdata"].inv[0].type == blocktype)
+ assert self.test_node.last_message["getdata"].inv[0].type == blocktype
test_witness_block(self.nodes[0], self.test_node, block3, True)
# Check that we can getdata for witness blocks or regular blocks,
@@ -404,7 +403,7 @@ class SegWitTest(BitcoinTestFramework):
block_hash = int(block_hash, 16)
block = self.test_node.request_block(block_hash, 2)
wit_block = self.test_node.request_block(block_hash, 2 | MSG_WITNESS_FLAG)
- assert_equal(block.serialize(True), wit_block.serialize(True))
+ assert_equal(block.serialize(), wit_block.serialize())
assert_equal(block.serialize(), hex_str_to_bytes(rpc_block))
else:
# After activation, witness blocks and non-witness blocks should
@@ -413,22 +412,22 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [])
# This gives us a witness commitment.
- assert(len(block.vtx[0].wit.vtxinwit) == 1)
- assert(len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1)
+ assert len(block.vtx[0].wit.vtxinwit) == 1
+ assert len(block.vtx[0].wit.vtxinwit[0].scriptWitness.stack) == 1
test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
# Now try to retrieve it...
rpc_block = self.nodes[0].getblock(block.hash, False)
non_wit_block = self.test_node.request_block(block.sha256, 2)
wit_block = self.test_node.request_block(block.sha256, 2 | MSG_WITNESS_FLAG)
- assert_equal(wit_block.serialize(True), hex_str_to_bytes(rpc_block))
+ assert_equal(wit_block.serialize(), hex_str_to_bytes(rpc_block))
assert_equal(wit_block.serialize(False), non_wit_block.serialize())
- assert_equal(wit_block.serialize(True), block.serialize(True))
+ assert_equal(wit_block.serialize(), block.serialize())
# Test size, vsize, weight
rpc_details = self.nodes[0].getblock(block.hash, True)
- assert_equal(rpc_details["size"], len(block.serialize(True)))
+ assert_equal(rpc_details["size"], len(block.serialize()))
assert_equal(rpc_details["strippedsize"], len(block.serialize(False)))
- weight = 3 * len(block.serialize(False)) + len(block.serialize(True))
+ weight = 3 * len(block.serialize(False)) + len(block.serialize())
assert_equal(rpc_details["weight"], weight)
# Upgraded node should not ask for blocks from unupgraded
@@ -448,7 +447,7 @@ class SegWitTest(BitcoinTestFramework):
msg.headers = [CBlockHeader(block4)]
self.old_node.send_message(msg)
self.old_node.announce_tx_and_wait_for_getdata(block4.vtx[0])
- assert(block4.sha256 not in self.old_node.getdataset)
+ assert block4.sha256 not in self.old_node.getdataset
@subtest
def test_v0_outputs_arent_spendable(self):
@@ -537,7 +536,7 @@ class SegWitTest(BitcoinTestFramework):
"""Mine enough blocks for segwit's vb state to be 'started'."""
height = self.nodes[0].getblockcount()
# Will need to rewrite the tests here if we are past the first period
- assert(height < VB_PERIOD - 1)
+ assert height < VB_PERIOD - 1
# Advance to end of period, status should now be 'started'
self.nodes[0].generate(VB_PERIOD - height - 1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
@@ -554,19 +553,19 @@ class SegWitTest(BitcoinTestFramework):
# If this is a non-segwit node, we should not get a witness
# commitment, nor a version bit signalling segwit.
assert_equal(block_version & (1 << VB_WITNESS_BIT), 0)
- assert('default_witness_commitment' not in gbt_results)
+ assert 'default_witness_commitment' not in gbt_results
else:
# For segwit-aware nodes, check the version bit and the witness
# commitment are correct.
- assert(block_version & (1 << VB_WITNESS_BIT) != 0)
- assert('default_witness_commitment' in gbt_results)
+ assert block_version & (1 << VB_WITNESS_BIT) != 0
+ assert 'default_witness_commitment' in gbt_results
witness_commitment = gbt_results['default_witness_commitment']
# Check that default_witness_commitment is present.
witness_root = CBlock.get_merkle_root([ser_uint256(0),
ser_uint256(txid)])
script = get_witness_script(witness_root, 0)
- assert_equal(witness_commitment, bytes_to_hex_str(script))
+ assert_equal(witness_commitment, script.hex())
@subtest
def advance_to_segwit_lockin(self):
@@ -575,7 +574,7 @@ class SegWitTest(BitcoinTestFramework):
# Advance to end of period, and verify lock-in happens at the end
self.nodes[0].generate(VB_PERIOD - 1)
height = self.nodes[0].getblockcount()
- assert((height % VB_PERIOD) == VB_PERIOD - 2)
+ assert (height % VB_PERIOD) == VB_PERIOD - 2
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'started')
self.nodes[0].generate(1)
assert_equal(get_bip9_status(self.nodes[0], 'segwit')['status'], 'locked_in')
@@ -600,7 +599,7 @@ class SegWitTest(BitcoinTestFramework):
# Verify that if a peer doesn't set nServices to include NODE_WITNESS,
# the getdata is just for the non-witness portion.
self.old_node.announce_tx_and_wait_for_getdata(tx)
- assert(self.old_node.last_message["getdata"].inv[0].type == 1)
+ assert self.old_node.last_message["getdata"].inv[0].type == 1
# Since we haven't delivered the tx yet, inv'ing the same tx from
# a witness transaction ought not result in a getdata.
@@ -646,7 +645,7 @@ class SegWitTest(BitcoinTestFramework):
# Mine it on test_node to create the confirmed output.
test_transaction_acceptance(self.nodes[0], self.test_node, p2sh_tx, with_witness=True, accepted=True)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Now test standardness of v0 P2WSH outputs.
# Start by creating a transaction with two outputs.
@@ -677,7 +676,7 @@ class SegWitTest(BitcoinTestFramework):
tx3 = CTransaction()
# tx and tx2 were both accepted. Don't bother trying to reclaim the
# P2PKH output; just send tx's first output back to an anyone-can-spend.
- sync_mempools([self.nodes[0], self.nodes[1]])
+ self.sync_mempools([self.nodes[0], self.nodes[1]])
tx3.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
tx3.vout = [CTxOut(tx.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))]
tx3.wit.vtxinwit.append(CTxInWitness())
@@ -686,17 +685,17 @@ class SegWitTest(BitcoinTestFramework):
if self.segwit_status != '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([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}])
# 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([bytes_to_hex_str(tx3.serialize_with_witness())]), [{'txid': tx3.hash, 'allowed': True}])
+ assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}])
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.utxo.pop(0)
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
assert_equal(len(self.nodes[1].getrawmempool()), 0)
@@ -734,7 +733,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
test_witness_block(self.nodes[0], self.test_node, block, accepted=True, with_witness=True)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Now test attempts to spend the output.
spend_tx = CTransaction()
@@ -792,7 +791,7 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
# Test the test -- witness serialization should be different
- assert(msg_witness_block(block).serialize() != msg_block(block).serialize())
+ assert msg_block(block).serialize() != msg_no_witness_block(block).serialize()
# This empty block should be valid.
test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
@@ -803,7 +802,7 @@ class SegWitTest(BitcoinTestFramework):
block_2.solve()
# The commitment should have changed!
- assert(block_2.vtx[0].vout[-1] != block.vtx[0].vout[-1])
+ assert block_2.vtx[0].vout[-1] != block.vtx[0].vout[-1]
# This should also be valid.
test_witness_block(self.nodes[0], self.test_node, block_2, accepted=True)
@@ -850,7 +849,7 @@ class SegWitTest(BitcoinTestFramework):
block_3.vtx[0].rehash()
block_3.hashMerkleRoot = block_3.calc_merkle_root()
block_3.rehash()
- assert(len(block_3.vtx[0].vout) == 4) # 3 OP_returns
+ assert len(block_3.vtx[0].vout) == 4 # 3 OP_returns
block_3.solve()
test_witness_block(self.nodes[0], self.test_node, block_3, accepted=True)
@@ -881,19 +880,19 @@ class SegWitTest(BitcoinTestFramework):
block.solve()
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 5000000)
- assert(get_virtual_size(block) > MAX_BLOCK_BASE_SIZE)
+ assert get_virtual_size(block) > MAX_BLOCK_BASE_SIZE
# We can't send over the p2p network, because this is too big to relay
# TODO: repeat this test with a block that can be relayed
- self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
+ self.nodes[0].submitblock(block.serialize().hex())
- assert(self.nodes[0].getbestblockhash() != block.hash)
+ assert self.nodes[0].getbestblockhash() != block.hash
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop()
- assert(get_virtual_size(block) < MAX_BLOCK_BASE_SIZE)
- self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
+ assert get_virtual_size(block) < MAX_BLOCK_BASE_SIZE
+ self.nodes[0].submitblock(block.serialize().hex())
- assert(self.nodes[0].getbestblockhash() == block.hash)
+ assert self.nodes[0].getbestblockhash() == block.hash
# Now make sure that malleating the witness reserved value doesn't
# result in a block permanently marked bad.
@@ -918,7 +917,7 @@ class SegWitTest(BitcoinTestFramework):
# Test that witness-bearing blocks are limited at ceil(base + wit/4) <= 1MB.
block = self.build_next_block()
- assert(len(self.utxo) > 0)
+ assert len(self.utxo) > 0
# Create a P2WSH transaction.
# The witness program will be a bunch of OP_2DROP's, followed by OP_TRUE.
@@ -940,7 +939,7 @@ class SegWitTest(BitcoinTestFramework):
for i in range(NUM_OUTPUTS):
parent_tx.vout.append(CTxOut(child_value, script_pubkey))
parent_tx.vout[0].nValue -= 50000
- assert(parent_tx.vout[0].nValue > 0)
+ assert parent_tx.vout[0].nValue > 0
parent_tx.rehash()
child_tx = CTransaction()
@@ -970,7 +969,7 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(vsize, MAX_BLOCK_BASE_SIZE + 1)
# Make sure that our test case would exceed the old max-network-message
# limit
- assert(len(block.serialize(True)) > 2 * 1024 * 1024)
+ assert len(block.serialize()) > 2 * 1024 * 1024
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
@@ -980,7 +979,7 @@ class SegWitTest(BitcoinTestFramework):
block.vtx[0].vout.pop()
add_witness_commitment(block)
block.solve()
- assert(get_virtual_size(block) == MAX_BLOCK_BASE_SIZE)
+ assert get_virtual_size(block) == MAX_BLOCK_BASE_SIZE
test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
@@ -998,14 +997,14 @@ class SegWitTest(BitcoinTestFramework):
add_witness_commitment(block, nonce=1)
block.vtx[0].wit = CTxWitness() # drop the nonce
block.solve()
- self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
- assert(self.nodes[0].getbestblockhash() != block.hash)
+ self.nodes[0].submitblock(block.serialize().hex())
+ assert self.nodes[0].getbestblockhash() != block.hash
# Now redo commitment with the standard nonce, but let bitcoind fill it in.
add_witness_commitment(block, nonce=0)
block.vtx[0].wit = CTxWitness()
block.solve()
- self.nodes[0].submitblock(bytes_to_hex_str(block.serialize(True)))
+ self.nodes[0].submitblock(block.serialize().hex())
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
# This time, add a tx with non-empty witness, but don't supply
@@ -1020,9 +1019,9 @@ class SegWitTest(BitcoinTestFramework):
block_2.vtx[0].vout.pop()
block_2.vtx[0].wit = CTxWitness()
- self.nodes[0].submitblock(bytes_to_hex_str(block_2.serialize(True)))
+ self.nodes[0].submitblock(block_2.serialize().hex())
# Tip should not advance!
- assert(self.nodes[0].getbestblockhash() != block_2.hash)
+ assert self.nodes[0].getbestblockhash() != block_2.hash
@subtest
def test_extra_witness_data(self):
@@ -1142,7 +1141,7 @@ class SegWitTest(BitcoinTestFramework):
# This program is 19 max pushes (9937 bytes), then 64 more opcode-bytes.
long_witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 63 + [OP_TRUE])
- assert(len(long_witness_program) == MAX_PROGRAM_LENGTH + 1)
+ assert len(long_witness_program) == MAX_PROGRAM_LENGTH + 1
long_witness_hash = sha256(long_witness_program)
long_script_pubkey = CScript([OP_0, long_witness_hash])
@@ -1166,7 +1165,7 @@ class SegWitTest(BitcoinTestFramework):
# Try again with one less byte in the witness program
witness_program = CScript([b'a' * 520] * 19 + [OP_DROP] * 62 + [OP_TRUE])
- assert(len(witness_program) == MAX_PROGRAM_LENGTH)
+ assert len(witness_program) == MAX_PROGRAM_LENGTH
witness_hash = sha256(witness_program)
script_pubkey = CScript([OP_0, witness_hash])
@@ -1197,7 +1196,7 @@ class SegWitTest(BitcoinTestFramework):
for i in range(10):
tx.vout.append(CTxOut(int(value / 10), script_pubkey))
tx.vout[0].nValue -= 1000
- assert(tx.vout[0].nValue >= 0)
+ assert tx.vout[0].nValue >= 0
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
@@ -1347,8 +1346,8 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(raw_tx["vsize"], vsize)
assert_equal(raw_tx["weight"], weight)
assert_equal(len(raw_tx["vin"][0]["txinwitness"]), 1)
- assert_equal(raw_tx["vin"][0]["txinwitness"][0], hexlify(witness_program).decode('ascii'))
- assert(vsize != raw_tx["size"])
+ assert_equal(raw_tx["vin"][0]["txinwitness"][0], witness_program.hex())
+ assert vsize != raw_tx["size"]
# Cleanup: mine the transactions and update utxo for next test
self.nodes[0].generate(1)
@@ -1361,7 +1360,8 @@ class SegWitTest(BitcoinTestFramework):
def test_segwit_versions(self):
"""Test validity of future segwit version transactions.
- Future segwit version transactions are non-standard, but valid in blocks.
+ Future segwit versions are non-standard to spend, but valid in blocks.
+ Sending to future segwit versions is always allowed.
Can run this before and after segwit activation."""
NUM_SEGWIT_VERSIONS = 17 # will test OP_0, OP1, ..., OP_16
@@ -1379,7 +1379,7 @@ class SegWitTest(BitcoinTestFramework):
for i in range(NUM_SEGWIT_VERSIONS):
self.utxo.append(UTXO(tx.sha256, i, split_value))
- sync_blocks(self.nodes)
+ self.sync_blocks()
temp_utxo = []
tx = CTransaction()
witness_program = CScript([OP_TRUE])
@@ -1397,11 +1397,11 @@ class SegWitTest(BitcoinTestFramework):
temp_utxo.append(UTXO(tx.sha256, 0, tx.vout[0].nValue))
self.nodes[0].generate(1) # Mine all the transactions
- sync_blocks(self.nodes)
- assert(len(self.nodes[0].getrawmempool()) == 0)
+ self.sync_blocks()
+ assert len(self.nodes[0].getrawmempool()) == 0
# Finally, verify that version 0 -> version 1 transactions
- # are non-standard
+ # are standard
script_pubkey = CScript([CScriptOp(OP_1), witness_hash])
tx2 = CTransaction()
tx2.vin = [CTxIn(COutPoint(tx.sha256, 0), b"")]
@@ -1409,10 +1409,9 @@ class SegWitTest(BitcoinTestFramework):
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
tx2.rehash()
- # Gets accepted to test_node, because standardness of outputs isn't
- # checked with fRequireStandard
+ # Gets accepted to both policy-enforcing nodes and others.
test_transaction_acceptance(self.nodes[0], self.test_node, tx2, with_witness=True, accepted=True)
- test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=False)
+ test_transaction_acceptance(self.nodes[1], self.std_node, tx2, with_witness=True, accepted=True)
temp_utxo.pop() # last entry in temp_utxo was the output we just spent
temp_utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
@@ -1434,7 +1433,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx2, tx3])
test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Add utxo to our list
self.utxo.append(UTXO(tx3.sha256, 0, tx3.vout[0].nValue))
@@ -1462,7 +1461,7 @@ class SegWitTest(BitcoinTestFramework):
# Now test a premature spend.
self.nodes[0].generate(98)
- sync_blocks(self.nodes)
+ self.sync_blocks()
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
test_witness_block(self.nodes[0], self.test_node, block2, accepted=False)
@@ -1472,7 +1471,7 @@ class SegWitTest(BitcoinTestFramework):
block2 = self.build_next_block()
self.update_witness_block_with_transactions(block2, [spend_tx])
test_witness_block(self.nodes[0], self.test_node, block2, accepted=True)
- sync_blocks(self.nodes)
+ self.sync_blocks()
@subtest
def test_uncompressed_pubkey(self):
@@ -1483,10 +1482,9 @@ class SegWitTest(BitcoinTestFramework):
# Segwit transactions using uncompressed pubkeys are not accepted
# under default policy, but should still pass consensus.
- key = CECKey()
- key.set_secretbytes(b"9")
- key.set_compressed(False)
- pubkey = CPubKey(key.get_pubkey())
+ key = ECKey()
+ key.generate(False)
+ pubkey = key.get_pubkey().get_bytes()
assert_equal(len(pubkey), 65) # This should be an uncompressed pubkey
utxo = self.utxo.pop(0)
@@ -1516,7 +1514,7 @@ class SegWitTest(BitcoinTestFramework):
tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_wsh))
script = get_p2pkh_script(pubkeyhash)
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ signature = key.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
tx2.wit.vtxinwit.append(CTxInWitness())
tx2.wit.vtxinwit[0].scriptWitness.stack = [signature, pubkey]
tx2.rehash()
@@ -1570,7 +1568,7 @@ class SegWitTest(BitcoinTestFramework):
tx5.vin.append(CTxIn(COutPoint(tx4.sha256, 0), b""))
tx5.vout.append(CTxOut(tx4.vout[0].nValue - 1000, CScript([OP_TRUE])))
(sig_hash, err) = SignatureHash(script_pubkey, tx5, 0, SIGHASH_ALL)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ signature = key.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
tx5.vin[0].scriptSig = CScript([signature, pubkey])
tx5.rehash()
# Should pass policy and consensus.
@@ -1583,9 +1581,9 @@ class SegWitTest(BitcoinTestFramework):
@subtest
def test_signature_version_1(self):
- key = CECKey()
- key.set_secretbytes(b"9")
- pubkey = CPubKey(key.get_pubkey())
+ key = ECKey()
+ key.generate()
+ pubkey = key.get_pubkey().get_bytes()
witness_program = CScript([pubkey, CScriptOp(OP_CHECKSIG)])
witness_hash = sha256(witness_program)
@@ -1602,7 +1600,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block()
self.update_witness_block_with_transactions(block, [tx])
test_witness_block(self.nodes[0], self.test_node, block, accepted=True)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.utxo.pop(0)
# Test each hashtype
@@ -1667,7 +1665,7 @@ class SegWitTest(BitcoinTestFramework):
# Create a slight bias for producing more utxos
num_outputs = random.randint(1, 11)
random.shuffle(temp_utxos)
- assert(len(temp_utxos) > num_inputs)
+ assert len(temp_utxos) > num_inputs
tx = CTransaction()
total_value = 0
for i in range(num_inputs):
@@ -1720,7 +1718,7 @@ class SegWitTest(BitcoinTestFramework):
script = get_p2pkh_script(pubkeyhash)
sig_hash = SegwitVersion1SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue)
- signature = key.sign(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
+ signature = key.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL
# Check that we can't have a scriptSig
tx2.vin[0].scriptSig = CScript([signature, pubkey])
@@ -1781,7 +1779,7 @@ class SegWitTest(BitcoinTestFramework):
tx.rehash()
test_transaction_acceptance(self.nodes[0], self.test_node, tx, False, True)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# We'll add an unnecessary witness to this transaction that would cause
# it to be non-standard, to test that violating policy with a witness
@@ -1810,7 +1808,7 @@ class SegWitTest(BitcoinTestFramework):
test_transaction_acceptance(self.nodes[0], self.test_node, tx3, False, True)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Update our utxo list; we spent the first entry.
self.utxo.pop(0)
@@ -1846,7 +1844,7 @@ class SegWitTest(BitcoinTestFramework):
test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Creating transactions for tests
p2wsh_txs = []
@@ -1910,7 +1908,7 @@ class SegWitTest(BitcoinTestFramework):
self.nodes[0].generate(1) # Mine and clean up the mempool of non-standard node
# Valid but non-standard transactions in a block should be accepted by standard node
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(len(self.nodes[0].getrawmempool()), 0)
assert_equal(len(self.nodes[1].getrawmempool()), 0)
@@ -1925,10 +1923,10 @@ class SegWitTest(BitcoinTestFramework):
self.start_node(2, extra_args=["-vbparams=segwit:0:999999999999"])
connect_nodes(self.nodes[0], 2)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Make sure that this peer thinks segwit has activated.
- assert(get_bip9_status(self.nodes[2], 'segwit')['status'] == "active")
+ assert get_bip9_status(self.nodes[2], 'segwit')['status'] == "active"
# Make sure this peer's blocks match those of node0.
height = self.nodes[2].getblockcount()
@@ -1955,7 +1953,7 @@ class SegWitTest(BitcoinTestFramework):
extra_sigops_available = MAX_SIGOP_COST % sigops_per_script
# We chose the number of checkmultisigs/checksigs to make this work:
- assert(extra_sigops_available < 100) # steer clear of MAX_OPS_PER_SCRIPT
+ assert extra_sigops_available < 100 # steer clear of MAX_OPS_PER_SCRIPT
# This script, when spent with the first
# N(=MAX_SIGOP_COST//sigops_per_script) outputs of our transaction,
@@ -2022,7 +2020,7 @@ class SegWitTest(BitcoinTestFramework):
test_witness_block(self.nodes[0], self.test_node, block_4, accepted=True)
# Reset the tip back down for the next test
- sync_blocks(self.nodes)
+ self.sync_blocks()
for x in self.nodes:
x.invalidateblock(block_4.hash)
@@ -2039,5 +2037,51 @@ class SegWitTest(BitcoinTestFramework):
# TODO: test p2sh sigop counting
+ def test_superfluous_witness(self):
+ # Serialization of tx that puts witness flag to 3 always
+ def serialize_with_bogus_witness(tx):
+ flags = 3
+ r = b""
+ r += struct.pack("<i", tx.nVersion)
+ if flags:
+ dummy = []
+ r += ser_vector(dummy)
+ r += struct.pack("<B", flags)
+ r += ser_vector(tx.vin)
+ r += ser_vector(tx.vout)
+ if flags & 1:
+ if (len(tx.wit.vtxinwit) != len(tx.vin)):
+ # vtxinwit must have the same length as vin
+ tx.wit.vtxinwit = tx.wit.vtxinwit[:len(tx.vin)]
+ for i in range(len(tx.wit.vtxinwit), len(tx.vin)):
+ tx.wit.vtxinwit.append(CTxInWitness())
+ r += tx.wit.serialize()
+ r += struct.pack("<I", tx.nLockTime)
+ return r
+
+ class msg_bogus_tx(msg_tx):
+ def serialize(self):
+ return serialize_with_bogus_witness(self.tx)
+
+ self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(address_type='bech32'), 5)
+ self.nodes[0].generate(1)
+ unspent = next(u for u in self.nodes[0].listunspent() if u['spendable'] and u['address'].startswith('bcrt'))
+
+ raw = self.nodes[0].createrawtransaction([{"txid": unspent['txid'], "vout": unspent['vout']}], {self.nodes[0].getnewaddress(): 1})
+ tx = FromHex(CTransaction(), raw)
+ assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, serialize_with_bogus_witness(tx).hex())
+ with self.nodes[0].assert_debug_log(['Superfluous witness record']):
+ self.nodes[0].p2p.send_message(msg_bogus_tx(tx))
+ self.nodes[0].p2p.sync_with_ping()
+ raw = self.nodes[0].signrawtransactionwithwallet(raw)
+ assert raw['complete']
+ raw = raw['hex']
+ tx = FromHex(CTransaction(), raw)
+ assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, serialize_with_bogus_witness(tx).hex())
+ with self.nodes[0].assert_debug_log(['Unknown transaction optional data']):
+ self.nodes[0].p2p.send_message(msg_bogus_tx(tx))
+ self.nodes[0].p2p.sync_with_ping()
+
+
if __name__ == '__main__':
SegWitTest().main()
diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py
index 7d7d251765..161b67e6d0 100755
--- a/test/functional/p2p_sendheaders.py
+++ b/test/functional/p2p_sendheaders.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test behavior of headers messages to announce blocks.
@@ -103,7 +103,6 @@ from test_framework.mininode import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- sync_blocks,
wait_until,
)
@@ -225,7 +224,7 @@ class SendHeadersTest(BitcoinTestFramework):
# make sure all invalidated blocks are node0's
self.nodes[0].generatetoaddress(length, self.nodes[0].get_deterministic_priv_key().address)
- sync_blocks(self.nodes, wait=0.1)
+ self.sync_blocks(self.nodes, wait=0.1)
for x in self.nodes[0].p2ps:
x.wait_for_block_announcement(int(self.nodes[0].getbestblockhash(), 16))
x.clear_block_announcements()
@@ -234,7 +233,7 @@ class SendHeadersTest(BitcoinTestFramework):
hash_to_invalidate = self.nodes[1].getblockhash(tip_height - (length - 1))
self.nodes[1].invalidateblock(hash_to_invalidate)
all_hashes = self.nodes[1].generatetoaddress(length + 1, self.nodes[1].get_deterministic_priv_key().address) # Must be longer than the orig chain
- sync_blocks(self.nodes, wait=0.1)
+ self.sync_blocks(self.nodes, wait=0.1)
return [int(x, 16) for x in all_hashes]
def run_test(self):
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index 11299cbc00..534d275c28 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test processing of unrequested blocks.
@@ -57,7 +57,11 @@ from test_framework.blocktools import create_block, create_coinbase, create_tx_w
from test_framework.messages import CBlockHeader, CInv, msg_block, msg_headers, msg_inv
from test_framework.mininode import mininode_lock, P2PInterface
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, sync_blocks
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ connect_nodes,
+)
class AcceptBlockTest(BitcoinTestFramework):
@@ -114,7 +118,7 @@ class AcceptBlockTest(BitcoinTestFramework):
if x['hash'] == block_h1f.hash:
assert_equal(x['status'], "headers-only")
tip_entry_found = True
- assert(tip_entry_found)
+ assert tip_entry_found
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_h1f.hash)
# 4. Send another two block that build on the fork.
@@ -131,7 +135,7 @@ class AcceptBlockTest(BitcoinTestFramework):
if x['hash'] == block_h2f.hash:
assert_equal(x['status'], "headers-only")
tip_entry_found = True
- assert(tip_entry_found)
+ assert tip_entry_found
# But this block should be accepted by node since it has equal work.
self.nodes[0].getblock(block_h2f.hash)
@@ -150,7 +154,7 @@ class AcceptBlockTest(BitcoinTestFramework):
if x['hash'] == block_h3.hash:
assert_equal(x['status'], "headers-only")
tip_entry_found = True
- assert(tip_entry_found)
+ assert tip_entry_found
self.nodes[0].getblock(block_h3.hash)
# But this block should be accepted by node since it has more work.
@@ -263,7 +267,7 @@ class AcceptBlockTest(BitcoinTestFramework):
if x['hash'] == block_292.hash:
assert_equal(x['status'], "headers-only")
tip_entry_found = True
- assert(tip_entry_found)
+ assert tip_entry_found
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, block_292.hash)
test_node.send_message(msg_block(block_289f))
@@ -302,7 +306,7 @@ class AcceptBlockTest(BitcoinTestFramework):
# 9. Connect node1 to node0 and ensure it is able to sync
connect_nodes(self.nodes[0], 1)
- sync_blocks([self.nodes[0], self.nodes[1]])
+ self.sync_blocks([self.nodes[0], self.nodes[1]])
self.log.info("Successfully synced nodes 1 and 0")
if __name__ == '__main__':
diff --git a/test/functional/rpc_bind.py b/test/functional/rpc_bind.py
index 3938ca98dd..acc7cd811c 100755
--- a/test/functional/rpc_bind.py
+++ b/test/functional/rpc_bind.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test running bitcoind with the -rpcbind and -rpcallowip options."""
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index af150a09af..facb05b54c 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test RPCs related to blockchainstate.
@@ -172,9 +172,9 @@ class BlockchainTest(BitcoinTestFramework):
assert_equal(chaintxstats['txcount'], 2)
assert_equal(chaintxstats['window_final_block_hash'], b1_hash)
assert_equal(chaintxstats['window_block_count'], 0)
- assert('window_tx_count' not in chaintxstats)
- assert('window_interval' not in chaintxstats)
- assert('txrate' not in chaintxstats)
+ assert 'window_tx_count' not in chaintxstats
+ assert 'window_interval' not in chaintxstats
+ assert 'txrate' not in chaintxstats
def _test_gettxoutsetinfo(self):
node = self.nodes[0]
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 3cc35a7b9a..58010f7c2e 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -1,11 +1,19 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
-"""Test transaction signing using the signrawtransaction* RPCs."""
+"""Test multisig RPCs"""
from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_raises_rpc_error,
+ assert_equal,
+)
+from test_framework.key import ECPubKey
+
+import binascii
import decimal
+import itertools
class RpcCreateMultiSigTest(BitcoinTestFramework):
def set_test_params(self):
@@ -17,29 +25,64 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
def get_keys(self):
node0, node1, node2 = self.nodes
- self.add = [node1.getnewaddress() for _ in range(self.nkeys)]
- self.pub = [node1.getaddressinfo(a)["pubkey"] for a in self.add]
- self.priv = [node1.dumpprivkey(a) for a in self.add]
+ add = [node1.getnewaddress() for _ in range(self.nkeys)]
+ self.pub = [node1.getaddressinfo(a)["pubkey"] for a in add]
+ self.priv = [node1.dumpprivkey(a) for a in add]
self.final = node2.getnewaddress()
def run_test(self):
- node0,node1,node2 = self.nodes
+ node0, node1, node2 = self.nodes
- # 50 BTC each, rest will be 25 BTC each
+ self.check_addmultisigaddress_errors()
+
+ self.log.info('Generating blocks ...')
node0.generate(149)
self.sync_all()
self.moved = 0
- for self.nkeys in [3,5]:
- for self.nsigs in [2,3]:
+ for self.nkeys in [3, 5]:
+ for self.nsigs in [2, 3]:
for self.output_type in ["bech32", "p2sh-segwit", "legacy"]:
self.get_keys()
self.do_multisig()
self.checkbalances()
+ # Test mixed compressed and uncompressed pubkeys
+ self.log.info('Mixed compressed and uncompressed multisigs are not allowed')
+ pk0 = node0.getaddressinfo(node0.getnewaddress())['pubkey']
+ pk1 = node1.getaddressinfo(node1.getnewaddress())['pubkey']
+ pk2 = node2.getaddressinfo(node2.getnewaddress())['pubkey']
+
+ # decompress pk2
+ pk_obj = ECPubKey()
+ pk_obj.set(binascii.unhexlify(pk2))
+ pk_obj.compressed = False
+ pk2 = binascii.hexlify(pk_obj.get_bytes()).decode()
+
+ # Check all permutations of keys because order matters apparently
+ for keys in itertools.permutations([pk0, pk1, pk2]):
+ # Results should be the same as this legacy one
+ legacy_addr = node0.createmultisig(2, keys, 'legacy')['address']
+ assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'legacy')['address'])
+
+ # Generate addresses with the segwit types. These should all make legacy addresses
+ assert_equal(legacy_addr, node0.createmultisig(2, keys, 'bech32')['address'])
+ assert_equal(legacy_addr, node0.createmultisig(2, keys, 'p2sh-segwit')['address'])
+ assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'bech32')['address'])
+ assert_equal(legacy_addr, node0.addmultisigaddress(2, keys, '', 'p2sh-segwit')['address'])
+
+ def check_addmultisigaddress_errors(self):
+ self.log.info('Check that addmultisigaddress fails when the private keys are missing')
+ addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)]
+ assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
+ for a in addresses:
+ # Importing all addresses should not change the result
+ self.nodes[0].importaddress(a)
+ assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
+
def checkbalances(self):
- node0,node1,node2 = self.nodes
+ node0, node1, node2 = self.nodes
node0.generate(100)
self.sync_all()
@@ -49,13 +92,13 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
height = node0.getblockchaininfo()["blocks"]
assert 150 < height < 350
- total = 149*50 + (height-149-100)*25
+ total = 149 * 50 + (height - 149 - 100) * 25
assert bal1 == 0
assert bal2 == self.moved
- assert bal0+bal1+bal2 == total
+ assert bal0 + bal1 + bal2 == total
def do_multisig(self):
- node0,node1,node2 = self.nodes
+ node0, node1, node2 = self.nodes
msig = node2.createmultisig(self.nsigs, self.pub, self.output_type)
madd = msig["address"]
@@ -74,7 +117,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
txid = node0.sendtoaddress(madd, 40)
tx = node0.getrawtransaction(txid, True)
- vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses",[])]
+ vout = [v["n"] for v in tx["vout"] if madd in v["scriptPubKey"].get("addresses", [])]
assert len(vout) == 1
vout = vout[0]
scriptPubKey = tx["vout"][vout]["scriptPubKey"]["hex"]
@@ -86,16 +129,17 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
outval = value - decimal.Decimal("0.00001000")
rawtx = node2.createrawtransaction([{"txid": txid, "vout": vout}], [{self.final: outval}])
- rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs-1], prevtxs)
+ rawtx2 = node2.signrawtransactionwithkey(rawtx, self.priv[0:self.nsigs - 1], prevtxs)
rawtx3 = node2.signrawtransactionwithkey(rawtx2["hex"], [self.priv[-1]], prevtxs)
self.moved += outval
- tx = node0.sendrawtransaction(rawtx3["hex"], True)
+ tx = node0.sendrawtransaction(rawtx3["hex"], 0)
blk = node0.generate(1)[0]
assert tx in node0.getblock(blk)["tx"]
txinfo = node0.getrawtransaction(tx, True, blk)
self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (self.nsigs, self.nkeys, self.output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"]))
+
if __name__ == '__main__':
RpcCreateMultiSigTest().main()
diff --git a/test/functional/rpc_decodescript.py b/test/functional/rpc_decodescript.py
index 940386eee7..01b8cb1854 100755
--- a/test/functional/rpc_decodescript.py
+++ b/test/functional/rpc_decodescript.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test decoding scripts via decodescript RPC command."""
from test_framework.messages import CTransaction, sha256
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, bytes_to_hex_str, hex_str_to_bytes
+from test_framework.util import assert_equal, hex_str_to_bytes
from io import BytesIO
@@ -81,7 +81,7 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decodescript(multisig_script)
assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm'])
# multisig in P2WSH
- multisig_script_hash = bytes_to_hex_str(sha256(hex_str_to_bytes(multisig_script)))
+ multisig_script_hash = sha256(hex_str_to_bytes(multisig_script)).hex()
assert_equal('0 ' + multisig_script_hash, rpc_result['segwit']['asm'])
# 4) P2SH scriptPubKey
@@ -119,7 +119,7 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decodescript(cltv_script)
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
# CLTV script in P2WSH
- cltv_script_hash = bytes_to_hex_str(sha256(hex_str_to_bytes(cltv_script)))
+ cltv_script_hash = sha256(hex_str_to_bytes(cltv_script)).hex()
assert_equal('0 ' + cltv_script_hash, rpc_result['segwit']['asm'])
# 7) P2PK scriptPubKey
@@ -196,7 +196,7 @@ class DecodeScriptTest(BitcoinTestFramework):
# some more full transaction tests of varying specific scriptSigs. used instead of
# tests in decodescript_script_sig because the decodescript RPC is specifically
# for working on scriptPubKeys (argh!).
- push_signature = bytes_to_hex_str(txSave.vin[0].scriptSig)[2:(0x48*2+4)]
+ push_signature = txSave.vin[0].scriptSig.hex()[2:(0x48*2+4)]
signature = push_signature[2:]
der_signature = signature[:-2]
signature_sighash_decoded = der_signature + '[ALL]'
@@ -206,23 +206,23 @@ class DecodeScriptTest(BitcoinTestFramework):
# 1) P2PK scriptSig
txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature)
- rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
+ rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
# make sure that the sighash decodes come out correctly for a more complex / lesser used case.
txSave.vin[0].scriptSig = hex_str_to_bytes(push_signature_2)
- rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
+ rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
# 2) multisig scriptSig
txSave.vin[0].scriptSig = hex_str_to_bytes('00' + push_signature + push_signature_2)
- rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
+ rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
# 3) test a scriptSig that contains more than push operations.
# in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
txSave.vin[0].scriptSig = hex_str_to_bytes('6a143011020701010101010101020601010101010101')
- rpc_result = self.nodes[0].decoderawtransaction(bytes_to_hex_str(txSave.serialize()))
+ rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
def run_test(self):
diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py
index 530f457ae7..9a21998d11 100755
--- a/test/functional/rpc_deprecated.py
+++ b/test/functional/rpc_deprecated.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test deprecation of RPC calls."""
diff --git a/test/functional/rpc_deriveaddresses.py b/test/functional/rpc_deriveaddresses.py
index 185dffd51c..1984694692 100755
--- a/test/functional/rpc_deriveaddresses.py
+++ b/test/functional/rpc_deriveaddresses.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
"""Test the deriveaddresses rpc call."""
diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py
index 4f350953b2..cdf636e200 100755
--- a/test/functional/rpc_fundrawtransaction.py
+++ b/test/functional/rpc_fundrawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the fundrawtransaction RPC."""
@@ -94,7 +94,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- assert(len(dec_tx['vin']) > 0) #test that we have enough inputs
+ assert len(dec_tx['vin']) > 0 #test that we have enough inputs
##############################
# simple test with two coins #
@@ -107,7 +107,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- assert(len(dec_tx['vin']) > 0) #test if we have enough inputs
+ assert len(dec_tx['vin']) > 0 #test if we have enough inputs
##############################
# simple test with two coins #
@@ -120,7 +120,7 @@ class RawTransactionsTest(BitcoinTestFramework):
rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
fee = rawtxfund['fee']
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- assert(len(dec_tx['vin']) > 0)
+ assert len(dec_tx['vin']) > 0
assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')
@@ -139,7 +139,7 @@ class RawTransactionsTest(BitcoinTestFramework):
for out in dec_tx['vout']:
totalOut += out['value']
- assert(len(dec_tx['vin']) > 0)
+ assert len(dec_tx['vin']) > 0
assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')
@@ -363,7 +363,7 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
- assert(feeDelta >= 0 and feeDelta <= feeTolerance)
+ assert feeDelta >= 0 and feeDelta <= feeTolerance
############################################################
############################################################
@@ -378,7 +378,7 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
- assert(feeDelta >= 0 and feeDelta <= feeTolerance)
+ assert feeDelta >= 0 and feeDelta <= feeTolerance
############################################################
@@ -405,7 +405,7 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
- assert(feeDelta >= 0 and feeDelta <= feeTolerance)
+ assert feeDelta >= 0 and feeDelta <= feeTolerance
############################################################
@@ -438,7 +438,7 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
- assert(feeDelta >= 0 and feeDelta <= feeTolerance)
+ assert feeDelta >= 0 and feeDelta <= feeTolerance
############################################################
@@ -558,7 +558,7 @@ class RawTransactionsTest(BitcoinTestFramework):
#compare fee
feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
- assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs
+ assert feeDelta >= 0 and feeDelta <= feeTolerance*19 #~19 inputs
#############################################
@@ -620,7 +620,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(len(res_dec["vin"]), 1)
assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)
- assert("fee" in result.keys())
+ assert "fee" in result.keys()
assert_greater_than(result["changepos"], -1)
###############################################################
@@ -635,16 +635,16 @@ class RawTransactionsTest(BitcoinTestFramework):
result = self.nodes[3].fundrawtransaction(rawtx, True)
res_dec = self.nodes[0].decoderawtransaction(result["hex"])
assert_equal(len(res_dec["vin"]), 2)
- assert(res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid)
+ assert res_dec["vin"][0]["txid"] == watchonly_txid or res_dec["vin"][1]["txid"] == watchonly_txid
assert_greater_than(result["fee"], 0)
assert_greater_than(result["changepos"], -1)
assert_equal(result["fee"] + res_dec["vout"][result["changepos"]]["value"], watchonly_amount / 10)
signedtx = self.nodes[3].signrawtransactionwithwallet(result["hex"])
- assert(not signedtx["complete"])
+ assert not signedtx["complete"]
signedtx = self.nodes[0].signrawtransactionwithwallet(signedtx["hex"])
- assert(signedtx["complete"])
+ assert signedtx["complete"]
self.nodes[0].sendrawtransaction(signedtx["hex"])
self.nodes[0].generate(1)
self.sync_all()
@@ -662,6 +662,7 @@ class RawTransactionsTest(BitcoinTestFramework):
result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee})
result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10*min_relay_tx_fee})
+ assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[3].fundrawtransaction, rawtx, {"feeRate": 1})
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
@@ -676,10 +677,10 @@ class RawTransactionsTest(BitcoinTestFramework):
for out in res_dec['vout']:
if out['value'] > 1.0:
changeaddress += out['scriptPubKey']['addresses'][0]
- assert(changeaddress != "")
+ assert changeaddress != ""
nextaddr = self.nodes[3].getnewaddress()
# Now the change address key should be removed from the keypool
- assert(changeaddress != nextaddr)
+ assert changeaddress != nextaddr
######################################
# Test subtractFeeFromOutputs option #
diff --git a/test/functional/rpc_getblockfilter.py b/test/functional/rpc_getblockfilter.py
new file mode 100755
index 0000000000..bd93b6f7a4
--- /dev/null
+++ b/test/functional/rpc_getblockfilter.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal, assert_is_hex_string, assert_raises_rpc_error,
+ connect_nodes, disconnect_nodes, sync_blocks
+ )
+
+FILTER_TYPES = ["basic"]
+
+class GetBlockFilterTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+ self.extra_args = [["-blockfilterindex"], []]
+
+ def run_test(self):
+ # Create two chains by disconnecting nodes 0 & 1, mining, then reconnecting
+ disconnect_nodes(self.nodes[0], 1)
+
+ self.nodes[0].generate(3)
+ self.nodes[1].generate(4)
+
+ assert_equal(self.nodes[0].getblockcount(), 3)
+ chain0_hashes = [self.nodes[0].getblockhash(block_height) for block_height in range(4)]
+
+ # Reorg node 0 to a new chain
+ connect_nodes(self.nodes[0], 1)
+ sync_blocks(self.nodes)
+
+ assert_equal(self.nodes[0].getblockcount(), 4)
+ chain1_hashes = [self.nodes[0].getblockhash(block_height) for block_height in range(4)]
+
+ # Test getblockfilter returns a filter for all blocks and filter types on active chain
+ for block_hash in chain1_hashes:
+ for filter_type in FILTER_TYPES:
+ result = self.nodes[0].getblockfilter(block_hash, filter_type)
+ assert_is_hex_string(result['filter'])
+
+ # Test getblockfilter returns a filter for all blocks and filter types on stale chain
+ for block_hash in chain0_hashes:
+ for filter_type in FILTER_TYPES:
+ result = self.nodes[0].getblockfilter(block_hash, filter_type)
+ assert_is_hex_string(result['filter'])
+
+ # Test getblockfilter with unknown block
+ bad_block_hash = "0123456789abcdef" * 4
+ assert_raises_rpc_error(-5, "Block not found", self.nodes[0].getblockfilter, bad_block_hash, "basic")
+
+ # Test getblockfilter with undefined filter type
+ genesis_hash = self.nodes[0].getblockhash(0)
+ assert_raises_rpc_error(-5, "Unknown filtertype", self.nodes[0].getblockfilter, genesis_hash, "unknown")
+
+if __name__ == '__main__':
+ GetBlockFilterTest().main()
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index feba16f1b3..efab69ac26 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
@@ -13,7 +13,6 @@ from test_framework.util import (
)
import json
import os
-import time
TESTSDIR = os.path.dirname(os.path.realpath(__file__))
@@ -21,18 +20,6 @@ class GetblockstatsTest(BitcoinTestFramework):
start_height = 101
max_stat_pos = 2
- STATS_NEED_TXINDEX = [
- 'avgfee',
- 'avgfeerate',
- 'maxfee',
- 'maxfeerate',
- 'medianfee',
- 'feerate_percentiles',
- 'minfee',
- 'minfeerate',
- 'totalfee',
- 'utxo_size_inc',
- ]
def add_options(self, parser):
parser.add_argument('--gen-test-data', dest='gen_test_data',
@@ -44,24 +31,26 @@ class GetblockstatsTest(BitcoinTestFramework):
help='Test data file')
def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [['-txindex'], ['-paytxfee=0.003']]
+ self.num_nodes = 1
self.setup_clean_chain = True
def get_stats(self):
return [self.nodes[0].getblockstats(hash_or_height=self.start_height + i) for i in range(self.max_stat_pos+1)]
def generate_test_data(self, filename):
- mocktime = time.time()
+ mocktime = 1525107225
+ self.nodes[0].setmocktime(mocktime)
self.nodes[0].generate(101)
- self.nodes[0].sendtoaddress(address=self.nodes[1].getnewaddress(), amount=10, subtractfeefromamount=True)
+ address = self.nodes[0].get_deterministic_priv_key().address
+ self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
self.nodes[0].generate(1)
self.sync_all()
- self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=10, subtractfeefromamount=True)
- self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=10, subtractfeefromamount=False)
- self.nodes[1].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1, subtractfeefromamount=True)
+ self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=True)
+ self.nodes[0].sendtoaddress(address=address, amount=10, subtractfeefromamount=False)
+ self.nodes[0].settxfee(amount=0.003)
+ self.nodes[0].sendtoaddress(address=address, amount=1, subtractfeefromamount=True)
self.sync_all()
self.nodes[0].generate(1)
@@ -93,11 +82,12 @@ class GetblockstatsTest(BitcoinTestFramework):
# Set the timestamps from the file so that the nodes can get out of Initial Block Download
self.nodes[0].setmocktime(mocktime)
- self.nodes[1].setmocktime(mocktime)
+ self.sync_all()
for b in blocks:
self.nodes[0].submitblock(b)
+
def run_test(self):
test_data = os.path.join(TESTSDIR, self.options.test_data)
if self.options.gen_test_data:
@@ -107,9 +97,6 @@ class GetblockstatsTest(BitcoinTestFramework):
self.sync_all()
stats = self.get_stats()
- expected_stats_noindex = []
- for stat_row in stats:
- expected_stats_noindex.append({k: v for k, v in stat_row.items() if k not in self.STATS_NEED_TXINDEX})
# Make sure all valid statistics are included but nothing else is
expected_keys = self.expected_stats[0].keys()
@@ -127,10 +114,6 @@ class GetblockstatsTest(BitcoinTestFramework):
stats_by_hash = self.nodes[0].getblockstats(hash_or_height=blockhash)
assert_equal(stats_by_hash, self.expected_stats[i])
- # Check with the node that has no txindex
- stats_no_txindex = self.nodes[1].getblockstats(hash_or_height=blockhash, stats=list(expected_stats_noindex[i].keys()))
- assert_equal(stats_no_txindex, expected_stats_noindex[i])
-
# Make sure each stat can be queried on its own
for stat in expected_keys:
for i in range(self.max_stat_pos+1):
@@ -168,12 +151,6 @@ class GetblockstatsTest(BitcoinTestFramework):
# Make sure we aren't always returning inv_sel_stat as the culprit stat
assert_raises_rpc_error(-8, 'Invalid selected statistic aaa%s' % inv_sel_stat,
self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee' , 'aaa%s' % inv_sel_stat])
-
- assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled',
- self.nodes[1].getblockstats, hash_or_height=1)
- assert_raises_rpc_error(-8, 'One or more of the selected stats requires -txindex enabled',
- self.nodes[1].getblockstats, hash_or_height=self.start_height + self.max_stat_pos)
-
# Mainchain's genesis block shouldn't be found on regtest
assert_raises_rpc_error(-5, 'Block not found', self.nodes[0].getblockstats,
hash_or_height='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f')
diff --git a/test/functional/rpc_getchaintips.py b/test/functional/rpc_getchaintips.py
index c869c7262f..8dc8474374 100755
--- a/test/functional/rpc_getchaintips.py
+++ b/test/functional/rpc_getchaintips.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the getchaintips RPC.
@@ -28,7 +28,8 @@ class GetChainTipsTest (BitcoinTestFramework):
self.split_network()
self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
self.nodes[2].generatetoaddress(20, self.nodes[2].get_deterministic_priv_key().address)
- self.sync_all([self.nodes[:2], self.nodes[2:]])
+ self.sync_all(self.nodes[:2])
+ self.sync_all(self.nodes[2:])
tips = self.nodes[1].getchaintips ()
assert_equal (len (tips), 1)
diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py
index d8a1deb2a3..3d3f694fd3 100755
--- a/test/functional/rpc_invalidateblock.py
+++ b/test/functional/rpc_invalidateblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the invalidateblock RPC."""
@@ -9,7 +9,6 @@ from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
from test_framework.util import (
assert_equal,
connect_nodes_bi,
- sync_blocks,
wait_until,
)
@@ -35,7 +34,7 @@ class InvalidateTest(BitcoinTestFramework):
self.log.info("Connect nodes to force a reorg")
connect_nodes_bi(self.nodes, 0, 1)
- sync_blocks(self.nodes[0:2])
+ self.sync_blocks(self.nodes[0:2])
assert_equal(self.nodes[0].getblockcount(), 6)
badhash = self.nodes[1].getblockhash(2)
@@ -47,7 +46,7 @@ class InvalidateTest(BitcoinTestFramework):
self.log.info("Make sure we won't reorg to a lower work chain:")
connect_nodes_bi(self.nodes, 1, 2)
self.log.info("Sync node 2 to node 1 so both have 6 blocks")
- sync_blocks(self.nodes[1:3])
+ self.sync_blocks(self.nodes[1:3])
assert_equal(self.nodes[2].getblockcount(), 6)
self.log.info("Invalidate block 5 on node 1 so its tip is now at 4")
self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5))
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index 7bf8e68176..8a3f8c6f06 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -46,5 +46,13 @@ class RpcMiscTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "unknown mode foobar", node.getmemoryinfo, mode="foobar")
+ self.log.info("test logging")
+ assert_equal(node.logging()['qt'], True)
+ node.logging(exclude=['qt'])
+ assert_equal(node.logging()['qt'], False)
+ node.logging(include=['qt'])
+ assert_equal(node.logging()['qt'], True)
+
+
if __name__ == '__main__':
RpcMiscTest().main()
diff --git a/test/functional/rpc_named_arguments.py b/test/functional/rpc_named_arguments.py
index 6c5c29dfdf..ecac9c2f82 100755
--- a/test/functional/rpc_named_arguments.py
+++ b/test/functional/rpc_named_arguments.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test using named arguments for RPCs."""
@@ -17,7 +17,7 @@ class NamedArgumentTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
h = node.help(command='getblockchaininfo')
- assert(h.startswith('getblockchaininfo\n'))
+ assert h.startswith('getblockchaininfo\n')
assert_raises_rpc_error(-8, 'Unknown named parameter', node.help, random='getblockchaininfo')
diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py
index 72e6e6329f..2d5631bb27 100755
--- a/test/functional/rpc_preciousblock.py
+++ b/test/functional/rpc_preciousblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test the preciousblock RPC."""
@@ -8,7 +8,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes_bi,
- sync_blocks,
)
def unidirectional_node_sync_via_rpc(node_src, node_dest):
@@ -16,7 +15,7 @@ def unidirectional_node_sync_via_rpc(node_src, node_dest):
blockhash = node_src.getbestblockhash()
while True:
try:
- assert(len(node_dest.getblock(blockhash, False)) > 0)
+ assert len(node_dest.getblock(blockhash, False)) > 0
break
except:
blocks_to_copy.append(blockhash)
@@ -24,7 +23,7 @@ def unidirectional_node_sync_via_rpc(node_src, node_dest):
blocks_to_copy.reverse()
for blockhash in blocks_to_copy:
blockdata = node_src.getblock(blockhash, False)
- assert(node_dest.submitblock(blockdata) in (None, 'inconclusive'))
+ assert node_dest.submitblock(blockdata) in (None, 'inconclusive')
def node_sync_via_rpc(nodes):
for node_src in nodes:
@@ -57,7 +56,7 @@ class PreciousTest(BitcoinTestFramework):
self.log.info("Mine competing blocks E-F-G on Node 1")
hashG = self.nodes[1].generatetoaddress(3, gen_address(1))[-1]
assert_equal(self.nodes[1].getblockcount(), 5)
- assert(hashC != hashG)
+ assert hashC != hashG
self.log.info("Connect nodes and check no reorg occurs")
# Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync)
node_sync_via_rpc(self.nodes[0:2])
@@ -72,7 +71,7 @@ class PreciousTest(BitcoinTestFramework):
assert_equal(self.nodes[0].getbestblockhash(), hashC)
self.log.info("Make Node1 prefer block C")
self.nodes[1].preciousblock(hashC)
- sync_blocks(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC
+ self.sync_blocks(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC
assert_equal(self.nodes[1].getbestblockhash(), hashC)
self.log.info("Make Node1 prefer block G again")
self.nodes[1].preciousblock(hashG)
@@ -86,7 +85,7 @@ class PreciousTest(BitcoinTestFramework):
self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1")
self.nodes[0].generatetoaddress(1, gen_address(0))
assert_equal(self.nodes[0].getblockcount(), 6)
- sync_blocks(self.nodes[0:2])
+ self.sync_blocks(self.nodes[0:2])
hashH = self.nodes[0].getbestblockhash()
assert_equal(self.nodes[1].getbestblockhash(), hashH)
self.log.info("Node1 should not be able to prefer block C anymore")
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index e9098e4f5a..8bfa7a0238 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
"""Test the Partially Signed Transaction RPCs.
@@ -7,7 +7,14 @@
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, disconnect_nodes, find_output, sync_blocks
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_raises_rpc_error,
+ connect_nodes_bi,
+ disconnect_nodes,
+ find_output,
+)
import json
import os
@@ -41,22 +48,22 @@ class PSBTTest(BitcoinTestFramework):
online_node.importaddress(offline_addr, "", False)
mining_node.sendtoaddress(address=offline_addr, amount=1.0)
mining_node.generate(nblocks=1)
- sync_blocks([mining_node, online_node])
+ self.sync_blocks([mining_node, online_node])
# Construct an unsigned PSBT on the online node (who doesn't know the output is Segwit, so will include a non-witness UTXO)
utxos = online_node.listunspent(addresses=[offline_addr])
raw = online_node.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
psbt = online_node.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
- assert("non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0])
+ assert "non_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]
# Have the offline node sign the PSBT (which will update the UTXO to segwit)
signed_psbt = offline_node.walletprocesspsbt(psbt)["psbt"]
- assert("witness_utxo" in mining_node.decodepsbt(signed_psbt)["inputs"][0])
+ assert "witness_utxo" in mining_node.decodepsbt(signed_psbt)["inputs"][0]
# Make sure we can mine the resulting transaction
txid = mining_node.sendrawtransaction(mining_node.finalizepsbt(signed_psbt)["hex"])
mining_node.generate(1)
- sync_blocks([mining_node, online_node])
+ self.sync_blocks([mining_node, online_node])
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)
# Reconnect
@@ -123,6 +130,15 @@ class PSBTTest(BitcoinTestFramework):
assert_equal(walletprocesspsbt_out['complete'], True)
self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])
+ # feeRate of 0.1 BTC / KB produces a total fee slightly below -maxtxfee (~0.05280000):
+ res = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 0.1})
+ assert_greater_than(res["fee"], 0.05)
+ assert_greater_than(0.06, res["fee"])
+
+ # feeRate of 10 BTC / KB produces a total fee well above -maxtxfee
+ # previously this was silenty capped at -maxtxfee
+ assert_raises_rpc_error(-4, "Fee exceeds maximum configured by -maxtxfee", self.nodes[1].walletcreatefundedpsbt, [{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99}, 0, {"feeRate": 10})
+
# partially sign multisig things with node 1
psbtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
@@ -144,10 +160,12 @@ class PSBTTest(BitcoinTestFramework):
new_psbt = self.nodes[0].converttopsbt(rawtx['hex'])
self.nodes[0].decodepsbt(new_psbt)
- # Make sure that a psbt with signatures cannot be converted
+ # Make sure that a non-psbt with signatures cannot be converted
+ # Error could be either "TX decode failed" (segwit inputs causes parsing to fail) or "Inputs must not have scriptSigs and scriptWitnesses"
+ # We must set iswitness=True because the serialized transaction has inputs and is therefore a witness transaction
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx['hex'])
- assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex'])
- assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].converttopsbt, signedtx['hex'], False)
+ assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], iswitness=True)
+ assert_raises_rpc_error(-22, "", self.nodes[0].converttopsbt, hexstring=signedtx['hex'], permitsigdata=False, iswitness=True)
# Unless we allow it to convert and strip signatures
self.nodes[0].converttopsbt(signedtx['hex'], True)
@@ -192,8 +210,8 @@ class PSBTTest(BitcoinTestFramework):
psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True}, False)
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
- assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
- assert "bip32_derivs" not in psbt_in
+ assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
+ assert "bip32_derivs" not in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height+2)
# Same construction with only locktime set
@@ -355,7 +373,7 @@ class PSBTTest(BitcoinTestFramework):
assert analyzed['inputs'][0]['has_utxo'] and not analyzed['inputs'][0]['is_final'] and analyzed['inputs'][0]['next'] == 'signer' and analyzed['next'] == 'signer' and analyzed['inputs'][0]['missing']['signatures'][0] == addrinfo['embedded']['witness_program']
# Check fee and size things
- assert analyzed['fee'] == Decimal('0.001') and analyzed['estimated_vsize'] == 134 and analyzed['estimated_feerate'] == '0.00746268 BTC/kB'
+ assert analyzed['fee'] == Decimal('0.001') and analyzed['estimated_vsize'] == 134 and analyzed['estimated_feerate'] == Decimal('0.00746268')
# After signing and finalizing, needs extracting
signed = self.nodes[1].walletprocesspsbt(updated)['psbt']
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index c793cf00de..4338675270 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the rawtransaction RPCs.
@@ -17,7 +17,7 @@ from decimal import Decimal
from io import BytesIO
from test_framework.messages import CTransaction, ToHex
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes
+from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, hex_str_to_bytes
class multidict(dict):
"""Dictionary that allows duplicate keys.
@@ -42,7 +42,11 @@ class RawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 3
- self.extra_args = [["-addresstype=legacy", "-txindex"], ["-addresstype=legacy", "-txindex"], ["-addresstype=legacy", "-txindex"]]
+ self.extra_args = [
+ ["-txindex"],
+ ["-txindex"],
+ ["-txindex"],
+ ]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -119,21 +123,21 @@ class RawTransactionsTest(BitcoinTestFramework):
tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs={address: 99}))))
assert_equal(len(tx.vout), 1)
assert_equal(
- bytes_to_hex_str(tx.serialize()),
+ tx.serialize().hex(),
self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}]),
)
# Two outputs
tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)])))))
assert_equal(len(tx.vout), 2)
assert_equal(
- bytes_to_hex_str(tx.serialize()),
+ tx.serialize().hex(),
self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}]),
)
# Multiple mixed outputs
tx.deserialize(BytesIO(hex_str_to_bytes(self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=multidict([(address, 99), (address2, 99), ('data', '99')])))))
assert_equal(len(tx.vout), 3)
assert_equal(
- bytes_to_hex_str(tx.serialize()),
+ tx.serialize().hex(),
self.nodes[2].createrawtransaction(inputs=[{'txid': txid, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]),
)
@@ -285,11 +289,7 @@ class RawTransactionsTest(BitcoinTestFramework):
txDetails = self.nodes[0].gettransaction(txId, True)
rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
- vout = False
- for outpoint in rawTx['vout']:
- if outpoint['value'] == Decimal('2.20000000'):
- vout = outpoint
- break
+ vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('2.20000000'))
bal = self.nodes[0].getbalance()
inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "amount" : vout['value']}]
@@ -330,11 +330,7 @@ class RawTransactionsTest(BitcoinTestFramework):
txDetails = self.nodes[0].gettransaction(txId, True)
rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex'])
- vout = False
- for outpoint in rawTx2['vout']:
- if outpoint['value'] == Decimal('2.20000000'):
- vout = outpoint
- break
+ vout = next(o for o in rawTx2['vout'] if o['value'] == Decimal('2.20000000'))
bal = self.nodes[0].getbalance()
inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "redeemScript" : mSigObjValid['hex'], "amount" : vout['value']}]
@@ -369,30 +365,30 @@ class RawTransactionsTest(BitcoinTestFramework):
# getrawtransaction tests
# 1. valid parameters - only supply txid
- txHash = rawTx["hash"]
- assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex'])
+ txId = rawTx["txid"]
+ assert_equal(self.nodes[0].getrawtransaction(txId), rawTxSigned['hex'])
# 2. valid parameters - supply txid and 0 for non-verbose
- assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex'])
+ assert_equal(self.nodes[0].getrawtransaction(txId, 0), rawTxSigned['hex'])
# 3. valid parameters - supply txid and False for non-verbose
- assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex'])
+ assert_equal(self.nodes[0].getrawtransaction(txId, False), rawTxSigned['hex'])
# 4. valid parameters - supply txid and 1 for verbose.
# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
- assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"], rawTxSigned['hex'])
+ assert_equal(self.nodes[0].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex'])
# 5. valid parameters - supply txid and True for non-verbose
- assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex'])
+ assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"], rawTxSigned['hex'])
# 6. invalid parameters - supply txid and string "Flase"
- assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, "Flase")
+ assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txId, "Flase")
# 7. invalid parameters - supply txid and empty array
- assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, [])
+ assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txId, [])
# 8. invalid parameters - supply txid and empty dict
- assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txHash, {})
+ assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txId, {})
inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}]
outputs = { self.nodes[0].getnewaddress() : 1 }
@@ -434,5 +430,30 @@ class RawTransactionsTest(BitcoinTestFramework):
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
assert_equal(decrawtx['version'], 0x7fffffff)
+ self.log.info('sendrawtransaction/testmempoolaccept with maxfeerate')
+
+ txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
+ rawTx = self.nodes[0].getrawtransaction(txId, True)
+ vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000'))
+
+ self.sync_all()
+ inputs = [{ "txid" : txId, "vout" : vout['n'] }]
+ outputs = { self.nodes[0].getnewaddress() : Decimal("0.99999000") } # 1000 sat fee
+ rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
+ rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
+ assert_equal(rawTxSigned['complete'], True)
+ # 1000 sat fee, ~100 b transaction, fee rate should land around 10 sat/b = 0.00010000 BTC/kB
+ # Thus, testmempoolaccept should reject
+ testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
+ assert_equal(testres['allowed'], False)
+ assert_equal(testres['reject-reason'], '256: absurdly-high-fee')
+ # and sendrawtransaction should throw
+ assert_raises_rpc_error(-26, "absurdly-high-fee", self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
+ # And below calls should both succeed
+ testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate='0.00070000')[0]
+ assert_equal(testres['allowed'], True)
+ self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate='0.00070000')
+
+
if __name__ == '__main__':
RawTransactionsTest().main()
diff --git a/test/functional/rpc_scantxoutset.py b/test/functional/rpc_scantxoutset.py
index 18258f5df3..a1cd33ad54 100755
--- a/test/functional/rpc_scantxoutset.py
+++ b/test/functional/rpc_scantxoutset.py
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
"""Test the scantxoutset rpc call."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
+from test_framework.util import assert_equal, assert_raises_rpc_error
from decimal import Decimal
import shutil
@@ -67,6 +67,13 @@ class ScantxoutsetTest(BitcoinTestFramework):
assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "addr(" + addr_BECH32 + ")"])['total_amount'], Decimal("0.007"))
assert_equal(self.nodes[0].scantxoutset("start", [ "addr(" + addr_P2SH_SEGWIT + ")", "addr(" + addr_LEGACY + ")", "combo(" + pubk3 + ")"])['total_amount'], Decimal("0.007"))
+ self.log.info("Test range validation.")
+ assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": -1}])
+ assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [-1, 10]}])
+ assert_raises_rpc_error(-8, "End of range is too high", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]}])
+ assert_raises_rpc_error(-8, "Range specified as [begin,end] must not have begin after end", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [2, 1]}])
+ assert_raises_rpc_error(-8, "Range is too large", self.nodes[0].scantxoutset, "start", [ {"desc": "desc", "range": [0, 1000001]}])
+
self.log.info("Test extended key derivation.")
# Run various scans, and verify that the sum of the amounts of the matches corresponds to the expected subset.
# Note that all amounts in the UTXO set are powers of 2 multiplied by 0.001 BTC, so each amounts uniquely identifies a subset.
diff --git a/test/functional/rpc_signmessage.py b/test/functional/rpc_signmessage.py
index ad0e29b451..0cb3ce4215 100755
--- a/test/functional/rpc_signmessage.py
+++ b/test/functional/rpc_signmessage.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test RPC commands for signing and verifying messages."""
@@ -25,18 +25,18 @@ class SignMessagesTest(BitcoinTestFramework):
expected_signature = 'INbVnW4e6PeRmsv2Qgu8NuopvrVjkcxob+sX8OcZG0SALhWybUjzMLPdAsXI46YZGb0KQTRii+wWIQzRpG/U+S0='
signature = self.nodes[0].signmessagewithprivkey(priv_key, message)
assert_equal(expected_signature, signature)
- assert(self.nodes[0].verifymessage(address, signature, message))
+ assert self.nodes[0].verifymessage(address, signature, message)
self.log.info('test signing with an address with wallet')
address = self.nodes[0].getnewaddress()
signature = self.nodes[0].signmessage(address, message)
- assert(self.nodes[0].verifymessage(address, signature, message))
+ assert self.nodes[0].verifymessage(address, signature, message)
self.log.info('test verifying with another address should not work')
other_address = self.nodes[0].getnewaddress()
other_signature = self.nodes[0].signmessage(other_address, message)
- assert(not self.nodes[0].verifymessage(other_address, signature, message))
- assert(not self.nodes[0].verifymessage(address, other_signature, message))
+ assert not self.nodes[0].verifymessage(other_address, signature, message)
+ assert not self.nodes[0].verifymessage(address, other_signature, message)
if __name__ == '__main__':
SignMessagesTest().main()
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index 56e2c73a90..780758e219 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test transaction signing using the signrawtransaction* RPCs."""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, bytes_to_hex_str, hex_str_to_bytes
+from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes
from test_framework.messages import sha256
from test_framework.script import CScript, OP_0
@@ -15,7 +15,6 @@ class SignRawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 2
- self.extra_args = [["-deprecatedrpc=signrawtransaction"], []]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
@@ -161,7 +160,7 @@ class SignRawTransactionsTest(BitcoinTestFramework):
unspent_output = self.nodes[1].listunspent(0, 999999, [p2sh_p2wsh_address["address"]])[0]
assert_equal(unspent_output["witnessScript"], p2sh_p2wsh_address["redeemScript"])
p2sh_redeemScript = CScript([OP_0, sha256(hex_str_to_bytes(p2sh_p2wsh_address["redeemScript"]))])
- assert_equal(unspent_output["redeemScript"], bytes_to_hex_str(p2sh_redeemScript))
+ assert_equal(unspent_output["redeemScript"], p2sh_redeemScript.hex())
# Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys
spending_tx = self.nodes[0].createrawtransaction([unspent_output], {self.nodes[1].getnewaddress(): Decimal("49.998")})
spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [unspent_output])
diff --git a/test/functional/rpc_uptime.py b/test/functional/rpc_uptime.py
index 20b6341550..e86f91b1d0 100755
--- a/test/functional/rpc_uptime.py
+++ b/test/functional/rpc_uptime.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test the RPC call related to the uptime command.
@@ -23,7 +23,7 @@ class UptimeTest(BitcoinTestFramework):
def _test_uptime(self):
wait_time = 10
self.nodes[0].setmocktime(int(time.time() + wait_time))
- assert(self.nodes[0].uptime() >= wait_time)
+ assert self.nodes[0].uptime() >= wait_time
if __name__ == '__main__':
diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py
index 456d43aa2e..f36cffe957 100644
--- a/test/functional/test_framework/address.py
+++ b/test/functional/test_framework/address.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Encode and decode BASE58, P2PKH and P2SH addresses."""
from .script import hash256, hash160, sha256, CScript, OP_0
-from .util import bytes_to_hex_str, hex_str_to_bytes
+from .util import hex_str_to_bytes
from . import segwit_addr
@@ -16,9 +16,9 @@ chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def byte_to_base58(b, version):
result = ''
- str = bytes_to_hex_str(b)
- str = bytes_to_hex_str(chr(version).encode('latin-1')) + str
- checksum = bytes_to_hex_str(hash256(hex_str_to_bytes(str)))
+ str = b.hex()
+ str = chr(version).encode('latin-1').hex() + str
+ checksum = hash256(hex_str_to_bytes(str)).hex()
str += checksum[:8]
value = int('0x'+str,0)
while value > 0:
@@ -32,12 +32,12 @@ def byte_to_base58(b, version):
# TODO: def base58_decode
def keyhash_to_p2pkh(hash, main = False):
- assert (len(hash) == 20)
+ assert len(hash) == 20
version = 0 if main else 111
return byte_to_base58(hash, version)
def scripthash_to_p2sh(hash, main = False):
- assert (len(hash) == 20)
+ assert len(hash) == 20
version = 5 if main else 196
return byte_to_base58(hash, version)
@@ -80,11 +80,11 @@ def check_key(key):
key = hex_str_to_bytes(key) # Assuming this is hex string
if (type(key) is bytes and (len(key) == 33 or len(key) == 65)):
return key
- assert(False)
+ assert False
def check_script(script):
if (type(script) is str):
script = hex_str_to_bytes(script) # Assuming this is hex string
if (type(script) is bytes or type(script) is CScript):
return script
- assert(False)
+ assert False
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index 1140fe9b3e..4ba6ac1db2 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -35,6 +35,7 @@ ServiceProxy class:
import base64
import decimal
+from http import HTTPStatus
import http.client
import json
import logging
@@ -49,13 +50,14 @@ USER_AGENT = "AuthServiceProxy/0.1"
log = logging.getLogger("BitcoinRPC")
class JSONRPCException(Exception):
- def __init__(self, rpc_error):
+ def __init__(self, rpc_error, http_status=None):
try:
errmsg = '%(message)s (%(code)i)' % rpc_error
except (KeyError, TypeError):
errmsg = ''
super().__init__(errmsg)
self.error = rpc_error
+ self.http_status = http_status
def EncodeDecimal(o):
@@ -120,8 +122,11 @@ class AuthServiceProxy():
def get_request(self, *args, **argsn):
AuthServiceProxy.__id_count += 1
- log.debug("-%s-> %s %s" % (AuthServiceProxy.__id_count, self._service_name,
- json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
+ log.debug("-{}-> {} {}".format(
+ AuthServiceProxy.__id_count,
+ self._service_name,
+ json.dumps(args or argsn, default=EncodeDecimal, ensure_ascii=self.ensure_ascii),
+ ))
if args and argsn:
raise ValueError('Cannot handle both named and positional arguments')
return {'version': '1.1',
@@ -131,19 +136,26 @@ class AuthServiceProxy():
def __call__(self, *args, **argsn):
postdata = json.dumps(self.get_request(*args, **argsn), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
- response = self._request('POST', self.__url.path, postdata.encode('utf-8'))
+ response, status = self._request('POST', self.__url.path, postdata.encode('utf-8'))
if response['error'] is not None:
- raise JSONRPCException(response['error'])
+ raise JSONRPCException(response['error'], status)
elif 'result' not in response:
raise JSONRPCException({
- 'code': -343, 'message': 'missing JSON-RPC result'})
+ 'code': -343, 'message': 'missing JSON-RPC result'}, status)
+ elif status != HTTPStatus.OK:
+ raise JSONRPCException({
+ 'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status)
else:
return response['result']
def batch(self, rpc_call_list):
postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.ensure_ascii)
log.debug("--> " + postdata)
- return self._request('POST', self.__url.path, postdata.encode('utf-8'))
+ response, status = self._request('POST', self.__url.path, postdata.encode('utf-8'))
+ if status != HTTPStatus.OK:
+ raise JSONRPCException({
+ 'code': -342, 'message': 'non-200 HTTP status code but no JSON-RPC error'}, status)
+ return response
def _get_response(self):
req_start_time = time.time()
@@ -162,8 +174,9 @@ class AuthServiceProxy():
content_type = http_response.getheader('Content-Type')
if content_type != 'application/json':
- raise JSONRPCException({
- 'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)})
+ raise JSONRPCException(
+ {'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)},
+ http_response.status)
responsedata = http_response.read().decode('utf8')
response = json.loads(responsedata, parse_float=decimal.Decimal)
@@ -172,7 +185,7 @@ class AuthServiceProxy():
log.debug("<-%s- [%.6f] %s" % (response["id"], elapsed, json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii)))
else:
log.debug("<-- [%.6f] %s" % (elapsed, responsedata))
- return response
+ return response, http_response.status
def __truediv__(self, relative_uri):
return AuthServiceProxy("{}/{}".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn)
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 15f4502994..7ac044d0d0 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -20,7 +20,6 @@ from .messages import (
CTxOut,
FromHex,
ToHex,
- bytes_to_hex_str,
hash256,
hex_str_to_bytes,
ser_string,
@@ -132,7 +131,7 @@ def create_tx_with_script(prevtx, n, script_sig=b"", *, amount, script_pub_key=C
Can optionally pass scriptPubKey and scriptSig, default is anyone-can-spend output.
"""
tx = CTransaction()
- assert(n < len(prevtx.vout))
+ assert n < len(prevtx.vout)
tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), script_sig, 0xffffffff))
tx.vout.append(CTxOut(amount, script_pub_key))
tx.calc_sha256()
@@ -190,7 +189,7 @@ def witness_script(use_p2wsh, pubkey):
witness_program = CScript([OP_1, hex_str_to_bytes(pubkey), OP_1, OP_CHECKMULTISIG])
scripthash = sha256(witness_program)
pkscript = CScript([OP_0, scripthash])
- return bytes_to_hex_str(pkscript)
+ return pkscript.hex()
def create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount):
"""Return a transaction (in hex) that spends the given utxo to a segwit output.
@@ -215,7 +214,7 @@ def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=Tru
tx_to_witness = create_witness_tx(node, use_p2wsh, utxo, pubkey, encode_p2sh, amount)
if (sign):
signed = node.signrawtransactionwithwallet(tx_to_witness)
- assert("errors" not in signed or len(["errors"]) == 0)
+ assert "errors" not in signed or len(["errors"]) == 0
return node.sendrawtransaction(signed["hex"])
else:
if (insert_redeem_script):
diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py
index 1b3e510dc4..912c0ca978 100644
--- a/test/functional/test_framework/key.py
+++ b/test/functional/test_framework/key.py
@@ -1,226 +1,386 @@
-# Copyright (c) 2011 Sam Rushing
-"""ECC secp256k1 OpenSSL wrapper.
+# Copyright (c) 2019 Pieter Wuille
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test-only secp256k1 elliptic curve implementation
-WARNING: This module does not mlock() secrets; your private keys may end up on
-disk in swap! Use with caution!
+WARNING: This code is slow, uses bad randomness, does not properly protect
+keys, and is trivially vulnerable to side channel attacks. Do not use for
+anything but tests."""
+import random
-This file is modified from python-bitcoinlib.
-"""
-
-import ctypes
-import ctypes.util
-import hashlib
-
-ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library ('ssl') or 'libeay32')
-
-ssl.BN_new.restype = ctypes.c_void_p
-ssl.BN_new.argtypes = []
-
-ssl.BN_bin2bn.restype = ctypes.c_void_p
-ssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p]
-
-ssl.BN_CTX_free.restype = None
-ssl.BN_CTX_free.argtypes = [ctypes.c_void_p]
-
-ssl.BN_CTX_new.restype = ctypes.c_void_p
-ssl.BN_CTX_new.argtypes = []
-
-ssl.ECDH_compute_key.restype = ctypes.c_int
-ssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p]
-
-ssl.ECDSA_sign.restype = ctypes.c_int
-ssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
-
-ssl.ECDSA_verify.restype = ctypes.c_int
-ssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
-
-ssl.EC_KEY_free.restype = None
-ssl.EC_KEY_free.argtypes = [ctypes.c_void_p]
-
-ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
-ssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int]
-
-ssl.EC_KEY_get0_group.restype = ctypes.c_void_p
-ssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p]
-
-ssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p
-ssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p]
-
-ssl.EC_KEY_set_private_key.restype = ctypes.c_int
-ssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
-
-ssl.EC_KEY_set_conv_form.restype = None
-ssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int]
-
-ssl.EC_KEY_set_public_key.restype = ctypes.c_int
-ssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
-
-ssl.i2o_ECPublicKey.restype = ctypes.c_void_p
-ssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
-
-ssl.EC_POINT_new.restype = ctypes.c_void_p
-ssl.EC_POINT_new.argtypes = [ctypes.c_void_p]
-
-ssl.EC_POINT_free.restype = None
-ssl.EC_POINT_free.argtypes = [ctypes.c_void_p]
-
-ssl.EC_POINT_mul.restype = ctypes.c_int
-ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
-
-# this specifies the curve used with ECDSA.
-NID_secp256k1 = 714 # from openssl/obj_mac.h
+def modinv(a, n):
+ """Compute the modular inverse of a modulo n
+ See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers.
+ """
+ t1, t2 = 0, 1
+ r1, r2 = n, a
+ while r2 != 0:
+ q = r1 // r2
+ t1, t2 = t2, t1 - q * t2
+ r1, r2 = r2, r1 - q * r2
+ if r1 > 1:
+ return None
+ if t1 < 0:
+ t1 += n
+ return t1
+
+def jacobi_symbol(n, k):
+ """Compute the Jacobi symbol of n modulo k
+
+ See http://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"
+ n %= k
+ t = 0
+ while n != 0:
+ while n & 1 == 0:
+ n >>= 1
+ r = k & 7
+ t ^= (r == 3 or r == 5)
+ n, k = k, n
+ t ^= (n & k & 3 == 3)
+ n = n % k
+ if k == 1:
+ return -1 if t else 1
+ return 0
+
+def modsqrt(a, p):
+ """Compute the square root of a modulo p when p % 4 = 3.
+
+ The Tonelli-Shanks algorithm can be used. See https://en.wikipedia.org/wiki/Tonelli-Shanks_algorithm
+
+ Limiting this function to only work for p % 4 = 3 means we don't need to
+ iterate through the loop. The highest n such that p - 1 = 2^n Q with Q odd
+ is n = 1. Therefore Q = (p-1)/2 and sqrt = a^((Q+1)/2) = a^((p+1)/4)
+
+ secp256k1's is defined over field of size 2**256 - 2**32 - 977, which is 3 mod 4.
+ """
+ if p % 4 != 3:
+ raise NotImplementedError("modsqrt only implemented for p % 4 = 3")
+ sqrt = pow(a, (p + 1)//4, p)
+ if pow(sqrt, 2, p) == a % p:
+ return sqrt
+ return None
+
+class EllipticCurve:
+ def __init__(self, p, a, b):
+ """Initialize elliptic curve y^2 = x^3 + a*x + b over GF(p)."""
+ self.p = p
+ self.a = a % p
+ self.b = b % p
+
+ def affine(self, p1):
+ """Convert a Jacobian point tuple p1 to affine form, or None if at infinity.
+
+ An affine point is represented as the Jacobian (x, y, 1)"""
+ x1, y1, z1 = p1
+ if z1 == 0:
+ return None
+ inv = modinv(z1, self.p)
+ inv_2 = (inv**2) % self.p
+ inv_3 = (inv_2 * inv) % self.p
+ return ((inv_2 * x1) % self.p, (inv_3 * y1) % self.p, 1)
+
+ def negate(self, p1):
+ """Negate a Jacobian point tuple p1."""
+ x1, y1, z1 = p1
+ return (x1, (self.p - y1) % self.p, z1)
+
+ def on_curve(self, p1):
+ """Determine whether a Jacobian tuple p is on the curve (and not infinity)"""
+ x1, y1, z1 = p1
+ z2 = pow(z1, 2, self.p)
+ z4 = pow(z2, 2, self.p)
+ return z1 != 0 and (pow(x1, 3, self.p) + self.a * x1 * z4 + self.b * z2 * z4 - pow(y1, 2, self.p)) % self.p == 0
+
+ def is_x_coord(self, x):
+ """Test whether x is a valid X coordinate on the curve."""
+ x_3 = pow(x, 3, self.p)
+ return jacobi_symbol(x_3 + self.a * x + self.b, self.p) != -1
+
+ def lift_x(self, x):
+ """Given an X coordinate on the curve, return a corresponding affine point."""
+ x_3 = pow(x, 3, self.p)
+ v = x_3 + self.a * x + self.b
+ y = modsqrt(v, self.p)
+ if y is None:
+ return None
+ return (x, y, 1)
+
+ def double(self, p1):
+ """Double a Jacobian tuple p1
+
+ See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Doubling"""
+ x1, y1, z1 = p1
+ if z1 == 0:
+ return (0, 1, 0)
+ y1_2 = (y1**2) % self.p
+ y1_4 = (y1_2**2) % self.p
+ x1_2 = (x1**2) % self.p
+ s = (4*x1*y1_2) % self.p
+ m = 3*x1_2
+ if self.a:
+ m += self.a * pow(z1, 4, self.p)
+ m = m % self.p
+ x2 = (m**2 - 2*s) % self.p
+ y2 = (m*(s - x2) - 8*y1_4) % self.p
+ z2 = (2*y1*z1) % self.p
+ return (x2, y2, z2)
+
+ def add_mixed(self, p1, p2):
+ """Add a Jacobian tuple p1 and an affine tuple p2
+
+ See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Addition (with affine point)"""
+ x1, y1, z1 = p1
+ x2, y2, z2 = p2
+ assert(z2 == 1)
+ # Adding to the point at infinity is a no-op
+ if z1 == 0:
+ return p2
+ z1_2 = (z1**2) % self.p
+ z1_3 = (z1_2 * z1) % self.p
+ u2 = (x2 * z1_2) % self.p
+ s2 = (y2 * z1_3) % self.p
+ if x1 == u2:
+ if (y1 != s2):
+ # p1 and p2 are inverses. Return the point at infinity.
+ return (0, 1, 0)
+ # p1 == p2. The formulas below fail when the two points are equal.
+ return self.double(p1)
+ h = u2 - x1
+ r = s2 - y1
+ h_2 = (h**2) % self.p
+ h_3 = (h_2 * h) % self.p
+ u1_h_2 = (x1 * h_2) % self.p
+ x3 = (r**2 - h_3 - 2*u1_h_2) % self.p
+ y3 = (r*(u1_h_2 - x3) - y1*h_3) % self.p
+ z3 = (h*z1) % self.p
+ return (x3, y3, z3)
+
+ def add(self, p1, p2):
+ """Add two Jacobian tuples p1 and p2
+
+ See https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates - Point Addition"""
+ x1, y1, z1 = p1
+ x2, y2, z2 = p2
+ # Adding the point at infinity is a no-op
+ if z1 == 0:
+ return p2
+ if z2 == 0:
+ return p1
+ # Adding an Affine to a Jacobian is more efficient since we save field multiplications and squarings when z = 1
+ if z1 == 1:
+ return self.add_mixed(p2, p1)
+ if z2 == 1:
+ return self.add_mixed(p1, p2)
+ z1_2 = (z1**2) % self.p
+ z1_3 = (z1_2 * z1) % self.p
+ z2_2 = (z2**2) % self.p
+ z2_3 = (z2_2 * z2) % self.p
+ u1 = (x1 * z2_2) % self.p
+ u2 = (x2 * z1_2) % self.p
+ s1 = (y1 * z2_3) % self.p
+ s2 = (y2 * z1_3) % self.p
+ if u1 == u2:
+ if (s1 != s2):
+ # p1 and p2 are inverses. Return the point at infinity.
+ return (0, 1, 0)
+ # p1 == p2. The formulas below fail when the two points are equal.
+ return self.double(p1)
+ h = u2 - u1
+ r = s2 - s1
+ h_2 = (h**2) % self.p
+ h_3 = (h_2 * h) % self.p
+ u1_h_2 = (u1 * h_2) % self.p
+ x3 = (r**2 - h_3 - 2*u1_h_2) % self.p
+ y3 = (r*(u1_h_2 - x3) - s1*h_3) % self.p
+ z3 = (h*z1*z2) % self.p
+ return (x3, y3, z3)
+
+ def mul(self, ps):
+ """Compute a (multi) point multiplication
+
+ ps is a list of (Jacobian tuple, scalar) pairs.
+ """
+ r = (0, 1, 0)
+ for i in range(255, -1, -1):
+ r = self.double(r)
+ for (p, n) in ps:
+ if ((n >> i) & 1):
+ r = self.add(r, p)
+ return r
+
+SECP256K1 = EllipticCurve(2**256 - 2**32 - 977, 0, 7)
+SECP256K1_G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8, 1)
SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2
-# Thx to Sam Devlin for the ctypes magic 64-bit fix.
-def _check_result(val, func, args):
- if val == 0:
- raise ValueError
- else:
- return ctypes.c_void_p (val)
-
-ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
-ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
-
-class CECKey():
- """Wrapper around OpenSSL's EC_KEY"""
-
- POINT_CONVERSION_COMPRESSED = 2
- POINT_CONVERSION_UNCOMPRESSED = 4
+class ECPubKey():
+ """A secp256k1 public key"""
def __init__(self):
- self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1)
-
- def __del__(self):
- if ssl:
- ssl.EC_KEY_free(self.k)
- self.k = None
-
- def set_secretbytes(self, secret):
- priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new())
- group = ssl.EC_KEY_get0_group(self.k)
- pub_key = ssl.EC_POINT_new(group)
- ctx = ssl.BN_CTX_new()
- if not ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx):
- raise ValueError("Could not derive public key from the supplied secret.")
- ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx)
- ssl.EC_KEY_set_private_key(self.k, priv_key)
- ssl.EC_KEY_set_public_key(self.k, pub_key)
- ssl.EC_POINT_free(pub_key)
- ssl.BN_CTX_free(ctx)
- return self.k
-
- def set_privkey(self, key):
- self.mb = ctypes.create_string_buffer(key)
- return ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
-
- def set_pubkey(self, key):
- self.mb = ctypes.create_string_buffer(key)
- return ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
-
- def get_privkey(self):
- size = ssl.i2d_ECPrivateKey(self.k, 0)
- mb_pri = ctypes.create_string_buffer(size)
- ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri)))
- return mb_pri.raw
-
- def get_pubkey(self):
- size = ssl.i2o_ECPublicKey(self.k, 0)
- mb = ctypes.create_string_buffer(size)
- ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb)))
- return mb.raw
-
- def get_raw_ecdh_key(self, other_pubkey):
- ecdh_keybuffer = ctypes.create_string_buffer(32)
- r = ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32,
- ssl.EC_KEY_get0_public_key(other_pubkey.k),
- self.k, 0)
- if r != 32:
- raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed')
- return ecdh_keybuffer.raw
-
- def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
- # FIXME: be warned it's not clear what the kdf should be as a default
- r = self.get_raw_ecdh_key(other_pubkey)
- return kdf(r)
-
- def sign(self, hash, low_s = True):
- # FIXME: need unit tests for below cases
- if not isinstance(hash, bytes):
- raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
- if len(hash) != 32:
- raise ValueError('Hash must be exactly 32 bytes long')
-
- sig_size0 = ctypes.c_uint32()
- sig_size0.value = ssl.ECDSA_size(self.k)
- mb_sig = ctypes.create_string_buffer(sig_size0.value)
- result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
- assert 1 == result
- assert mb_sig.raw[0] == 0x30
- assert mb_sig.raw[1] == sig_size0.value - 2
- total_size = mb_sig.raw[1]
- assert mb_sig.raw[2] == 2
- r_size = mb_sig.raw[3]
- assert mb_sig.raw[4 + r_size] == 2
- s_size = mb_sig.raw[5 + r_size]
- s_value = int.from_bytes(mb_sig.raw[6+r_size:6+r_size+s_size], byteorder='big')
- if (not low_s) or s_value <= SECP256K1_ORDER_HALF:
- return mb_sig.raw[:sig_size0.value]
- else:
- low_s_value = SECP256K1_ORDER - s_value
- low_s_bytes = (low_s_value).to_bytes(33, byteorder='big')
- while len(low_s_bytes) > 1 and low_s_bytes[0] == 0 and low_s_bytes[1] < 0x80:
- low_s_bytes = low_s_bytes[1:]
- new_s_size = len(low_s_bytes)
- new_total_size_byte = (total_size + new_s_size - s_size).to_bytes(1,byteorder='big')
- new_s_size_byte = (new_s_size).to_bytes(1,byteorder='big')
- return b'\x30' + new_total_size_byte + mb_sig.raw[2:5+r_size] + new_s_size_byte + low_s_bytes
-
- def verify(self, hash, sig):
- """Verify a DER signature"""
- return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) == 1
-
- def set_compressed(self, compressed):
- if compressed:
- form = self.POINT_CONVERSION_COMPRESSED
+ """Construct an uninitialized public key"""
+ self.valid = False
+
+ def set(self, data):
+ """Construct a public key from a serialization in compressed or uncompressed format"""
+ if (len(data) == 65 and data[0] == 0x04):
+ p = (int.from_bytes(data[1:33], 'big'), int.from_bytes(data[33:65], 'big'), 1)
+ self.valid = SECP256K1.on_curve(p)
+ if self.valid:
+ self.p = p
+ self.compressed = False
+ elif (len(data) == 33 and (data[0] == 0x02 or data[0] == 0x03)):
+ x = int.from_bytes(data[1:33], 'big')
+ if SECP256K1.is_x_coord(x):
+ p = SECP256K1.lift_x(x)
+ # if the oddness of the y co-ord isn't correct, find the other
+ # valid y
+ if (p[1] & 1) != (data[0] & 1):
+ p = SECP256K1.negate(p)
+ self.p = p
+ self.valid = True
+ self.compressed = True
+ else:
+ self.valid = False
else:
- form = self.POINT_CONVERSION_UNCOMPRESSED
- ssl.EC_KEY_set_conv_form(self.k, form)
-
+ self.valid = False
-class CPubKey(bytes):
- """An encapsulated public key
-
- Attributes:
+ @property
+ def is_compressed(self):
+ return self.compressed
- is_valid - Corresponds to CPubKey.IsValid()
- is_fullyvalid - Corresponds to CPubKey.IsFullyValid()
- is_compressed - Corresponds to CPubKey.IsCompressed()
- """
+ @property
+ def is_valid(self):
+ return self.valid
+
+ def get_bytes(self):
+ assert(self.valid)
+ p = SECP256K1.affine(self.p)
+ if p is None:
+ return None
+ if self.compressed:
+ return bytes([0x02 + (p[1] & 1)]) + p[0].to_bytes(32, 'big')
+ else:
+ return bytes([0x04]) + p[0].to_bytes(32, 'big') + p[1].to_bytes(32, 'big')
+
+ def verify_ecdsa(self, sig, msg, low_s=True):
+ """Verify a strictly DER-encoded ECDSA signature against this pubkey.
+
+ See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
+ ECDSA verifier algorithm"""
+ assert(self.valid)
+
+ # Extract r and s from the DER formatted signature. Return false for
+ # any DER encoding errors.
+ if (sig[1] + 2 != len(sig)):
+ return False
+ if (len(sig) < 4):
+ return False
+ if (sig[0] != 0x30):
+ return False
+ if (sig[2] != 0x02):
+ return False
+ rlen = sig[3]
+ if (len(sig) < 6 + rlen):
+ return False
+ if rlen < 1 or rlen > 33:
+ return False
+ if sig[4] >= 0x80:
+ return False
+ if (rlen > 1 and (sig[4] == 0) and not (sig[5] & 0x80)):
+ return False
+ r = int.from_bytes(sig[4:4+rlen], 'big')
+ if (sig[4+rlen] != 0x02):
+ return False
+ slen = sig[5+rlen]
+ if slen < 1 or slen > 33:
+ return False
+ if (len(sig) != 6 + rlen + slen):
+ return False
+ if sig[6+rlen] >= 0x80:
+ return False
+ if (slen > 1 and (sig[6+rlen] == 0) and not (sig[7+rlen] & 0x80)):
+ return False
+ s = int.from_bytes(sig[6+rlen:6+rlen+slen], 'big')
+
+ # Verify that r and s are within the group order
+ if r < 1 or s < 1 or r >= SECP256K1_ORDER or s >= SECP256K1_ORDER:
+ return False
+ if low_s and s >= SECP256K1_ORDER_HALF:
+ return False
+ z = int.from_bytes(msg, 'big')
+
+ # Run verifier algorithm on r, s
+ w = modinv(s, SECP256K1_ORDER)
+ u1 = z*w % SECP256K1_ORDER
+ u2 = r*w % SECP256K1_ORDER
+ R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, u1), (self.p, u2)]))
+ if R is None or R[0] != r:
+ return False
+ return True
+
+class ECKey():
+ """A secp256k1 private key"""
- def __new__(cls, buf, _cec_key=None):
- self = super(CPubKey, cls).__new__(cls, buf)
- if _cec_key is None:
- _cec_key = CECKey()
- self._cec_key = _cec_key
- self.is_fullyvalid = _cec_key.set_pubkey(self) != 0
- return self
+ def __init__(self):
+ self.valid = False
+
+ def set(self, secret, compressed):
+ """Construct a private key object with given 32-byte secret and compressed flag."""
+ assert(len(secret) == 32)
+ secret = int.from_bytes(secret, 'big')
+ self.valid = (secret > 0 and secret < SECP256K1_ORDER)
+ if self.valid:
+ self.secret = secret
+ self.compressed = compressed
+
+ def generate(self, compressed=True):
+ """Generate a random private key (compressed or uncompressed)."""
+ self.set(random.randrange(1, SECP256K1_ORDER).to_bytes(32, 'big'), compressed)
+
+ def get_bytes(self):
+ """Retrieve the 32-byte representation of this key."""
+ assert(self.valid)
+ return self.secret.to_bytes(32, 'big')
@property
def is_valid(self):
- return len(self) > 0
+ return self.valid
@property
def is_compressed(self):
- return len(self) == 33
-
- def verify(self, hash, sig):
- return self._cec_key.verify(hash, sig)
-
- def __str__(self):
- return repr(self)
-
- def __repr__(self):
- return '%s(%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__())
+ return self.compressed
+ def get_pubkey(self):
+ """Compute an ECPubKey object for this secret key."""
+ assert(self.valid)
+ ret = ECPubKey()
+ p = SECP256K1.mul([(SECP256K1_G, self.secret)])
+ ret.p = p
+ ret.valid = True
+ ret.compressed = self.compressed
+ return ret
+
+ def sign_ecdsa(self, msg, low_s=True):
+ """Construct a DER-encoded ECDSA signature with this key.
+
+ See https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm for the
+ ECDSA signer algorithm."""
+ assert(self.valid)
+ z = int.from_bytes(msg, 'big')
+ # Note: no RFC6979, but a simple random nonce (some tests rely on distinct transactions for the same operation)
+ k = random.randrange(1, SECP256K1_ORDER)
+ R = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, k)]))
+ r = R[0] % SECP256K1_ORDER
+ s = (modinv(k, SECP256K1_ORDER) * (z + self.secret * r)) % SECP256K1_ORDER
+ if low_s and s > SECP256K1_ORDER_HALF:
+ s = SECP256K1_ORDER - s
+ # Represent in DER format. The byte representations of r and s have
+ # length rounded up (255 bits becomes 32 bytes and 256 bits becomes 33
+ # bytes).
+ rb = r.to_bytes((r.bit_length() + 8) // 8, 'big')
+ sb = s.to_bytes((s.bit_length() + 8) // 8, 'big')
+ return b'\x30' + bytes([4 + len(rb) + len(sb), 2, len(rb)]) + rb + bytes([2, len(sb)]) + sb
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 4bd58519c5..e454ed5987 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2018 The Bitcoin Core developers
+# Copyright (c) 2010-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.
"""Bitcoin test framework primitive and message structures
@@ -28,7 +28,7 @@ import struct
import time
from test_framework.siphash import siphash256
-from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, assert_equal
+from test_framework.util import hex_str_to_bytes, assert_equal
MIN_VERSION_SUPPORTED = 60001
MY_VERSION = 70014 # past bip-31 for ping/pong
@@ -181,7 +181,7 @@ def FromHex(obj, hex_string):
# Convert a binary-serializable object to hex (eg for submission via RPC)
def ToHex(obj):
- return bytes_to_hex_str(obj.serialize())
+ return obj.serialize().hex()
# Objects that map to bitcoind objects, which can be serialized/deserialized
@@ -319,7 +319,7 @@ class CTxIn:
def __repr__(self):
return "CTxIn(prevout=%s scriptSig=%s nSequence=%i)" \
- % (repr(self.prevout), bytes_to_hex_str(self.scriptSig),
+ % (repr(self.prevout), self.scriptSig.hex(),
self.nSequence)
@@ -343,7 +343,7 @@ class CTxOut:
def __repr__(self):
return "CTxOut(nValue=%i.%08i scriptPubKey=%s)" \
% (self.nValue // COIN, self.nValue % COIN,
- bytes_to_hex_str(self.scriptPubKey))
+ self.scriptPubKey.hex())
class CScriptWitness:
@@ -355,7 +355,7 @@ class CScriptWitness:
def __repr__(self):
return "CScriptWitness(%s)" % \
- (",".join([bytes_to_hex_str(x) for x in self.stack]))
+ (",".join([x.hex() for x in self.stack]))
def is_null(self):
if self.stack:
@@ -605,7 +605,7 @@ class CBlock(CBlockHeader):
super(CBlock, self).deserialize(f)
self.vtx = deser_vector(f, CTransaction)
- def serialize(self, with_witness=False):
+ def serialize(self, with_witness=True):
r = b""
r += super(CBlock, self).serialize()
if with_witness:
@@ -1130,7 +1130,7 @@ class msg_block:
self.block.deserialize(f)
def serialize(self):
- return self.block.serialize(with_witness=False)
+ return self.block.serialize()
def __repr__(self):
return "msg_block(block=%s)" % (repr(self.block))
@@ -1152,11 +1152,10 @@ class msg_generic:
return "msg_generic()"
-class msg_witness_block(msg_block):
+class msg_no_witness_block(msg_block):
__slots__ = ()
def serialize(self):
- r = self.block.serialize(with_witness=True)
- return r
+ return self.block.serialize(with_witness=False)
class msg_getaddr:
@@ -1442,17 +1441,15 @@ class msg_blocktxn:
def serialize(self):
r = b""
- r += self.block_transactions.serialize(with_witness=False)
+ r += self.block_transactions.serialize()
return r
def __repr__(self):
return "msg_blocktxn(block_transactions=%s)" % (repr(self.block_transactions))
-class msg_witness_blocktxn(msg_blocktxn):
+class msg_no_witness_blocktxn(msg_blocktxn):
__slots__ = ()
def serialize(self):
- r = b""
- r += self.block_transactions.serialize(with_witness=True)
- return r
+ return self.block_transactions.serialize(with_witness=False)
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index ac7cc068bd..cc3a4cc72a 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Copyright (c) 2010 ArtForz -- public domain half-a-node
# Copyright (c) 2012 Jeff Garzik
-# Copyright (c) 2010-2018 The Bitcoin Core developers
+# Copyright (c) 2010-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.
"""Bitcoin P2P network half-a-node.
@@ -171,7 +171,7 @@ class P2PConnection(asyncio.Protocol):
if len(self.recvbuf) < 4:
return
if self.recvbuf[:4] != self.magic_bytes:
- raise ValueError("got garbage %s" % repr(self.recvbuf))
+ raise ValueError("magic bytes mismatch: {} != {}".format(repr(self.magic_bytes), repr(self.recvbuf)))
if len(self.recvbuf) < 4 + 12 + 4 + 4:
return
command = self.recvbuf[4:4+12].split(b"\x00", 1)[0]
@@ -218,10 +218,7 @@ class P2PConnection(asyncio.Protocol):
def maybe_write():
if not self._transport:
return
- # Python <3.4.4 does not have is_closing, so we have to check for
- # its existence explicitly as long as Bitcoin Core supports all
- # Python 3.4 versions.
- if hasattr(self._transport, 'is_closing') and self._transport.is_closing():
+ if self._transport.is_closing():
return
self._transport.write(raw_message_bytes)
NetworkThread.network_event_loop.call_soon_threadsafe(maybe_write)
@@ -364,6 +361,14 @@ class P2PInterface(P2PConnection):
# Message receiving helper methods
+ def wait_for_tx(self, txid, timeout=60):
+ def test_function():
+ if not self.last_message.get('tx'):
+ return False
+ return self.last_message['tx'].tx.rehash() == txid
+
+ wait_until(test_function, timeout=timeout, lock=mininode_lock)
+
def wait_for_block(self, blockhash, timeout=60):
test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
wait_until(test_function, timeout=timeout, lock=mininode_lock)
@@ -534,7 +539,7 @@ class P2PDataStore(P2PInterface):
for b in blocks:
self.send_message(msg_block(block=b))
else:
- self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
+ self.send_message(msg_headers([CBlockHeader(block) for block in blocks]))
wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
if expect_disconnect:
diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py
index 45c182f630..c98424e8e2 100644
--- a/test/functional/test_framework/netutil.py
+++ b/test/functional/test_framework/netutil.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Linux network utilities.
@@ -12,7 +12,7 @@ import socket
import struct
import array
import os
-from binascii import unhexlify, hexlify
+from binascii import unhexlify
# STATE_ESTABLISHED = '01'
# STATE_SYN_SENT = '02'
@@ -129,17 +129,17 @@ def addr_to_hex(addr):
if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end
continue
x += 1 # :: skips to suffix
- assert(x < 2)
+ assert x < 2
else: # two bytes per component
val = int(comp, 16)
sub[x].append(val >> 8)
sub[x].append(val & 0xff)
nullbytes = 16 - len(sub[0]) - len(sub[1])
- assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0))
+ assert (x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)
addr = sub[0] + ([0] * nullbytes) + sub[1]
else:
raise ValueError('Could not parse address %s' % addr)
- return hexlify(bytearray(addr)).decode('ascii')
+ return bytearray(addr).hex()
def test_ipv6_local():
'''
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 012c80a1be..384062b808 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Functionality to build scripts, as well as SignatureHash().
@@ -9,7 +9,6 @@ This file is modified from python-bitcoinlib.
from .messages import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string
-from binascii import hexlify
import hashlib
import struct
@@ -450,10 +449,6 @@ class CScript(bytes):
# join makes no sense for a CScript()
raise NotImplementedError
- # Python 3.4 compatibility
- def hex(self):
- return hexlify(self).decode('ascii')
-
def __new__(cls, value=b''):
if isinstance(value, bytes) or isinstance(value, bytearray):
return super(CScript, cls).__new__(cls, value)
@@ -545,7 +540,7 @@ class CScript(bytes):
def __repr__(self):
def _repr(o):
if isinstance(o, bytes):
- return "x('%s')" % hexlify(o).decode('ascii')
+ return "x('%s')" % o.hex()
else:
return repr(o)
diff --git a/test/functional/test_framework/socks5.py b/test/functional/test_framework/socks5.py
index a21c864e75..799b1c74b8 100644
--- a/test/functional/test_framework/socks5.py
+++ b/test/functional/test_framework/socks5.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Dummy Socks5 server for testing."""
@@ -144,7 +144,7 @@ class Socks5Server():
thread.start()
def start(self):
- assert(not self.running)
+ assert not self.running
self.running = True
self.thread = threading.Thread(None, self.run)
self.thread.daemon = True
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 09d7d877a7..aa674f9ebe 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-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Base class for RPC testing."""
@@ -10,6 +10,7 @@ import logging
import argparse
import os
import pdb
+import random
import shutil
import sys
import tempfile
@@ -28,7 +29,6 @@ from .util import (
disconnect_nodes,
get_datadir_path,
initialize_datadir,
- p2p_port,
sync_blocks,
sync_mempools,
)
@@ -129,6 +129,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
help="use bitcoin-cli instead of RPC for all commands")
parser.add_argument("--perf", dest="perf", default=False, action="store_true",
help="profile running nodes with perf for the duration of the test")
+ parser.add_argument("--randomseed", type=int,
+ help="set a random seed for deterministically reproducing a previous test run")
self.add_options(parser)
self.options = parser.parse_args()
@@ -158,6 +160,22 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.options.tmpdir = tempfile.mkdtemp(prefix=TMPDIR_PREFIX)
self._start_logging()
+ # Seed the PRNG. Note that test runs are reproducible if and only if
+ # a single thread accesses the PRNG. For more information, see
+ # https://docs.python.org/3/library/random.html#notes-on-reproducibility.
+ # The network thread shouldn't access random. If we need to change the
+ # network thread to access randomness, it should instantiate its own
+ # random.Random object.
+ seed = self.options.randomseed
+
+ if seed is None:
+ seed = random.randrange(sys.maxsize)
+ else:
+ self.log.debug("User supplied random seed {}".format(seed))
+
+ random.seed(seed)
+ self.log.debug("PRNG seed is: {}".format(seed))
+
self.log.debug('Setting up network thread')
self.network_thread = NetworkThread()
self.network_thread.start()
@@ -396,7 +414,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
"""
disconnect_nodes(self.nodes[1], 2)
disconnect_nodes(self.nodes[2], 1)
- self.sync_all([self.nodes[:2], self.nodes[2:]])
+ self.sync_all(self.nodes[:2])
+ self.sync_all(self.nodes[2:])
def join_network(self):
"""
@@ -405,13 +424,15 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
connect_nodes_bi(self.nodes, 1, 2)
self.sync_all()
- def sync_all(self, node_groups=None):
- if not node_groups:
- node_groups = [self.nodes]
+ def sync_blocks(self, nodes=None, **kwargs):
+ sync_blocks(nodes or self.nodes, **kwargs)
+
+ def sync_mempools(self, nodes=None, **kwargs):
+ sync_mempools(nodes or self.nodes, **kwargs)
- for group in node_groups:
- sync_blocks(group)
- sync_mempools(group)
+ def sync_all(self, nodes=None, **kwargs):
+ self.sync_blocks(nodes, **kwargs)
+ self.sync_mempools(nodes, **kwargs)
# Private helper methods. These should not be accessed by the subclass test scripts.
@@ -446,35 +467,23 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def _initialize_chain(self):
"""Initialize a pre-mined blockchain for use by the test.
- Create a cache of a 199-block-long chain (with wallet) for MAX_NODES
+ Create a cache of a 199-block-long chain
Afterward, create num_nodes copies from the cache."""
+ CACHE_NODE_ID = 0 # Use node 0 to create the cache for all other nodes
+ cache_node_dir = get_datadir_path(self.options.cachedir, CACHE_NODE_ID)
assert self.num_nodes <= MAX_NODES
- create_cache = False
- for i in range(MAX_NODES):
- if not os.path.isdir(get_datadir_path(self.options.cachedir, i)):
- create_cache = True
- break
-
- if create_cache:
- self.log.debug("Creating data directories from cached datadir")
-
- # find and delete old cache directories if any exist
- for i in range(MAX_NODES):
- if os.path.isdir(get_datadir_path(self.options.cachedir, i)):
- shutil.rmtree(get_datadir_path(self.options.cachedir, i))
-
- # Create cache directories, run bitcoinds:
- for i in range(MAX_NODES):
- datadir = initialize_datadir(self.options.cachedir, i)
- args = [self.options.bitcoind, "-datadir=" + datadir, '-disablewallet']
- if i > 0:
- args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
- self.nodes.append(TestNode(
- i,
- get_datadir_path(self.options.cachedir, i),
+
+ if not os.path.isdir(cache_node_dir):
+ self.log.debug("Creating cache directory {}".format(cache_node_dir))
+
+ initialize_datadir(self.options.cachedir, CACHE_NODE_ID)
+ self.nodes.append(
+ TestNode(
+ CACHE_NODE_ID,
+ cache_node_dir,
extra_conf=["bind=127.0.0.1"],
- extra_args=[],
+ extra_args=['-disablewallet'],
rpchost=None,
timewait=self.rpc_timeout,
bitcoind=self.options.bitcoind,
@@ -482,12 +491,10 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
coverage_dir=None,
cwd=self.options.tmpdir,
))
- self.nodes[i].args = args
- self.start_node(i)
+ self.start_node(CACHE_NODE_ID)
# Wait for RPC connections to be ready
- for node in self.nodes:
- node.wait_for_rpc_connection()
+ self.nodes[CACHE_NODE_ID].wait_for_rpc_connection()
# Create a 199-block-long chain; each of the 4 first nodes
# gets 25 mature blocks and 25 immature.
@@ -496,29 +503,29 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# This is needed so that we are out of IBD when the test starts,
# see the tip age check in IsInitialBlockDownload().
for i in range(8):
- self.nodes[0].generatetoaddress(25 if i != 7 else 24, self.nodes[i % 4].get_deterministic_priv_key().address)
- sync_blocks(self.nodes)
+ self.nodes[CACHE_NODE_ID].generatetoaddress(
+ nblocks=25 if i != 7 else 24,
+ address=TestNode.PRIV_KEYS[i % 4].address,
+ )
- for n in self.nodes:
- assert_equal(n.getblockchaininfo()["blocks"], 199)
+ assert_equal(self.nodes[CACHE_NODE_ID].getblockchaininfo()["blocks"], 199)
- # Shut them down, and clean up cache directories:
+ # Shut it down, and clean up cache directories:
self.stop_nodes()
self.nodes = []
- def cache_path(n, *paths):
- return os.path.join(get_datadir_path(self.options.cachedir, n), "regtest", *paths)
+ def cache_path(*paths):
+ return os.path.join(cache_node_dir, "regtest", *paths)
- for i in range(MAX_NODES):
- os.rmdir(cache_path(i, 'wallets')) # Remove empty wallets dir
- for entry in os.listdir(cache_path(i)):
- if entry not in ['chainstate', 'blocks']:
- os.remove(cache_path(i, entry))
+ os.rmdir(cache_path('wallets')) # Remove empty wallets dir
+ for entry in os.listdir(cache_path()):
+ if entry not in ['chainstate', 'blocks']: # Only keep chainstate and blocks folder
+ os.remove(cache_path(entry))
for i in range(self.num_nodes):
- from_dir = get_datadir_path(self.options.cachedir, i)
+ self.log.debug("Copy cache directory {} to node {}".format(cache_node_dir, i))
to_dir = get_datadir_path(self.options.tmpdir, i)
- shutil.copytree(from_dir, to_dir)
+ shutil.copytree(cache_node_dir, to_dir)
initialize_datadir(self.options.tmpdir, i) # Overwrite port/rpcport in bitcoin.conf
def _initialize_chain_clean(self):
@@ -553,21 +560,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def is_cli_compiled(self):
"""Checks whether bitcoin-cli was compiled."""
- config = configparser.ConfigParser()
- config.read_file(open(self.options.configfile))
-
- return config["components"].getboolean("ENABLE_CLI")
+ return self.config["components"].getboolean("ENABLE_CLI")
def is_wallet_compiled(self):
"""Checks whether the wallet module was compiled."""
- config = configparser.ConfigParser()
- config.read_file(open(self.options.configfile))
-
- return config["components"].getboolean("ENABLE_WALLET")
+ return self.config["components"].getboolean("ENABLE_WALLET")
def is_zmq_compiled(self):
"""Checks whether the zmq module was compiled."""
- config = configparser.ConfigParser()
- config.read_file(open(self.options.configfile))
-
- return config["components"].getboolean("ENABLE_ZMQ")
+ return self.config["components"].getboolean("ENABLE_ZMQ")
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 37fd2a8744..3311377090 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Class for bitcoind node under test"""
@@ -23,6 +23,7 @@ import sys
from .authproxy import JSONRPCException
from .util import (
+ MAX_NODES,
append_config,
delete_cookie_file,
get_rpc_proxy,
@@ -31,9 +32,6 @@ from .util import (
p2p_port,
)
-# For Python 3.4 compatibility
-JSONDecodeError = getattr(json, "JSONDecodeError", ValueError)
-
BITCOIND_PROC_WAIT_TIMEOUT = 60
@@ -83,10 +81,14 @@ class TestNode():
# For those callers that need more flexibility, they can just set the args property directly.
# Note that common args are set in the config file (see initialize_datadir)
self.extra_args = extra_args
+ # Configuration for logging is set as command-line args rather than in the bitcoin.conf file.
+ # This means that starting a bitcoind using the temp dir to debug a failed test won't
+ # spam debug.log.
self.args = [
self.binary,
"-datadir=" + self.datadir,
"-logtimemicros",
+ "-logthreadnames",
"-debug",
"-debugexclude=libevent",
"-debugexclude=leveldb",
@@ -109,10 +111,8 @@ class TestNode():
self.p2ps = []
- def get_deterministic_priv_key(self):
- """Return a deterministic priv key in base58, that only depends on the node's index"""
- AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
- PRIV_KEYS = [
+ AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
+ PRIV_KEYS = [
# address , privkey
AddressKeyPair('mjTkW3DjgyZck4KbiRusZsqTgaYTxdSz6z', 'cVpF924EspNh8KjYsfhgY96mmxvT6DgdWiTYMtMjuM74hJaU5psW'),
AddressKeyPair('msX6jQXvxiNhx3Q62PKeLPrhrqZQdSimTg', 'cUxsWyKyZ9MAQTaAhUQWJmBbSvHMwSmuv59KgxQV7oZQU3PXN3KE'),
@@ -123,8 +123,15 @@ class TestNode():
AddressKeyPair('myzuPxRwsf3vvGzEuzPfK9Nf2RfwauwYe6', 'cQMpDLJwA8DBe9NcQbdoSb1BhmFxVjWD5gRyrLZCtpuF9Zi3a9RK'),
AddressKeyPair('mumwTaMtbxEPUswmLBBN3vM9oGRtGBrys8', 'cSXmRKXVcoouhNNVpcNKFfxsTsToY5pvB9DVsFksF1ENunTzRKsy'),
AddressKeyPair('mpV7aGShMkJCZgbW7F6iZgrvuPHjZjH9qg', 'cSoXt6tm3pqy43UMabY6eUTmR3eSUYFtB2iNQDGgb3VUnRsQys2k'),
- ]
- return PRIV_KEYS[self.index]
+ AddressKeyPair('mq4fBNdckGtvY2mijd9am7DRsbRB4KjUkf', 'cN55daf1HotwBAgAKWVgDcoppmUNDtQSfb7XLutTLeAgVc3u8hik'),
+ AddressKeyPair('mpFAHDjX7KregM3rVotdXzQmkbwtbQEnZ6', 'cT7qK7g1wkYEMvKowd2ZrX1E5f6JQ7TM246UfqbCiyF7kZhorpX3'),
+ AddressKeyPair('mzRe8QZMfGi58KyWCse2exxEFry2sfF2Y7', 'cPiRWE8KMjTRxH1MWkPerhfoHFn5iHPWVK5aPqjW8NxmdwenFinJ'),
+ ]
+
+ def get_deterministic_priv_key(self):
+ """Return a deterministic priv key in base58, that only depends on the node's index"""
+ assert len(self.PRIV_KEYS) == MAX_NODES
+ return self.PRIV_KEYS[self.index]
def get_mem_rss_kilobytes(self):
"""Get the memory usage (RSS) per `ps`.
@@ -372,7 +379,7 @@ class TestNode():
stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) == 0
if not sys.platform.startswith('linux'):
- self.log.warning("Can't profile with perf; only availabe on Linux platforms")
+ self.log.warning("Can't profile with perf; only available on Linux platforms")
return None
if not test_success('which perf'):
@@ -565,5 +572,5 @@ class TestNodeCLI():
raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr)
try:
return json.loads(cli_stdout, parse_float=decimal.Decimal)
- except JSONDecodeError:
+ except json.JSONDecodeError:
return cli_stdout.rstrip("\n")
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index fef9982412..26215083fb 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Helpful routines for regression testing."""
from base64 import b64encode
-from binascii import hexlify, unhexlify
+from binascii import unhexlify
from decimal import Decimal, ROUND_DOWN
import hashlib
import inspect
@@ -182,9 +182,6 @@ def check_json_precision():
def count_bytes(hex_string):
return len(bytearray.fromhex(hex_string))
-def bytes_to_hex_str(byte_str):
- return hexlify(byte_str).decode('ascii')
-
def hash256(byte_str):
sha256 = hashlib.sha256()
sha256.update(byte_str)
@@ -219,7 +216,7 @@ def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=N
time.sleep(0.05)
# Print the cause of the timeout
- predicate_source = inspect.getsourcelines(predicate)
+ predicate_source = "''''\n" + inspect.getsource(predicate) + "'''"
logger.error("wait_until() failed. Predicate: {}".format(predicate_source))
if attempt >= attempts:
raise AssertionError("Predicate {} not true after {} attempts".format(predicate_source, attempts))
@@ -231,7 +228,7 @@ def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=N
############################################
# The maximum number of nodes a single test can spawn
-MAX_NODES = 8
+MAX_NODES = 12
# Don't assign rpc or p2p ports lower than this
PORT_MIN = 11000
# The number of ports to "reserve" for p2p and rpc, each
@@ -267,7 +264,7 @@ def get_rpc_proxy(url, node_number, timeout=None, coveragedir=None):
return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile)
def p2p_port(n):
- assert(n <= MAX_NODES)
+ assert n <= MAX_NODES
return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
def rpc_port(n):
@@ -326,12 +323,14 @@ def get_auth_cookie(datadir):
if line.startswith("rpcpassword="):
assert password is None # Ensure that there is only one rpcpassword line
password = line.split("=")[1].strip("\n")
- if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")) and os.access(os.path.join(datadir, "regtest", ".cookie"), os.R_OK):
+ try:
with open(os.path.join(datadir, "regtest", ".cookie"), 'r', encoding="ascii") as f:
userpass = f.read()
split_userpass = userpass.split(':')
user = split_userpass[0]
password = split_userpass[1]
+ except OSError:
+ pass
if user is None or password is None:
raise ValueError("No RPC credentials")
return user, password
@@ -425,7 +424,7 @@ def gather_inputs(from_node, amount_needed, confirmations_required=1):
"""
Return a random set of unspent txouts that are enough to pay amount_needed
"""
- assert(confirmations_required >= 0)
+ assert confirmations_required >= 0
utxo = from_node.listunspent(confirmations_required)
random.shuffle(utxo)
inputs = []
@@ -470,7 +469,7 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
rawtx = from_node.createrawtransaction(inputs, outputs)
signresult = from_node.signrawtransactionwithwallet(rawtx)
- txid = from_node.sendrawtransaction(signresult["hex"], True)
+ txid = from_node.sendrawtransaction(signresult["hex"], 0)
return (txid, signresult["hex"], fee)
@@ -503,7 +502,7 @@ def create_confirmed_utxos(fee, node, count):
node.generate(1)
utxos = node.listunspent()
- assert(len(utxos) >= count)
+ assert len(utxos) >= count
return utxos
# Create large OP_RETURN txouts that can be appended to a transaction
@@ -542,7 +541,7 @@ def create_lots_of_big_transactions(node, txouts, utxos, num, fee):
newtx = newtx + txouts
newtx = newtx + rawtx[94:]
signresult = node.signrawtransactionwithwallet(newtx, None, "NONE")
- txid = node.sendrawtransaction(signresult["hex"], True)
+ txid = node.sendrawtransaction(signresult["hex"], 0)
txids.append(txid)
return txids
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index bb9ac58e46..462547f44f 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Run regression test suite.
@@ -66,8 +66,15 @@ if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393):
TEST_EXIT_PASSED = 0
TEST_EXIT_SKIPPED = 77
+EXTENDED_SCRIPTS = [
+ # These tests are not run by default.
+ # Longest test should go first, to favor running tests in parallel
+ 'feature_pruning.py',
+ 'feature_dbcrash.py',
+]
+
BASE_SCRIPTS = [
- # Scripts that are run by the travis build process.
+ # Scripts that are run by default.
# Longest test should go first, to favor running tests in parallel
'feature_fee_estimation.py',
'wallet_hd.py',
@@ -113,6 +120,7 @@ BASE_SCRIPTS = [
'rpc_misc.py',
'interface_rest.py',
'mempool_spend_coinbase.py',
+ 'wallet_avoidreuse.py',
'mempool_reorg.py',
'mempool_persist.py',
'wallet_multiwallet.py',
@@ -134,6 +142,7 @@ BASE_SCRIPTS = [
'rpc_net.py',
'wallet_keypool.py',
'p2p_mempool.py',
+ 'p2p_blocksonly.py',
'mining_prioritisetransaction.py',
'p2p_invalid_locator.py',
'p2p_invalid_block.py',
@@ -144,6 +153,7 @@ BASE_SCRIPTS = [
'wallet_txn_doublespend.py',
'wallet_txn_clone.py --mineblock',
'feature_notifications.py',
+ 'rpc_getblockfilter.py',
'rpc_invalidateblock.py',
'feature_rbf.py',
'mempool_packages.py',
@@ -195,13 +205,6 @@ BASE_SCRIPTS = [
# Put them in a random line within the section that fits their approximate run-time
]
-EXTENDED_SCRIPTS = [
- # These tests are not run by the travis build process.
- # Longest test should go first, to favor running tests in parallel
- 'feature_pruning.py',
- 'feature_dbcrash.py',
-]
-
# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests
ALL_SCRIPTS = EXTENDED_SCRIPTS + BASE_SCRIPTS
@@ -400,16 +403,18 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
print_results(test_results, max_len_name, (int(time.time() - start_time)))
if coverage:
- coverage.report_rpc_coverage()
+ coverage_passed = coverage.report_rpc_coverage()
logging.debug("Cleaning up coverage data")
coverage.cleanup()
+ else:
+ coverage_passed = True
# Clear up the temp directory if all subdirectories are gone
if not os.listdir(tmpdir):
os.rmdir(tmpdir)
- all_passed = all(map(lambda test_result: test_result.was_successful, test_results))
+ all_passed = all(map(lambda test_result: test_result.was_successful, test_results)) and coverage_passed
# This will be a no-op unless failfast is True in which case there may be dangling
# processes which need to be killed.
@@ -478,6 +483,11 @@ class TestHandler:
log_stderr))
if not self.jobs:
raise IndexError('pop from empty list')
+
+ # Print remaining running jobs when all jobs have been started.
+ if not self.test_list:
+ print("Remaining jobs: [{}]".format(", ".join(j[0] for j in self.jobs)))
+
dot_count = 0
while True:
# Return first proc that finishes
@@ -485,7 +495,8 @@ class TestHandler:
for job in self.jobs:
(name, start_time, proc, testdir, log_out, log_err) = job
if int(time.time() - start_time) > self.timeout_duration:
- # In travis, timeout individual tests (to stop tests hanging and not providing useful output).
+ # Timeout individual tests if timeout is specified (to stop
+ # tests hanging and not providing useful output).
proc.send_signal(signal.SIGINT)
if proc.poll() is not None:
log_out.seek(0), log_err.seek(0)
@@ -573,7 +584,7 @@ def check_script_list(*, src_dir, fail_on_warn):
if len(missed_tests) != 0:
print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests)))
if fail_on_warn:
- # On travis this warning is an error to prevent merging incomplete commits into master
+ # On CI this warning is an error to prevent merging incomplete commits into master
sys.exit(1)
@@ -606,8 +617,10 @@ class RPCCoverage():
if uncovered:
print("Uncovered RPC commands:")
print("".join((" - %s\n" % command) for command in sorted(uncovered)))
+ return False
else:
print("All RPC commands covered.")
+ return True
def cleanup(self):
return shutil.rmtree(self.dir)
diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py
index b0b151d2d6..e86679bc31 100755
--- a/test/functional/wallet_abandonconflict.py
+++ b/test/functional/wallet_abandonconflict.py
@@ -18,8 +18,6 @@ from test_framework.util import (
assert_raises_rpc_error,
connect_nodes,
disconnect_nodes,
- sync_blocks,
- sync_mempools,
)
@@ -33,12 +31,12 @@ class AbandonConflictTest(BitcoinTestFramework):
def run_test(self):
self.nodes[1].generate(100)
- sync_blocks(self.nodes)
+ self.sync_blocks()
balance = self.nodes[0].getbalance()
txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10"))
- sync_mempools(self.nodes)
+ self.sync_mempools()
self.nodes[1].generate(1)
# Can not abandon non-wallet transaction
@@ -46,7 +44,7 @@ class AbandonConflictTest(BitcoinTestFramework):
# Can not abandon confirmed transaction
assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: self.nodes[0].abandontransaction(txid=txA))
- sync_blocks(self.nodes)
+ self.sync_blocks()
newbalance = self.nodes[0].getbalance()
assert balance - newbalance < Decimal("0.001") #no more than fees lost
balance = newbalance
@@ -163,7 +161,7 @@ class AbandonConflictTest(BitcoinTestFramework):
self.nodes[1].generate(1)
connect_nodes(self.nodes[0], 1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted
newbalance = self.nodes[0].getbalance()
diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py
index 380dd9c0ad..a40613dfc7 100755
--- a/test/functional/wallet_address_types.py
+++ b/test/functional/wallet_address_types.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test that the wallet can send and receive using all combinations of address types.
@@ -63,8 +63,6 @@ from test_framework.util import (
assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
- sync_blocks,
- sync_mempools,
)
@@ -102,62 +100,62 @@ class AddressTypeTest(BitcoinTestFramework):
def test_address(self, node, address, multisig, typ):
"""Run sanity checks on an address."""
info = self.nodes[node].getaddressinfo(address)
- assert(self.nodes[node].validateaddress(address)['isvalid'])
+ assert self.nodes[node].validateaddress(address)['isvalid']
assert_equal(info.get('solvable'), True)
if not multisig and typ == 'legacy':
# P2PKH
- assert(not info['isscript'])
- assert(not info['iswitness'])
- assert('pubkey' in info)
+ assert not info['isscript']
+ assert not info['iswitness']
+ assert 'pubkey' in info
elif not multisig and typ == 'p2sh-segwit':
# P2SH-P2WPKH
- assert(info['isscript'])
- assert(not info['iswitness'])
+ assert info['isscript']
+ assert not info['iswitness']
assert_equal(info['script'], 'witness_v0_keyhash')
- assert('pubkey' in info)
+ assert 'pubkey' in info
elif not multisig and typ == 'bech32':
# P2WPKH
- assert(not info['isscript'])
- assert(info['iswitness'])
+ assert not info['isscript']
+ assert info['iswitness']
assert_equal(info['witness_version'], 0)
assert_equal(len(info['witness_program']), 40)
- assert('pubkey' in info)
+ assert 'pubkey' in info
elif typ == 'legacy':
# P2SH-multisig
- assert(info['isscript'])
+ assert info['isscript']
assert_equal(info['script'], 'multisig')
- assert(not info['iswitness'])
- assert('pubkeys' in info)
+ assert not info['iswitness']
+ assert 'pubkeys' in info
elif typ == 'p2sh-segwit':
# P2SH-P2WSH-multisig
- assert(info['isscript'])
+ assert info['isscript']
assert_equal(info['script'], 'witness_v0_scripthash')
- assert(not info['iswitness'])
- assert(info['embedded']['isscript'])
+ assert not info['iswitness']
+ assert info['embedded']['isscript']
assert_equal(info['embedded']['script'], 'multisig')
- assert(info['embedded']['iswitness'])
+ assert info['embedded']['iswitness']
assert_equal(info['embedded']['witness_version'], 0)
assert_equal(len(info['embedded']['witness_program']), 64)
- assert('pubkeys' in info['embedded'])
+ assert 'pubkeys' in info['embedded']
elif typ == 'bech32':
# P2WSH-multisig
- assert(info['isscript'])
+ assert info['isscript']
assert_equal(info['script'], 'multisig')
- assert(info['iswitness'])
+ assert info['iswitness']
assert_equal(info['witness_version'], 0)
assert_equal(len(info['witness_program']), 64)
- assert('pubkeys' in info)
+ assert 'pubkeys' in info
else:
# Unknown type
- assert(False)
+ assert False
def test_desc(self, node, address, multisig, typ, utxo):
"""Run sanity checks on a descriptor reported by getaddressinfo."""
info = self.nodes[node].getaddressinfo(address)
- assert('desc' in info)
+ assert 'desc' in info
assert_equal(info['desc'], utxo['desc'])
- assert(self.nodes[node].validateaddress(address)['isvalid'])
+ assert self.nodes[node].validateaddress(address)['isvalid']
# Use a ridiculously roundabout way to find the key origin info through
# the PSBT logic. However, this does test consistency between the PSBT reported
@@ -172,11 +170,11 @@ class AddressTypeTest(BitcoinTestFramework):
key_descs[deriv['pubkey']] = '[' + deriv['master_fingerprint'] + deriv['path'][1:] + ']' + deriv['pubkey']
# Verify the descriptor checksum against the Python implementation
- assert(descsum_check(info['desc']))
+ assert descsum_check(info['desc'])
# Verify that stripping the checksum and recreating it using Python roundtrips
- assert(info['desc'] == descsum_create(info['desc'][:-9]))
+ assert info['desc'] == descsum_create(info['desc'][:-9])
# Verify that stripping the checksum and feeding it to getdescriptorinfo roundtrips
- assert(info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'][:-9])['descriptor'])
+ assert info['desc'] == self.nodes[0].getdescriptorinfo(info['desc'][:-9])['descriptor']
if not multisig and typ == 'legacy':
# P2PKH
@@ -198,7 +196,7 @@ class AddressTypeTest(BitcoinTestFramework):
assert_equal(info['desc'], descsum_create("wsh(multi(2,%s,%s))" % (key_descs[info['pubkeys'][0]], key_descs[info['pubkeys'][1]])))
else:
# Unknown type
- assert(False)
+ assert False
def test_change_output_type(self, node_sender, destinations, expected_type):
txid = self.nodes[node_sender].sendmany(dummy="", amounts=dict.fromkeys(destinations, 0.001))
@@ -220,7 +218,7 @@ class AddressTypeTest(BitcoinTestFramework):
# Mine 101 blocks on node5 to bring nodes out of IBD and make sure that
# no coinbases are maturing for the nodes-under-test during the test
self.nodes[5].generate(101)
- sync_blocks(self.nodes)
+ self.sync_blocks()
uncompressed_1 = "0496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858ee"
uncompressed_2 = "047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77"
@@ -287,7 +285,7 @@ class AddressTypeTest(BitcoinTestFramework):
self.log.debug("Sending: {}".format(sends))
self.nodes[from_node].sendmany("", sends)
- sync_mempools(self.nodes)
+ self.sync_mempools()
unconf_balances = self.get_balances(False)
self.log.debug("Check unconfirmed balances: {}".format(unconf_balances))
@@ -298,7 +296,7 @@ class AddressTypeTest(BitcoinTestFramework):
# node5 collects fee and block subsidy to keep accounting simple
self.nodes[5].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Verify that the receiving wallet contains a UTXO with the expected address, and expected descriptor
for n, to_node in enumerate(range(from_node, from_node + 4)):
@@ -328,7 +326,7 @@ class AddressTypeTest(BitcoinTestFramework):
# Fund node 4:
self.nodes[5].sendtoaddress(self.nodes[4].getnewaddress(), Decimal("1"))
self.nodes[5].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(self.nodes[4].getbalance(), 1)
self.log.info("Nodes with addresstype=legacy never use a P2WPKH change output")
diff --git a/test/functional/wallet_avoidreuse.py b/test/functional/wallet_avoidreuse.py
new file mode 100755
index 0000000000..58ad835d39
--- /dev/null
+++ b/test/functional/wallet_avoidreuse.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018 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 avoid_reuse and setwalletflag features."""
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ connect_nodes_bi,
+)
+
+# TODO: Copied from wallet_groups.py -- should perhaps move into util.py
+def assert_approx(v, vexp, vspan=0.00001):
+ if v < vexp - vspan:
+ raise AssertionError("%s < [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
+ if v > vexp + vspan:
+ raise AssertionError("%s > [%s..%s]" % (str(v), str(vexp - vspan), str(vexp + vspan)))
+
+def reset_balance(node, discardaddr):
+ '''Throw away all owned coins by the node so it gets a balance of 0.'''
+ balance = node.getbalance(avoid_reuse=False)
+ if balance > 0.5:
+ node.sendtoaddress(address=discardaddr, amount=balance, subtractfeefromamount=True, avoid_reuse=False)
+
+def count_unspent(node):
+ '''Count the unspent outputs for the given node and return various statistics'''
+ r = {
+ "total": {
+ "count": 0,
+ "sum": 0,
+ },
+ "reused": {
+ "count": 0,
+ "sum": 0,
+ },
+ }
+ supports_reused = True
+ for utxo in node.listunspent(minconf=0):
+ r["total"]["count"] += 1
+ r["total"]["sum"] += utxo["amount"]
+ if supports_reused and "reused" in utxo:
+ if utxo["reused"]:
+ r["reused"]["count"] += 1
+ r["reused"]["sum"] += utxo["amount"]
+ else:
+ supports_reused = False
+ r["reused"]["supported"] = supports_reused
+ return r
+
+def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None, reused_count=None, reused_sum=None):
+ '''Make assertions about a node's unspent output statistics'''
+ stats = count_unspent(node)
+ if total_count is not None:
+ assert_equal(stats["total"]["count"], total_count)
+ if total_sum is not None:
+ assert_approx(stats["total"]["sum"], total_sum, 0.001)
+ if reused_supported is not None:
+ assert_equal(stats["reused"]["supported"], reused_supported)
+ if reused_count is not None:
+ assert_equal(stats["reused"]["count"], reused_count)
+ if reused_sum is not None:
+ assert_approx(stats["reused"]["sum"], reused_sum, 0.001)
+
+def assert_balances(node, mine):
+ '''Make assertions about a node's getbalances output'''
+ got = node.getbalances()["mine"]
+ for k,v in mine.items():
+ assert_approx(got[k], v, 0.001)
+
+class AvoidReuseTest(BitcoinTestFramework):
+
+ def set_test_params(self):
+ self.setup_clean_chain = False
+ self.num_nodes = 2
+
+ def skip_test_if_missing_module(self):
+ self.skip_if_no_wallet()
+
+ def run_test(self):
+ '''Set up initial chain and run tests defined below'''
+
+ self.test_persistence()
+ self.test_immutable()
+
+ self.nodes[0].generate(110)
+ self.sync_all()
+ reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
+ self.test_fund_send_fund_senddirty()
+ reset_balance(self.nodes[1], self.nodes[0].getnewaddress())
+ self.test_fund_send_fund_send()
+
+ def test_persistence(self):
+ '''Test that wallet files persist the avoid_reuse flag.'''
+ # Configure node 1 to use avoid_reuse
+ self.nodes[1].setwalletflag('avoid_reuse')
+
+ # Flags should be node1.avoid_reuse=false, node2.avoid_reuse=true
+ assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False)
+ assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True)
+
+ # Stop and restart node 1
+ self.stop_node(1)
+ self.start_node(1)
+ connect_nodes_bi(self.nodes, 0, 1)
+
+ # Flags should still be node1.avoid_reuse=false, node2.avoid_reuse=true
+ assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False)
+ assert_equal(self.nodes[1].getwalletinfo()["avoid_reuse"], True)
+
+ # Attempting to set flag to its current state should throw
+ assert_raises_rpc_error(-8, "Wallet flag is already set to false", self.nodes[0].setwalletflag, 'avoid_reuse', False)
+ assert_raises_rpc_error(-8, "Wallet flag is already set to true", self.nodes[1].setwalletflag, 'avoid_reuse', True)
+
+ def test_immutable(self):
+ '''Test immutable wallet flags'''
+ # Attempt to set the disable_private_keys flag; this should not work
+ assert_raises_rpc_error(-8, "Wallet flag is immutable", self.nodes[1].setwalletflag, 'disable_private_keys')
+
+ tempwallet = ".wallet_avoidreuse.py_test_immutable_wallet.dat"
+
+ # Create a wallet with disable_private_keys set; this should work
+ self.nodes[1].createwallet(tempwallet, True)
+ w = self.nodes[1].get_wallet_rpc(tempwallet)
+
+ # Attempt to unset the disable_private_keys flag; this should not work
+ assert_raises_rpc_error(-8, "Wallet flag is immutable", w.setwalletflag, 'disable_private_keys', False)
+
+ # Unload temp wallet
+ self.nodes[1].unloadwallet(tempwallet)
+
+ def test_fund_send_fund_senddirty(self):
+ '''
+ Test the same as test_fund_send_fund_send, except send the 10 BTC with
+ the avoid_reuse flag set to false. This means the 10 BTC send should succeed,
+ where it fails in test_fund_send_fund_send.
+ '''
+
+ fundaddr = self.nodes[1].getnewaddress()
+ retaddr = self.nodes[0].getnewaddress()
+
+ self.nodes[0].sendtoaddress(fundaddr, 10)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 1 single, unused 10 btc output
+ assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
+ # getbalances should show no used, 10 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
+ # node 0 should not show a used entry, as it does not enable avoid_reuse
+ assert("used" not in self.nodes[0].getbalances()["mine"])
+
+ self.nodes[1].sendtoaddress(retaddr, 5)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 1 single, unused 5 btc output
+ assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
+ # getbalances should show no used, 5 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
+
+ self.nodes[0].sendtoaddress(fundaddr, 10)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
+ assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
+ # getbalances should show 10 used, 5 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})
+
+ self.nodes[1].sendtoaddress(address=retaddr, amount=10, avoid_reuse=False)
+
+ # listunspent should show 1 total outputs (5 btc), unused
+ assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_count=0)
+ # getbalances should show no used, 5 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
+
+ # node 1 should now have about 5 btc left (for both cases)
+ assert_approx(self.nodes[1].getbalance(), 5, 0.001)
+ assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 5, 0.001)
+
+ def test_fund_send_fund_send(self):
+ '''
+ Test the simple case where [1] generates a new address A, then
+ [0] sends 10 BTC to A.
+ [1] spends 5 BTC from A. (leaving roughly 5 BTC useable)
+ [0] sends 10 BTC to A again.
+ [1] tries to spend 10 BTC (fails; dirty).
+ [1] tries to spend 4 BTC (succeeds; change address sufficient)
+ '''
+
+ fundaddr = self.nodes[1].getnewaddress()
+ retaddr = self.nodes[0].getnewaddress()
+
+ self.nodes[0].sendtoaddress(fundaddr, 10)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 1 single, unused 10 btc output
+ assert_unspent(self.nodes[1], total_count=1, total_sum=10, reused_supported=True, reused_count=0)
+ # getbalances should show no used, 10 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 0, "trusted": 10})
+
+ self.nodes[1].sendtoaddress(retaddr, 5)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 1 single, unused 5 btc output
+ assert_unspent(self.nodes[1], total_count=1, total_sum=5, reused_supported=True, reused_count=0)
+ # getbalances should show no used, 5 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 0, "trusted": 5})
+
+ self.nodes[0].sendtoaddress(fundaddr, 10)
+ self.nodes[0].generate(1)
+ self.sync_all()
+
+ # listunspent should show 2 total outputs (5, 10 btc), one unused (5), one reused (10)
+ assert_unspent(self.nodes[1], total_count=2, total_sum=15, reused_count=1, reused_sum=10)
+ # getbalances should show 10 used, 5 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 10, "trusted": 5})
+
+ # node 1 should now have a balance of 5 (no dirty) or 15 (including dirty)
+ assert_approx(self.nodes[1].getbalance(), 5, 0.001)
+ assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 15, 0.001)
+
+ assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[1].sendtoaddress, retaddr, 10)
+
+ self.nodes[1].sendtoaddress(retaddr, 4)
+
+ # listunspent should show 2 total outputs (1, 10 btc), one unused (1), one reused (10)
+ assert_unspent(self.nodes[1], total_count=2, total_sum=11, reused_count=1, reused_sum=10)
+ # getbalances should show 10 used, 1 btc trusted
+ assert_balances(self.nodes[1], mine={"used": 10, "trusted": 1})
+
+ # node 1 should now have about 1 btc left (no dirty) and 11 (including dirty)
+ assert_approx(self.nodes[1].getbalance(), 1, 0.001)
+ assert_approx(self.nodes[1].getbalance(avoid_reuse=False), 11, 0.001)
+
+if __name__ == '__main__':
+ AvoidReuseTest().main()
diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py
index dd3750203a..55c517e92f 100755
--- a/test/functional/wallet_backup.py
+++ b/test/functional/wallet_backup.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the wallet backup features.
@@ -36,7 +36,12 @@ from random import randint
import shutil
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes, sync_blocks, sync_mempools
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+ connect_nodes,
+)
+
class WalletBackupTest(BitcoinTestFramework):
def set_test_params(self):
@@ -75,9 +80,9 @@ class WalletBackupTest(BitcoinTestFramework):
# Have the miner (node3) mine a block.
# Must sync mempools before mining.
- sync_mempools(self.nodes)
+ self.sync_mempools()
self.nodes[3].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# As above, this mirrors the original bash test.
def start_three(self):
@@ -102,13 +107,13 @@ class WalletBackupTest(BitcoinTestFramework):
def run_test(self):
self.log.info("Generating initial blockchain")
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.nodes[1].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.nodes[2].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.nodes[3].generate(100)
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(self.nodes[0].getbalance(), 50)
assert_equal(self.nodes[1].getbalance(), 50)
@@ -165,7 +170,7 @@ class WalletBackupTest(BitcoinTestFramework):
self.log.info("Re-starting nodes")
self.start_three()
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(self.nodes[0].getbalance(), balance0)
assert_equal(self.nodes[1].getbalance(), balance1)
@@ -189,7 +194,7 @@ class WalletBackupTest(BitcoinTestFramework):
self.nodes[1].importwallet(os.path.join(self.nodes[1].datadir, 'wallet.dump'))
self.nodes[2].importwallet(os.path.join(self.nodes[2].datadir, 'wallet.dump'))
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(self.nodes[0].getbalance(), balance0)
assert_equal(self.nodes[1].getbalance(), balance1)
diff --git a/test/functional/wallet_balance.py b/test/functional/wallet_balance.py
index 05c97e0340..137c77a51e 100755
--- a/test/functional/wallet_balance.py
+++ b/test/functional/wallet_balance.py
@@ -1,23 +1,26 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
"""Test the wallet balance RPC methods."""
from decimal import Decimal
+import struct
+from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE as ADDRESS_WATCHONLY
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
+ connect_nodes_bi,
+ sync_blocks,
)
-RANDOM_COINBASE_ADDRESS = 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ'
def create_transactions(node, address, amt, fees):
# Create and sign raw transactions from node to address for amt.
# Creates a transaction for each fee and returns an array
# of the raw transactions.
- utxos = node.listunspent(0)
+ utxos = [u for u in node.listunspent(0) if u['spendable']]
# Create transactions
inputs = []
@@ -25,14 +28,20 @@ def create_transactions(node, address, amt, fees):
for utxo in utxos:
inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
ins_total += utxo['amount']
- if ins_total > amt:
+ if ins_total >= amt + max(fees):
break
+ # make sure there was enough utxos
+ assert ins_total >= amt + max(fees)
txs = []
for fee in fees:
- outputs = {address: amt, node.getrawchangeaddress(): ins_total - amt - fee}
+ outputs = {address: amt}
+ # prevent 0 change output
+ if ins_total > amt + fee:
+ outputs[node.getrawchangeaddress()] = ins_total - amt - fee
raw_tx = node.createrawtransaction(inputs, outputs, 0, True)
raw_tx = node.signrawtransactionwithwallet(raw_tx)
+ assert_equal(raw_tx['complete'], True)
txs.append(raw_tx)
return txs
@@ -41,31 +50,48 @@ class WalletTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True
+ self.extra_args = [
+ ['-limitdescendantcount=3'], # Limit mempool descendants as a hack to have wallet txs rejected from the mempool
+ [],
+ ]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
+ self.nodes[0].importaddress(ADDRESS_WATCHONLY)
# Check that nodes don't own any UTXOs
assert_equal(len(self.nodes[0].listunspent()), 0)
assert_equal(len(self.nodes[1].listunspent()), 0)
- self.log.info("Mining one block for each node")
+ self.log.info("Check that only node 0 is watching an address")
+ assert 'watchonly' in self.nodes[0].getbalances()
+ assert 'watchonly' not in self.nodes[1].getbalances()
+ self.log.info("Mining blocks ...")
self.nodes[0].generate(1)
self.sync_all()
self.nodes[1].generate(1)
- self.nodes[1].generatetoaddress(100, RANDOM_COINBASE_ADDRESS)
+ self.nodes[1].generatetoaddress(101, ADDRESS_WATCHONLY)
self.sync_all()
+ assert_equal(self.nodes[0].getbalances()['mine']['trusted'], 50)
+ assert_equal(self.nodes[0].getwalletinfo()['balance'], 50)
+ assert_equal(self.nodes[1].getbalances()['mine']['trusted'], 50)
+
+ assert_equal(self.nodes[0].getbalances()['watchonly']['immature'], 5000)
+ assert 'watchonly' not in self.nodes[1].getbalances()
+
assert_equal(self.nodes[0].getbalance(), 50)
assert_equal(self.nodes[1].getbalance(), 50)
self.log.info("Test getbalance with different arguments")
assert_equal(self.nodes[0].getbalance("*"), 50)
assert_equal(self.nodes[0].getbalance("*", 1), 50)
- assert_equal(self.nodes[0].getbalance("*", 1, True), 50)
+ assert_equal(self.nodes[0].getbalance("*", 1, True), 100)
assert_equal(self.nodes[0].getbalance(minconf=1), 50)
+ assert_equal(self.nodes[0].getbalance(minconf=0, include_watchonly=True), 100)
+ assert_equal(self.nodes[1].getbalance(minconf=0, include_watchonly=True), 50)
# Send 40 BTC from 0 to 1 and 60 BTC from 1 to 0.
txs = create_transactions(self.nodes[0], self.nodes[1].getnewaddress(), 40, [Decimal('0.01')])
@@ -83,32 +109,37 @@ class WalletTest(BitcoinTestFramework):
self.log.info("Test getbalance and getunconfirmedbalance with unconfirmed inputs")
- # getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions
- assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send
- assert_equal(self.nodes[1].getbalance(), Decimal('29.99')) # change from node 1's send
- # Same with minconf=0
- assert_equal(self.nodes[0].getbalance(minconf=0), Decimal('9.99'))
- assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('29.99'))
- # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
- # TODO: fix getbalance tracking of coin spentness depth
- assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0'))
- assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
- # getunconfirmedbalance
- assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60')) # output of node 1's spend
- assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
+ def test_balances(*, fee_node_1=0):
+ # getbalance without any arguments includes unconfirmed transactions, but not untrusted transactions
+ assert_equal(self.nodes[0].getbalance(), Decimal('9.99')) # change from node 0's send
+ assert_equal(self.nodes[1].getbalance(), Decimal('30') - fee_node_1) # change from node 1's send
+ # Same with minconf=0
+ assert_equal(self.nodes[0].getbalance(minconf=0), Decimal('9.99'))
+ assert_equal(self.nodes[1].getbalance(minconf=0), Decimal('30') - fee_node_1)
+ # getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
+ # TODO: fix getbalance tracking of coin spentness depth
+ assert_equal(self.nodes[0].getbalance(minconf=1), Decimal('0'))
+ assert_equal(self.nodes[1].getbalance(minconf=1), Decimal('0'))
+ # getunconfirmedbalance
+ assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60')) # output of node 1's spend
+ assert_equal(self.nodes[0].getbalances()['mine']['untrusted_pending'], Decimal('60'))
+ assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('60'))
+
+ assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0')) # Doesn't include output of node 0's send since it was spent
+ assert_equal(self.nodes[1].getbalances()['mine']['untrusted_pending'], Decimal('0'))
+ assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0'))
+
+ test_balances(fee_node_1=Decimal('0.01'))
# Node 1 bumps the transaction fee and resends
self.nodes[1].sendrawtransaction(txs[1]['hex'])
+ self.nodes[0].sendrawtransaction(txs[1]['hex']) # sending on both nodes is faster than waiting for propagation
self.sync_all()
self.log.info("Test getbalance and getunconfirmedbalance with conflicted unconfirmed inputs")
+ test_balances(fee_node_1=Decimal('0.02'))
- assert_equal(self.nodes[0].getwalletinfo()["unconfirmed_balance"], Decimal('60')) # output of node 1's send
- assert_equal(self.nodes[0].getunconfirmedbalance(), Decimal('60'))
- assert_equal(self.nodes[1].getwalletinfo()["unconfirmed_balance"], Decimal('0')) # Doesn't include output of node 0's send since it was spent
- assert_equal(self.nodes[1].getunconfirmedbalance(), Decimal('0'))
-
- self.nodes[1].generatetoaddress(1, RANDOM_COINBASE_ADDRESS)
+ self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)
self.sync_all()
# balances are correct after the transactions are confirmed
@@ -118,7 +149,7 @@ class WalletTest(BitcoinTestFramework):
# Send total balance away from node 1
txs = create_transactions(self.nodes[1], self.nodes[0].getnewaddress(), Decimal('29.97'), [Decimal('0.01')])
self.nodes[1].sendrawtransaction(txs[0]['hex'])
- self.nodes[1].generatetoaddress(2, RANDOM_COINBASE_ADDRESS)
+ self.nodes[1].generatetoaddress(2, ADDRESS_WATCHONLY)
self.sync_all()
# getbalance with a minconf incorrectly excludes coins that have been spent more recently than the minconf blocks ago
@@ -129,5 +160,64 @@ class WalletTest(BitcoinTestFramework):
# getbalance with minconf=2 will show the new balance.
assert_equal(self.nodes[1].getbalance(minconf=2), Decimal('0'))
+ # check mempool transactions count for wallet unconfirmed balance after
+ # dynamically loading the wallet.
+ before = self.nodes[1].getunconfirmedbalance()
+ dst = self.nodes[1].getnewaddress()
+ self.nodes[1].unloadwallet('')
+ self.nodes[0].sendtoaddress(dst, 0.1)
+ self.sync_all()
+ self.nodes[1].loadwallet('')
+ after = self.nodes[1].getunconfirmedbalance()
+ assert_equal(before + Decimal('0.1'), after)
+
+ # Create 3 more wallet txs, where the last is not accepted to the
+ # mempool because it is the third descendant of the tx above
+ for _ in range(3):
+ # Set amount high enough such that all coins are spent by each tx
+ txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 99)
+
+ self.log.info('Check that wallet txs not in the mempool are untrusted')
+ assert txid not in self.nodes[0].getrawmempool()
+ assert_equal(self.nodes[0].gettransaction(txid)['trusted'], False)
+ assert_equal(self.nodes[0].getbalance(minconf=0), 0)
+
+ self.log.info("Test replacement and reorg of non-mempool tx")
+ tx_orig = self.nodes[0].gettransaction(txid)['hex']
+ # Increase fee by 1 coin
+ tx_replace = tx_orig.replace(
+ struct.pack("<q", 99 * 10**8).hex(),
+ struct.pack("<q", 98 * 10**8).hex(),
+ )
+ tx_replace = self.nodes[0].signrawtransactionwithwallet(tx_replace)['hex']
+ # Total balance is given by the sum of outputs of the tx
+ total_amount = sum([o['value'] for o in self.nodes[0].decoderawtransaction(tx_replace)['vout']])
+ self.sync_all()
+ self.nodes[1].sendrawtransaction(hexstring=tx_replace, maxfeerate=0)
+
+ # Now confirm tx_replace
+ block_reorg = self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)[0]
+ self.sync_all()
+ assert_equal(self.nodes[0].getbalance(minconf=0), total_amount)
+
+ self.log.info('Put txs back into mempool of node 1 (not node 0)')
+ self.nodes[0].invalidateblock(block_reorg)
+ self.nodes[1].invalidateblock(block_reorg)
+ self.sync_blocks()
+ self.nodes[0].syncwithvalidationinterfacequeue()
+ assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
+ self.nodes[0].generatetoaddress(1, ADDRESS_WATCHONLY)
+ assert_equal(self.nodes[0].getbalance(minconf=0), 0) # wallet txs not in the mempool are untrusted
+
+ # Now confirm tx_orig
+ self.restart_node(1, ['-persistmempool=0'])
+ connect_nodes_bi(self.nodes, 0, 1)
+ sync_blocks(self.nodes)
+ self.nodes[1].sendrawtransaction(tx_orig)
+ self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)
+ self.sync_all()
+ assert_equal(self.nodes[0].getbalance(minconf=0), total_amount + 1) # The reorg recovered our fee of 1 coin
+
+
if __name__ == '__main__':
WalletTest().main()
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 0477164b6b..daa834b5b8 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -13,8 +13,6 @@ from test_framework.util import (
assert_fee_amount,
assert_raises_rpc_error,
connect_nodes_bi,
- sync_blocks,
- sync_mempools,
wait_until,
)
@@ -34,7 +32,7 @@ class WalletTest(BitcoinTestFramework):
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes_bi(self.nodes, 1, 2)
connect_nodes_bi(self.nodes, 0, 2)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
"""Return curr_balance after asserting the fee was in range"""
@@ -59,9 +57,9 @@ class WalletTest(BitcoinTestFramework):
assert_equal(walletinfo['immature_balance'], 50)
assert_equal(walletinfo['balance'], 0)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
self.nodes[1].generate(101)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[0].getbalance(), 50)
assert_equal(self.nodes[1].getbalance(), 50)
@@ -108,7 +106,7 @@ class WalletTest(BitcoinTestFramework):
# Have node0 mine a block, thus it will collect its own fee.
self.nodes[0].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
# Exercise locking of unspent outputs
unspent_0 = self.nodes[2].listunspent()[0]
@@ -144,7 +142,7 @@ class WalletTest(BitcoinTestFramework):
# Have node1 generate 100 blocks (so node0 can recover the fee)
self.nodes[1].generate(100)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
# node0 should end up with 100 btc in block rewards plus fees, but
# minus the 21 plus fees sent to node2
@@ -168,12 +166,12 @@ class WalletTest(BitcoinTestFramework):
txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx))
# Have node 1 (miner) send the transactions
- self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
- self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)
+ self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], 0)
+ self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], 0)
# Have node1 mine a block to confirm transactions:
self.nodes[1].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[0].getbalance(), 0)
assert_equal(self.nodes[2].getbalance(), 94)
@@ -188,14 +186,14 @@ class WalletTest(BitcoinTestFramework):
self.nodes[2].settxfee(fee_per_byte * 1000)
txid = self.nodes[2].sendtoaddress(address, 10, "", "", False)
self.nodes[2].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
assert_equal(self.nodes[0].getbalance(), Decimal('10'))
# Send 10 BTC with subtract fee from amount
txid = self.nodes[2].sendtoaddress(address, 10, "", "", True)
self.nodes[2].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
@@ -203,7 +201,7 @@ class WalletTest(BitcoinTestFramework):
# Sendmany 10 BTC
txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [])
self.nodes[2].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
node_0_bal += Decimal('10')
node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
assert_equal(self.nodes[0].getbalance(), node_0_bal)
@@ -211,28 +209,14 @@ class WalletTest(BitcoinTestFramework):
# Sendmany 10 BTC with subtract fee from amount
txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address])
self.nodes[2].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(self.nodes[2].gettransaction(txid)['hex']))
- # Test ResendWalletTransactions:
- # Create a couple of transactions, then start up a fourth
- # node (nodes[3]) and ask nodes[0] to rebroadcast.
- # EXPECT: nodes[3] should have those transactions in its mempool.
- txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
- txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- sync_mempools(self.nodes[0:2])
-
self.start_node(3)
connect_nodes_bi(self.nodes, 0, 3)
- sync_blocks(self.nodes)
-
- relayed = self.nodes[0].resendwallettransactions()
- assert_equal(set(relayed), {txid1, txid2})
- sync_mempools(self.nodes)
-
- assert txid1 in self.nodes[3].getrawmempool()
+ self.sync_all()
# check if we can list zero value tx as available coins
# 1. create raw_tx
@@ -269,18 +253,18 @@ class WalletTest(BitcoinTestFramework):
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes_bi(self.nodes, 1, 2)
connect_nodes_bi(self.nodes, 0, 2)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast)
self.nodes[1].generate(1) # mine a block, tx should not be in there
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted
# now broadcast from another node, mine a block, sync, and check the balance
self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex'])
self.nodes[1].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
node_2_bal += 2
tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast)
assert_equal(self.nodes[2].getbalance(), node_2_bal)
@@ -296,10 +280,10 @@ class WalletTest(BitcoinTestFramework):
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes_bi(self.nodes, 1, 2)
connect_nodes_bi(self.nodes, 0, 2)
- sync_blocks(self.nodes[0:3])
+ self.sync_blocks(self.nodes[0:3])
self.nodes[0].generate(1)
- sync_blocks(self.nodes[0:3])
+ self.sync_blocks(self.nodes[0:3])
node_2_bal += 2
# tx should be added to balance because after restarting the nodes tx should be broadcast
@@ -356,7 +340,7 @@ class WalletTest(BitcoinTestFramework):
address_to_import = self.nodes[2].getnewaddress()
txid = self.nodes[0].sendtoaddress(address_to_import, 1)
self.nodes[0].generate(1)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
# 2. Import address from node2 to node1
self.nodes[1].importaddress(address_to_import)
@@ -382,15 +366,15 @@ class WalletTest(BitcoinTestFramework):
coinbase_addr = self.nodes[1].getnewaddress()
block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0]
coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0]
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
# Check that the txid and balance is found by node1
self.nodes[1].gettransaction(coinbase_txid)
# check if wallet or blockchain maintenance changes the balance
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
blocks = self.nodes[0].generate(2)
- self.sync_all([self.nodes[0:3]])
+ self.sync_all(self.nodes[0:3])
balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
block_count = self.nodes[0].getblockcount()
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index 3bef70f0a0..1fe029a6fb 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test the bumpfee RPC.
@@ -19,7 +19,13 @@ import io
from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness
from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes, sync_mempools
+from test_framework.util import (
+ assert_equal,
+ assert_greater_than,
+ assert_raises_rpc_error,
+ connect_nodes_bi,
+ hex_str_to_bytes,
+)
WALLET_PASSPHRASE = "test"
WALLET_PASSPHRASE_TIMEOUT = 3600
@@ -60,7 +66,7 @@ class BumpFeeTest(BitcoinTestFramework):
self.log.info("Running tests")
dest_address = peer_node.getnewaddress()
- test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)
+ test_simple_bumpfee_succeeds(self, rbf_node, peer_node, dest_address)
test_segwit_bumpfee_succeeds(rbf_node, dest_address)
test_nonrbf_bumpfee_fails(peer_node, dest_address)
test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)
@@ -73,19 +79,23 @@ class BumpFeeTest(BitcoinTestFramework):
test_unconfirmed_not_spendable(rbf_node, rbf_node_address)
test_bumpfee_metadata(rbf_node, dest_address)
test_locked_wallet_fails(rbf_node, dest_address)
+ test_change_script_match(rbf_node, dest_address)
+ # These tests wipe out a number of utxos that are expected in other tests
+ test_small_output_with_feerate_succeeds(rbf_node, dest_address)
+ test_no_more_inputs_fails(rbf_node, dest_address)
self.log.info("Success")
-def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):
+def test_simple_bumpfee_succeeds(self, rbf_node, peer_node, dest_address):
rbfid = spend_one_input(rbf_node, dest_address)
rbftx = rbf_node.gettransaction(rbfid)
- sync_mempools((rbf_node, peer_node))
+ self.sync_mempools((rbf_node, peer_node))
assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
bumped_tx = rbf_node.bumpfee(rbfid)
assert_equal(bumped_tx["errors"], [])
assert bumped_tx["fee"] - abs(rbftx["fee"]) > 0
# check that bumped_tx propagates, original tx was evicted and has a wallet conflict
- sync_mempools((rbf_node, peer_node))
+ self.sync_mempools((rbf_node, peer_node))
assert bumped_tx["txid"] in rbf_node.getrawmempool()
assert bumped_tx["txid"] in peer_node.getrawmempool()
assert rbfid not in rbf_node.getrawmempool()
@@ -173,6 +183,40 @@ def test_small_output_fails(rbf_node, dest_address):
rbfid = spend_one_input(rbf_node, dest_address)
assert_raises_rpc_error(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001})
+def test_small_output_with_feerate_succeeds(rbf_node, dest_address):
+
+ # Make sure additional inputs exist
+ rbf_node.generatetoaddress(101, rbf_node.getnewaddress())
+ rbfid = spend_one_input(rbf_node, dest_address)
+ original_input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"]
+ assert_equal(len(original_input_list), 1)
+ original_txin = original_input_list[0]
+ # Keep bumping until we out-spend change output
+ tx_fee = 0
+ while tx_fee < Decimal("0.0005"):
+ new_input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"]
+ new_item = list(new_input_list)[0]
+ assert_equal(len(original_input_list), 1)
+ assert_equal(original_txin["txid"], new_item["txid"])
+ assert_equal(original_txin["vout"], new_item["vout"])
+ rbfid_new_details = rbf_node.bumpfee(rbfid)
+ rbfid_new = rbfid_new_details["txid"]
+ raw_pool = rbf_node.getrawmempool()
+ assert rbfid not in raw_pool
+ assert rbfid_new in raw_pool
+ rbfid = rbfid_new
+ tx_fee = rbfid_new_details["origfee"]
+
+ # input(s) have been added
+ final_input_list = rbf_node.getrawtransaction(rbfid, 1)["vin"]
+ assert_greater_than(len(final_input_list), 1)
+ # Original input is in final set
+ assert [txin for txin in final_input_list
+ if txin["txid"] == original_txin["txid"]
+ and txin["vout"] == original_txin["vout"]]
+
+ rbf_node.generatetoaddress(1, rbf_node.getnewaddress())
+ assert_equal(rbf_node.gettransaction(rbfid)["confirmations"], 1)
def test_dust_to_fee(rbf_node, dest_address):
# check that if output is reduced to dust, it will be converted to fee
@@ -274,19 +318,37 @@ def test_locked_wallet_fails(rbf_node, dest_address):
rbf_node.walletlock()
assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.",
rbf_node.bumpfee, rbfid)
+ rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
+def test_change_script_match(rbf_node, dest_address):
+ """Test that the same change addresses is used for the replacement transaction when possible."""
+ def get_change_address(tx):
+ tx_details = rbf_node.getrawtransaction(tx, 1)
+ txout_addresses = [txout['scriptPubKey']['addresses'][0] for txout in tx_details["vout"]]
+ return [address for address in txout_addresses if rbf_node.getaddressinfo(address)["ischange"]]
-def spend_one_input(node, dest_address):
+ # Check that there is only one change output
+ rbfid = spend_one_input(rbf_node, dest_address)
+ change_addresses = get_change_address(rbfid)
+ assert_equal(len(change_addresses), 1)
+
+ # Now find that address in each subsequent tx, and no other change
+ bumped_total_tx = rbf_node.bumpfee(rbfid, {"totalFee": 2000})
+ assert_equal(change_addresses, get_change_address(bumped_total_tx['txid']))
+ bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"])
+ assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid']))
+
+def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")):
tx_input = dict(
sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000")))
- rawtx = node.createrawtransaction(
- [tx_input], {dest_address: Decimal("0.00050000"),
- node.getrawchangeaddress(): Decimal("0.00049000")})
+ destinations = {dest_address: Decimal("0.00050000")}
+ if change_size > 0:
+ destinations[node.getrawchangeaddress()] = change_size
+ rawtx = node.createrawtransaction([tx_input], destinations)
signedtx = node.signrawtransactionwithwallet(rawtx)
txid = node.sendrawtransaction(signedtx["hex"])
return txid
-
def submit_block_with_tx(node, tx):
ctx = CTransaction()
ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))
@@ -300,9 +362,15 @@ def submit_block_with_tx(node, tx):
block.hashMerkleRoot = block.calc_merkle_root()
add_witness_commitment(block)
block.solve()
- node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ node.submitblock(block.serialize().hex())
return block
+def test_no_more_inputs_fails(rbf_node, dest_address):
+ # feerate rbf requires confirmed outputs when change output doesn't exist or is insufficient
+ rbf_node.generatetoaddress(1, dest_address)
+ # spend all funds, no change output
+ rbfid = rbf_node.sendtoaddress(rbf_node.getnewaddress(), rbf_node.getbalance(), "", "", True)
+ assert_raises_rpc_error(-4, "Unable to create transaction: Insufficient funds", rbf_node.bumpfee, rbfid)
if __name__ == "__main__":
BumpFeeTest().main()
diff --git a/test/functional/wallet_create_tx.py b/test/functional/wallet_create_tx.py
index 7b749235e2..0b584a0bb2 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 The Bitcoin Core developers
+# 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.
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index 7ec72b8649..c17949a2f6 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
"""Test createwallet arguments.
@@ -40,8 +40,8 @@ class CreateWalletTest(BitcoinTestFramework):
privkey = w0.dumpprivkey(addr)
assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey)
result = w1.importmulti([{'scriptPubKey': {'address': addr}, 'timestamp': 'now', 'keys': [privkey]}])
- assert(not result[0]['success'])
- assert('warning' not in result[0])
+ assert not result[0]['success']
+ assert 'warning' not in result[0]
assert_equal(result[0]['error']['code'], -4)
assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled')
@@ -92,9 +92,32 @@ class CreateWalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress)
# Encrypt the wallet
- w5.encryptwallet('pass')
+ assert_raises_rpc_error(-16, "Error: wallet does not contain private keys, nothing to encrypt.", w5.encryptwallet, 'pass')
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress)
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress)
+ self.log.info('New blank and encrypted wallets can be created')
+ self.nodes[0].createwallet(wallet_name='wblank', disable_private_keys=False, blank=True, passphrase='thisisapassphrase')
+ wblank = node.get_wallet_rpc('wblank')
+ assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wblank.signmessage, "needanargument", "test")
+ wblank.walletpassphrase('thisisapassphrase', 10)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getrawchangeaddress)
+
+ self.log.info('Test creating a new encrypted wallet.')
+ # Born encrypted wallet is created (has keys)
+ self.nodes[0].createwallet(wallet_name='w6', disable_private_keys=False, blank=False, passphrase='thisisapassphrase')
+ w6 = node.get_wallet_rpc('w6')
+ assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", w6.signmessage, "needanargument", "test")
+ w6.walletpassphrase('thisisapassphrase', 10)
+ w6.signmessage(w6.getnewaddress('', 'legacy'), "test")
+ w6.keypoolrefill(1)
+ # There should only be 1 key
+ walletinfo = w6.getwalletinfo()
+ assert_equal(walletinfo['keypoolsize'], 1)
+ assert_equal(walletinfo['keypoolsize_hd_internal'], 1)
+ # Empty passphrase, error
+ assert_raises_rpc_error(-16, 'Cannot encrypt a wallet with a blank password', self.nodes[0].createwallet, 'w7', False, False, '')
+
if __name__ == '__main__':
CreateWalletTest().main()
diff --git a/test/functional/wallet_disable.py b/test/functional/wallet_disable.py
index 6530c58c78..7c2ec56b5a 100755
--- a/test/functional/wallet_disable.py
+++ b/test/functional/wallet_disable.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
"""Test a node with the -disablewallet option.
@@ -21,9 +21,9 @@ class DisableWalletTest (BitcoinTestFramework):
# Make sure wallet is really disabled
assert_raises_rpc_error(-32601, 'Method not found', self.nodes[0].getwalletinfo)
x = self.nodes[0].validateaddress('3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy')
- assert(x['isvalid'] == False)
+ assert x['isvalid'] == False
x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ')
- assert(x['isvalid'] == True)
+ assert x['isvalid'] == True
# Checking mining to an address without a wallet. Generating to a valid address should succeed
# but generating to an invalid address will fail.
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index 3f39654bb8..53edf710b9 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test the dumpwallet RPC."""
@@ -46,10 +46,10 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old):
keypath = None
if keytype == "inactivehdseed=1":
# ensure the old master is still available
- assert (hd_master_addr_old == addr)
+ assert hd_master_addr_old == addr
elif keytype == "hdseed=1":
# ensure we have generated a new hd master key
- assert (hd_master_addr_old != addr)
+ assert hd_master_addr_old != addr
hd_master_addr_ret = addr
elif keytype == "script=1":
# scripts don't have keypaths
diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py
index 61245e5104..97172d8b82 100755
--- a/test/functional/wallet_hd.py
+++ b/test/functional/wallet_hd.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2016-2018 The Bitcoin Core developers
+# Copyright (c) 2016-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.
"""Test Hierarchical Deterministic wallet function."""
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index 46462a16f3..47c97f62bf 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-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test wallet import RPCs.
@@ -20,7 +20,11 @@ happened previously.
"""
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import (assert_raises_rpc_error, connect_nodes, sync_blocks, assert_equal, set_node_times)
+from test_framework.util import (
+ connect_nodes,
+ assert_equal,
+ set_node_times,
+)
import collections
import enum
@@ -34,23 +38,17 @@ Rescan = enum.Enum("Rescan", "no yes late_timestamp")
class Variant(collections.namedtuple("Variant", "call data rescan prune")):
"""Helper for importing one key and verifying scanned transactions."""
- def try_rpc(self, func, *args, **kwargs):
- if self.expect_disabled:
- assert_raises_rpc_error(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs)
- else:
- return func(*args, **kwargs)
-
def do_import(self, timestamp):
"""Call one key import RPC."""
rescan = self.rescan == Rescan.yes
if self.call == Call.single:
if self.data == Data.address:
- response = self.try_rpc(self.node.importaddress, address=self.address["address"], label=self.label, rescan=rescan)
+ response = self.node.importaddress(address=self.address["address"], label=self.label, rescan=rescan)
elif self.data == Data.pub:
- response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
+ response = self.node.importpubkey(pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
elif self.data == Data.priv:
- response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan)
+ response = self.node.importprivkey(privkey=self.key, label=self.label, rescan=rescan)
assert_equal(response, None)
elif self.call in (Call.multiaddress, Call.multiscript):
@@ -161,13 +159,13 @@ class ImportRescanTest(BitcoinTestFramework):
timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_all()
# For each variation of wallet key import, invoke the import RPC and
# check the results from getbalance and listtransactions.
for variant in IMPORT_VARIANTS:
- variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single
- expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled
+ self.log.info('Run import for variant {}'.format(variant))
+ expect_rescan = variant.rescan == Rescan.yes
variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]
variant.do_import(timestamp)
if expect_rescan:
@@ -187,16 +185,14 @@ class ImportRescanTest(BitcoinTestFramework):
# Generate a block containing the new transactions.
self.nodes[0].generate(1)
assert_equal(self.nodes[0].getrawmempool(), [])
- sync_blocks(self.nodes)
+ self.sync_all()
# Check the latest results from getbalance and listtransactions.
for variant in IMPORT_VARIANTS:
- if not variant.expect_disabled:
- variant.expected_balance += variant.sent_amount
- variant.expected_txs += 1
- variant.check(variant.sent_txid, variant.sent_amount, 1)
- else:
- variant.check()
+ self.log.info('Run check for variant {}'.format(variant))
+ variant.expected_balance += variant.sent_amount
+ variant.expected_txs += 1
+ variant.check(variant.sent_txid, variant.sent_amount, 1)
if __name__ == "__main__":
ImportRescanTest().main()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index c6d0425f22..e19c7919a9 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the importmulti RPC.
@@ -25,7 +25,6 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
- bytes_to_hex_str,
)
from test_framework.wallet_util import (
get_key,
@@ -127,7 +126,7 @@ class ImportMultiTest(BitcoinTestFramework):
# Nonstandard scriptPubKey + !internal
self.log.info("Should not import a nonstandard scriptPubKey without internal flag")
- nonstandardScriptPubKey = key.p2pkh_script + bytes_to_hex_str(CScript([OP_NOP]))
+ nonstandardScriptPubKey = key.p2pkh_script + CScript([OP_NOP]).hex()
key = get_key(self.nodes[0])
self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey,
"timestamp": "now"},
@@ -572,6 +571,7 @@ class ImportMultiTest(BitcoinTestFramework):
# Test ranged descriptor fails if range is not specified
xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
addresses = ["2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1'
+ addresses += ["bcrt1qrd3n235cj2czsfmsuvqqpr3lu6lg0ju7scl8gn", "bcrt1qfqeppuvj0ww98r6qghmdkj70tv8qpchehegrg8"] # wpkh subscripts corresponding to the above addresses
desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))"
self.log.info("Ranged descriptor import should fail without a specified range")
self.test_importmulti({"desc": descsum_create(desc),
@@ -580,17 +580,49 @@ class ImportMultiTest(BitcoinTestFramework):
error_code=-8,
error_message='Descriptor is ranged, please specify the range')
- # Test importing of a ranged descriptor without keys
+ # Test importing of a ranged descriptor with xpriv
self.log.info("Should import the ranged descriptor with specified range as solvable")
self.test_importmulti({"desc": descsum_create(desc),
"timestamp": "now",
"range": 1},
- success=True,
- warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
+ success=True)
for address in addresses:
test_address(self.nodes[1],
- key.p2sh_p2wpkh_addr,
- solvable=True)
+ address,
+ solvable=True,
+ ismine=True)
+
+ self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": -1},
+ success=False, error_code=-8, error_message='End of range is too high')
+
+ self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]},
+ success=False, error_code=-8, error_message='Range should be greater or equal than 0')
+
+ self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]},
+ success=False, error_code=-8, error_message='End of range is too high')
+
+ self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]},
+ success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end')
+
+ self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]},
+ success=False, error_code=-8, error_message='Range is too large')
+
+ # Test importing a descriptor containing a WIF private key
+ wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh"
+ address = "2MuhcG52uHPknxDgmGPsV18jSHFBnnRgjPg"
+ desc = "sh(wpkh(" + wif_priv + "))"
+ self.log.info("Should import a descriptor with a WIF private key as spendable")
+ self.test_importmulti({"desc": descsum_create(desc),
+ "timestamp": "now"},
+ success=True)
+ test_address(self.nodes[1],
+ address,
+ solvable=True,
+ ismine=True)
+
+ # dump the private key to ensure it matches what was imported
+ privkey = self.nodes[1].dumpprivkey(address)
+ assert_equal(privkey, wif_priv)
# Test importing of a P2PKH address via descriptor
key = get_key(self.nodes[0])
@@ -630,7 +662,8 @@ class ImportMultiTest(BitcoinTestFramework):
self.log.info("Should import a 1-of-2 bare multisig from descriptor")
self.test_importmulti({"desc": descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey + ")"),
"timestamp": "now"},
- success=True)
+ success=True,
+ warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
self.log.info("Should not treat individual keys from the imported bare multisig as watchonly")
test_address(self.nodes[1],
key1.p2pkh_addr,
@@ -760,7 +793,7 @@ class ImportMultiTest(BitcoinTestFramework):
assert_equal(addr2, newaddr2)
# Import a multisig and make sure the keys don't go into the keypool
- self.log.info('Imported scripts with pubkeys shoud not have their pubkeys go into the keypool')
+ self.log.info('Imported scripts with pubkeys should not have their pubkeys go into the keypool')
addr1 = self.nodes[0].getnewaddress()
addr2 = self.nodes[0].getnewaddress()
pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
diff --git a/test/functional/wallet_keypool.py b/test/functional/wallet_keypool.py
index 1116196268..e3aeb61197 100755
--- a/test/functional/wallet_keypool.py
+++ b/test/functional/wallet_keypool.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the wallet keypool and interaction with wallet encryption/locking."""
@@ -21,7 +21,7 @@ class KeyPoolTest(BitcoinTestFramework):
addr_before_encrypting = nodes[0].getnewaddress()
addr_before_encrypting_data = nodes[0].getaddressinfo(addr_before_encrypting)
wallet_info_old = nodes[0].getwalletinfo()
- assert(addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid'])
+ assert addr_before_encrypting_data['hdseedid'] == wallet_info_old['hdseedid']
# Encrypt wallet and wait to terminate
nodes[0].encryptwallet('test')
@@ -29,8 +29,8 @@ class KeyPoolTest(BitcoinTestFramework):
addr = nodes[0].getnewaddress()
addr_data = nodes[0].getaddressinfo(addr)
wallet_info = nodes[0].getwalletinfo()
- assert(addr_before_encrypting_data['hdseedid'] != wallet_info['hdseedid'])
- assert(addr_data['hdseedid'] == wallet_info['hdseedid'])
+ assert addr_before_encrypting_data['hdseedid'] != wallet_info['hdseedid']
+ assert addr_data['hdseedid'] == wallet_info['hdseedid']
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
# put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min)
@@ -59,7 +59,7 @@ class KeyPoolTest(BitcoinTestFramework):
addr.add(nodes[0].getnewaddress())
addr.add(nodes[0].getnewaddress())
addr.add(nodes[0].getnewaddress())
- assert(len(addr) == 6)
+ assert len(addr) == 6
# the next one should fail
assert_raises_rpc_error(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py
index b7c8d3098d..0014555ade 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-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.
"""Test HD Wallet keypool restore function.
@@ -17,7 +17,6 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes_bi,
- sync_blocks,
)
@@ -55,11 +54,11 @@ class KeypoolRestoreTest(BitcoinTestFramework):
# Make sure we're creating the outputs we expect
address_details = self.nodes[idx].validateaddress(addr_extpool)
if i == 0:
- assert(not address_details["isscript"] and not address_details["iswitness"])
+ assert not address_details["isscript"] and not address_details["iswitness"]
elif i == 1:
- assert(address_details["isscript"] and not address_details["iswitness"])
+ assert address_details["isscript"] and not address_details["iswitness"]
else:
- assert(not address_details["isscript"] and address_details["iswitness"])
+ assert not address_details["isscript"] and address_details["iswitness"]
self.log.info("Send funds to wallet")
@@ -67,7 +66,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.nodes[0].sendtoaddress(addr_extpool, 5)
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
self.log.info("Restart node with wallet backup")
self.stop_node(idx)
diff --git a/test/functional/wallet_listreceivedby.py b/test/functional/wallet_listreceivedby.py
index 011975e371..5e94068930 100755
--- a/test/functional/wallet_listreceivedby.py
+++ b/test/functional/wallet_listreceivedby.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the listreceivedbyaddress RPC."""
@@ -10,7 +10,6 @@ from test_framework.util import (
assert_array_result,
assert_equal,
assert_raises_rpc_error,
- sync_blocks,
)
@@ -24,7 +23,7 @@ class ReceivedByTest(BitcoinTestFramework):
def run_test(self):
# Generate block to get out of IBD
self.nodes[0].generate(1)
- sync_blocks(self.nodes)
+ self.sync_blocks()
# save the number of coinbase reward addresses so far
num_cb_reward_addresses = len(self.nodes[1].listreceivedbyaddress(minconf=0, include_empty=True, include_watchonly=True))
diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py
index 25ab222375..021a29d4ac 100755
--- a/test/functional/wallet_listsinceblock.py
+++ b/test/functional/wallet_listsinceblock.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test the listsincelast RPC."""
@@ -98,7 +98,8 @@ class ListSinceBlockTest (BitcoinTestFramework):
self.nodes[2].generate(7)
self.log.info('lastblockhash=%s' % (lastblockhash))
- self.sync_all([self.nodes[:2], self.nodes[2:]])
+ self.sync_all(self.nodes[:2])
+ self.sync_all(self.nodes[2:])
self.join_network()
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 17f044bf65..997d6e702c 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2014-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the listtransactions API."""
@@ -11,9 +11,7 @@ from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_array_result,
assert_equal,
- bytes_to_hex_str,
hex_str_to_bytes,
- sync_mempools,
)
def tx_from_hex(hexstring):
@@ -126,9 +124,9 @@ class ListTransactionsTest(BitcoinTestFramework):
# 1. Chain a few transactions that don't opt-in.
txid_1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
- assert(not is_opt_in(self.nodes[0], txid_1))
+ assert not is_opt_in(self.nodes[0], txid_1)
assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"})
- sync_mempools(self.nodes)
+ self.sync_mempools()
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_1}, {"bip125-replaceable": "no"})
# Tx2 will build off txid_1, still not opting in to RBF.
@@ -146,9 +144,9 @@ class ListTransactionsTest(BitcoinTestFramework):
txid_2 = self.nodes[1].sendrawtransaction(tx2_signed)
# ...and check the result
- assert(not is_opt_in(self.nodes[1], txid_2))
+ assert not is_opt_in(self.nodes[1], txid_2)
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"})
- sync_mempools(self.nodes)
+ self.sync_mempools()
assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_2}, {"bip125-replaceable": "no"})
# Tx3 will opt-in to RBF
@@ -158,13 +156,13 @@ class ListTransactionsTest(BitcoinTestFramework):
tx3 = self.nodes[0].createrawtransaction(inputs, outputs)
tx3_modified = tx_from_hex(tx3)
tx3_modified.vin[0].nSequence = 0
- tx3 = bytes_to_hex_str(tx3_modified.serialize())
+ tx3 = tx3_modified.serialize().hex()
tx3_signed = self.nodes[0].signrawtransactionwithwallet(tx3)['hex']
txid_3 = self.nodes[0].sendrawtransaction(tx3_signed)
- assert(is_opt_in(self.nodes[0], txid_3))
+ assert is_opt_in(self.nodes[0], txid_3)
assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"})
- sync_mempools(self.nodes)
+ self.sync_mempools()
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_3}, {"bip125-replaceable": "yes"})
# Tx4 will chain off tx3. Doesn't signal itself, but depends on one
@@ -176,21 +174,21 @@ class ListTransactionsTest(BitcoinTestFramework):
tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"]
txid_4 = self.nodes[1].sendrawtransaction(tx4_signed)
- assert(not is_opt_in(self.nodes[1], txid_4))
+ assert not is_opt_in(self.nodes[1], txid_4)
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"})
- sync_mempools(self.nodes)
+ self.sync_mempools()
assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "yes"})
# Replace tx3, and check that tx4 becomes unknown
tx3_b = tx3_modified
tx3_b.vout[0].nValue -= int(Decimal("0.004") * COIN) # bump the fee
- tx3_b = bytes_to_hex_str(tx3_b.serialize())
+ tx3_b = tx3_b.serialize().hex()
tx3_b_signed = self.nodes[0].signrawtransactionwithwallet(tx3_b)['hex']
- txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, True)
- assert(is_opt_in(self.nodes[0], txid_3b))
+ txid_3b = self.nodes[0].sendrawtransaction(tx3_b_signed, 0)
+ assert is_opt_in(self.nodes[0], txid_3b)
assert_array_result(self.nodes[0].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"})
- sync_mempools(self.nodes)
+ self.sync_mempools()
assert_array_result(self.nodes[1].listtransactions(), {"txid": txid_4}, {"bip125-replaceable": "unknown"})
# Check gettransaction as well:
@@ -203,7 +201,7 @@ class ListTransactionsTest(BitcoinTestFramework):
# After mining a transaction, it's no longer BIP125-replaceable
self.nodes[0].generate(1)
- assert(txid_3b not in self.nodes[0].getrawmempool())
+ assert txid_3b not in self.nodes[0].getrawmempool()
assert_equal(self.nodes[0].gettransaction(txid_3b)["bip125-replaceable"], "no")
assert_equal(self.nodes[0].gettransaction(txid_4)["bip125-replaceable"], "unknown")
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index df778f57df..984ffab5a4 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# 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.
"""Test multiwallet.
diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py
index 00bf58d709..5810e94938 100755
--- a/test/functional/wallet_resendwallettransactions.py
+++ b/test/functional/wallet_resendwallettransactions.py
@@ -1,32 +1,77 @@
#!/usr/bin/env python3
-# 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.
-"""Test resendwallettransactions RPC."""
+"""Test that the wallet resends transactions periodically."""
+from collections import defaultdict
+import time
+from test_framework.blocktools import create_block, create_coinbase
+from test_framework.messages import ToHex
+from test_framework.mininode import P2PInterface, mininode_lock
from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal, assert_raises_rpc_error
+from test_framework.util import assert_equal, wait_until
+
+class P2PStoreTxInvs(P2PInterface):
+ def __init__(self):
+ super().__init__()
+ self.tx_invs_received = defaultdict(int)
+
+ def on_inv(self, message):
+ # Store how many times invs have been received for each tx.
+ for i in message.inv:
+ if i.type == 1:
+ # save txid
+ self.tx_invs_received[i.hash] += 1
class ResendWalletTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['--walletbroadcast=false']]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
- # Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled.
- assert_raises_rpc_error(-4, "Error: Wallet transaction broadcasting is disabled with -walletbroadcast", self.nodes[0].resendwallettransactions)
+ node = self.nodes[0] # alias
+
+ node.add_p2p_connection(P2PStoreTxInvs())
+
+ self.log.info("Create a new transaction and wait until it's broadcast")
+ txid = int(node.sendtoaddress(node.getnewaddress(), 1), 16)
+
+ # Wallet rebroadcast is first scheduled 1 sec after startup (see
+ # nNextResend in ResendWalletTransactions()). Sleep for just over a
+ # second to be certain that it has been called before the first
+ # setmocktime call below.
+ time.sleep(1.1)
+
+ # Can take a few seconds due to transaction trickling
+ wait_until(lambda: node.p2p.tx_invs_received[txid] >= 1, lock=mininode_lock)
+
+ # Add a second peer since txs aren't rebroadcast to the same peer (see filterInventoryKnown)
+ node.add_p2p_connection(P2PStoreTxInvs())
+
+ self.log.info("Create a block")
+ # Create and submit a block without the transaction.
+ # Transactions are only rebroadcast if there has been a block at least five minutes
+ # after the last time we tried to broadcast. Use mocktime and give an extra minute to be sure.
+ block_time = int(time.time()) + 6 * 60
+ node.setmocktime(block_time)
+ block = create_block(int(node.getbestblockhash(), 16), create_coinbase(node.getblockchaininfo()['blocks']), block_time)
+ block.nVersion = 3
+ block.rehash()
+ block.solve()
+ node.submitblock(ToHex(block))
- # Should return an empty array if there aren't unconfirmed wallet transactions.
- self.stop_node(0)
- self.start_node(0, extra_args=[])
- assert_equal(self.nodes[0].resendwallettransactions(), [])
+ # Transaction should not be rebroadcast
+ node.p2ps[1].sync_with_ping()
+ assert_equal(node.p2ps[1].tx_invs_received[txid], 0)
- # Should return an array with the unconfirmed wallet transaction.
- txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
- assert_equal(self.nodes[0].resendwallettransactions(), [txid])
+ self.log.info("Transaction should be rebroadcast after 30 minutes")
+ # Use mocktime and give an extra 5 minutes to be sure.
+ rebroadcast_time = int(time.time()) + 41 * 60
+ node.setmocktime(rebroadcast_time)
+ wait_until(lambda: node.p2ps[1].tx_invs_received[txid] >= 1, lock=mininode_lock)
if __name__ == '__main__':
ResendWalletTransactionsTest().main()
diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py
index a0a35bf43d..60d7205887 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-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the wallet accounts properly when there are cloned transactions with malleated scriptsigs."""
@@ -8,10 +8,8 @@ import io
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
- bytes_to_hex_str as b2x,
connect_nodes,
disconnect_nodes,
- sync_blocks,
)
from test_framework.messages import CTransaction, COIN
@@ -82,13 +80,13 @@ class TxnMallTest(BitcoinTestFramework):
# Use a different signature hash type to sign. This creates an equivalent but malleated clone.
# Don't send the clone anywhere yet
- tx1_clone = self.nodes[0].signrawtransactionwithwallet(b2x(clone_tx.serialize()), None, "ALL|ANYONECANPAY")
+ tx1_clone = self.nodes[0].signrawtransactionwithwallet(clone_tx.serialize().hex(), None, "ALL|ANYONECANPAY")
assert_equal(tx1_clone["complete"], True)
# Have node0 mine a block, if requested:
if (self.options.mine_block):
self.nodes[0].generate(1)
- sync_blocks(self.nodes[0:2])
+ self.sync_blocks(self.nodes[0:2])
tx1 = self.nodes[0].gettransaction(txid1)
tx2 = self.nodes[0].gettransaction(txid2)
@@ -124,7 +122,7 @@ class TxnMallTest(BitcoinTestFramework):
self.nodes[2].sendrawtransaction(node0_tx2["hex"])
self.nodes[2].sendrawtransaction(tx2["hex"])
self.nodes[2].generate(1) # Mine another block to make sure we sync
- sync_blocks(self.nodes)
+ self.sync_blocks()
# Re-fetch transaction info:
tx1 = self.nodes[0].gettransaction(txid1)
diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py
index 9050e21247..40eeb4048c 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-2018 The Bitcoin Core developers
+# Copyright (c) 2014-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.
"""Test the wallet accounts properly when there is a double-spend conflict."""
@@ -11,7 +11,6 @@ from test_framework.util import (
connect_nodes,
disconnect_nodes,
find_output,
- sync_blocks,
)
class TxnMallTest(BitcoinTestFramework):
@@ -86,7 +85,7 @@ class TxnMallTest(BitcoinTestFramework):
# Have node0 mine a block:
if (self.options.mine_block):
self.nodes[0].generate(1)
- sync_blocks(self.nodes[0:2])
+ self.sync_blocks(self.nodes[0:2])
tx1 = self.nodes[0].gettransaction(txid1)
tx2 = self.nodes[0].gettransaction(txid2)
@@ -119,7 +118,7 @@ class TxnMallTest(BitcoinTestFramework):
# Reconnect the split network, and sync chain:
connect_nodes(self.nodes[1], 2)
self.nodes[2].generate(1) # Mine another block to make sure we sync
- sync_blocks(self.nodes)
+ self.sync_blocks()
assert_equal(self.nodes[0].gettransaction(doublespend_txid)["confirmations"], 2)
# Re-fetch transaction info:
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 1869f71753..f19cf924d2 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -106,8 +106,10 @@ def run_once(*, corpus, test_list, build_dir, export_coverage):
os.path.join(corpus, t),
]
logging.debug('Run {} with args {}'.format(t, args))
- output = subprocess.run(args, check=True, stderr=subprocess.PIPE, universal_newlines=True).stderr
+ result = subprocess.run(args, stderr=subprocess.PIPE, universal_newlines=True)
+ output = result.stderr
logging.debug('Output: {}'.format(output))
+ result.check_returncode()
if not export_coverage:
continue
for l in output.splitlines():
diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py
index c370ce0c04..1d6122a13d 100755
--- a/test/lint/check-doc.py
+++ b/test/lint/check-doc.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# Copyright (c) 2015-2018 The Bitcoin Core developers
+# Copyright (c) 2015-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.
@@ -12,26 +12,23 @@ Author: @MarcoFalke
from subprocess import check_output
import re
-import sys
FOLDER_GREP = 'src'
FOLDER_TEST = 'src/test/'
REGEX_ARG = '(?:ForceSet|SoftSet|Get|Is)(?:Bool)?Args?(?:Set)?\("(-[^"]+)"'
REGEX_DOC = 'AddArg\("(-[^"=]+?)(?:=|")'
-CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_GREP)
+CMD_ROOT_DIR = '$(git rev-parse --show-toplevel)/{}'.format(FOLDER_GREP)
CMD_GREP_ARGS = r"git grep --perl-regexp '{}' -- {} ':(exclude){}'".format(REGEX_ARG, CMD_ROOT_DIR, FOLDER_TEST)
+CMD_GREP_WALLET_ARGS = r"git grep --function-context 'void WalletInit::AddWalletOptions' -- {} | grep AddArg".format(CMD_ROOT_DIR)
+CMD_GREP_WALLET_HIDDEN_ARGS = r"git grep --function-context 'void DummyWalletInit::AddWalletOptions' -- {}".format(CMD_ROOT_DIR)
CMD_GREP_DOCS = r"git grep --perl-regexp '{}' {}".format(REGEX_DOC, CMD_ROOT_DIR)
# list unsupported, deprecated and duplicate args as they need no documentation
SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb'])
-def main():
- if sys.version_info >= (3, 6):
- used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True, encoding='utf8')
- docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True, encoding='utf8')
- else:
- used = check_output(CMD_GREP_ARGS, shell=True).decode('utf8').strip()
- docd = check_output(CMD_GREP_DOCS, shell=True).decode('utf8').strip()
+def lint_missing_argument_documentation():
+ used = check_output(CMD_GREP_ARGS, shell=True).decode('utf8').strip()
+ docd = check_output(CMD_GREP_DOCS, shell=True).decode('utf8').strip()
args_used = set(re.findall(re.compile(REGEX_ARG), used))
args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL)
@@ -45,7 +42,24 @@ def main():
print("Args unknown : {}".format(len(args_unknown)))
print(args_unknown)
- sys.exit(len(args_need_doc))
+ assert 0 == len(args_need_doc), "Please document the following arguments: {}".format(args_need_doc)
+
+
+def lint_missing_hidden_wallet_args():
+ wallet_args = check_output(CMD_GREP_WALLET_ARGS, shell=True).decode('utf8').strip()
+ wallet_hidden_args = check_output(CMD_GREP_WALLET_HIDDEN_ARGS, shell=True).decode('utf8').strip()
+
+ wallet_args = set(re.findall(re.compile(REGEX_DOC), wallet_args))
+ wallet_hidden_args = set(re.findall(re.compile(r' "([^"=]+)'), wallet_hidden_args))
+
+ hidden_missing = wallet_args.difference(wallet_hidden_args)
+ if hidden_missing:
+ assert 0, "Please add {} to the hidden args in DummyWalletInit::AddWalletOptions".format(hidden_missing)
+
+
+def main():
+ lint_missing_argument_documentation()
+ lint_missing_hidden_wallet_args()
if __name__ == "__main__":
diff --git a/test/lint/lint-all.sh b/test/lint/lint-all.sh
index 7c4f96cb3b..fabc24c91b 100755
--- a/test/lint/lint-all.sh
+++ b/test/lint/lint-all.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
-# Copyright (c) 2017 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.
#
@@ -16,11 +16,15 @@ set -u
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
LINTALL=$(basename "${BASH_SOURCE[0]}")
+EXIT_CODE=0
+
for f in "${SCRIPTDIR}"/lint-*.sh; do
if [ "$(basename "$f")" != "$LINTALL" ]; then
if ! "$f"; then
echo "^---- failure generated from $f"
- exit 1
+ EXIT_CODE=1
fi
fi
done
+
+exit ${EXIT_CODE}
diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh
index be67cbed31..70cc16337e 100755
--- a/test/lint/lint-circular-dependencies.sh
+++ b/test/lint/lint-circular-dependencies.sh
@@ -10,10 +10,8 @@ export LC_ALL=C
EXPECTED_CIRCULAR_DEPENDENCIES=(
"chainparamsbase -> util/system -> chainparamsbase"
- "checkpoints -> validation -> checkpoints"
"index/txindex -> validation -> index/txindex"
"policy/fees -> txmempool -> policy/fees"
- "policy/policy -> validation -> policy/policy"
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel"
"qt/bantablemodel -> qt/clientmodel -> qt/bantablemodel"
"qt/bitcoingui -> qt/utilitydialog -> qt/bitcoingui"
@@ -26,19 +24,13 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel"
"qt/walletmodel -> qt/walletmodeltransaction -> qt/walletmodel"
"txmempool -> validation -> txmempool"
- "validation -> validationinterface -> validation"
"wallet/coincontrol -> wallet/wallet -> wallet/coincontrol"
"wallet/fees -> wallet/wallet -> wallet/fees"
"wallet/wallet -> wallet/walletdb -> wallet/wallet"
- "policy/fees -> policy/policy -> validation -> policy/fees"
- "policy/rbf -> txmempool -> validation -> policy/rbf"
- "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/addressbookpage"
+ "policy/fees -> txmempool -> validation -> policy/fees"
"qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/guiutil"
"txmempool -> validation -> validationinterface -> txmempool"
- "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/receivecoinsdialog -> qt/addressbookpage"
- "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/signverifymessagedialog -> qt/addressbookpage"
- "qt/guiutil -> qt/walletmodel -> qt/optionsmodel -> qt/intro -> qt/guiutil"
- "qt/addressbookpage -> qt/bitcoingui -> qt/walletview -> qt/sendcoinsdialog -> qt/sendcoinsentry -> qt/addressbookpage"
+ "wallet/ismine -> wallet/wallet -> wallet/ismine"
)
EXIT_CODE=0
diff --git a/test/lint/lint-format-strings.py b/test/lint/lint-format-strings.py
index f5d4780b6d..224e62f04a 100755
--- a/test/lint/lint-format-strings.py
+++ b/test/lint/lint-format-strings.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (c) 2018 The Bitcoin Core developers
+# 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.
#
@@ -39,7 +39,7 @@ def parse_function_calls(function_name, source_code):
>>> len(parse_function_calls("foo", "#define FOO foo();"))
0
"""
- assert(type(function_name) is str and type(source_code) is str and function_name)
+ assert type(function_name) is str and type(source_code) is str and function_name
lines = [re.sub("// .*", " ", line).strip()
for line in source_code.split("\n")
if not line.strip().startswith("#")]
@@ -53,7 +53,7 @@ def normalize(s):
>>> normalize(" /* nothing */ foo\tfoo /* bar */ foo ")
'foo foo foo'
"""
- assert(type(s) is str)
+ assert type(s) is str
s = s.replace("\n", " ")
s = s.replace("\t", " ")
s = re.sub("/\*.*?\*/", " ", s)
@@ -77,7 +77,7 @@ def escape(s):
>>> escape(r'foo \\t foo \\n foo \\\\ foo \\ foo \\"bar\\"')
'foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\ foo \\\\ foo [escaped-quote]bar[escaped-quote]'
"""
- assert(type(s) is str)
+ assert type(s) is str
for raw_value, escaped_value in ESCAPE_MAP.items():
s = s.replace(raw_value, escaped_value)
return s
@@ -92,7 +92,7 @@ def unescape(s):
>>> unescape("foo [escaped-tab] foo [escaped-newline] foo \\\\\\\\ foo \\\\ foo [escaped-quote]bar[escaped-quote]")
'foo \\\\t foo \\\\n foo \\\\\\\\ foo \\\\ foo \\\\"bar\\\\"'
"""
- assert(type(s) is str)
+ assert type(s) is str
for raw_value, escaped_value in ESCAPE_MAP.items():
s = s.replace(escaped_value, raw_value)
return s
@@ -151,10 +151,10 @@ def parse_function_call_and_arguments(function_name, function_call):
>>> parse_function_call_and_arguments("strprintf", 'strprintf("%s (%d)", foo>foo<1,2>(1,2),err)');
['strprintf(', '"%s (%d)",', ' foo>foo<1,2>(1,2),', 'err', ')']
"""
- assert(type(function_name) is str and type(function_call) is str and function_name)
+ assert type(function_name) is str and type(function_call) is str and function_name
remaining = normalize(escape(function_call))
expected_function_call = "{}(".format(function_name)
- assert(remaining.startswith(expected_function_call))
+ assert remaining.startswith(expected_function_call)
parts = [expected_function_call]
remaining = remaining[len(expected_function_call):]
open_parentheses = 1
@@ -213,7 +213,7 @@ def parse_string_content(argument):
>>> parse_string_content('1 2 3')
''
"""
- assert(type(argument) is str)
+ assert type(argument) is str
string_content = ""
in_string = False
for char in normalize(escape(argument)):
@@ -240,7 +240,7 @@ def count_format_specifiers(format_string):
>>> count_format_specifiers("foo %d bar %i foo %% foo %*d foo")
4
"""
- assert(type(format_string) is str)
+ assert type(format_string) is str
format_string = format_string.replace('%%', 'X')
n = 0
in_specifier = False
@@ -262,27 +262,27 @@ def main():
parser.add_argument("--skip-arguments", type=int, help="number of arguments before the format string "
"argument (e.g. 1 in the case of fprintf)", default=0)
parser.add_argument("function_name", help="function name (e.g. fprintf)", default=None)
- parser.add_argument("file", type=argparse.FileType("r", encoding="utf-8"), nargs="*", help="C++ source code file (e.g. foo.cpp)")
+ parser.add_argument("file", nargs="*", help="C++ source code file (e.g. foo.cpp)")
args = parser.parse_args()
-
exit_code = 0
- for f in args.file:
- for function_call_str in parse_function_calls(args.function_name, f.read()):
- parts = parse_function_call_and_arguments(args.function_name, function_call_str)
- relevant_function_call_str = unescape("".join(parts))[:512]
- if (f.name, relevant_function_call_str) in FALSE_POSITIVES:
- continue
- if len(parts) < 3 + args.skip_arguments:
- exit_code = 1
- print("{}: Could not parse function call string \"{}(...)\": {}".format(f.name, args.function_name, relevant_function_call_str))
- continue
- argument_count = len(parts) - 3 - args.skip_arguments
- format_str = parse_string_content(parts[1 + args.skip_arguments])
- format_specifier_count = count_format_specifiers(format_str)
- if format_specifier_count != argument_count:
- exit_code = 1
- print("{}: Expected {} argument(s) after format string but found {} argument(s): {}".format(f.name, format_specifier_count, argument_count, relevant_function_call_str))
- continue
+ for filename in args.file:
+ with open(filename, "r", encoding="utf-8") as f:
+ for function_call_str in parse_function_calls(args.function_name, f.read()):
+ parts = parse_function_call_and_arguments(args.function_name, function_call_str)
+ relevant_function_call_str = unescape("".join(parts))[:512]
+ if (f.name, relevant_function_call_str) in FALSE_POSITIVES:
+ continue
+ if len(parts) < 3 + args.skip_arguments:
+ exit_code = 1
+ print("{}: Could not parse function call string \"{}(...)\": {}".format(f.name, args.function_name, relevant_function_call_str))
+ continue
+ argument_count = len(parts) - 3 - args.skip_arguments
+ format_str = parse_string_content(parts[1 + args.skip_arguments])
+ format_specifier_count = count_format_specifiers(format_str)
+ if format_specifier_count != argument_count:
+ exit_code = 1
+ print("{}: Expected {} argument(s) after format string but found {} argument(s): {}".format(f.name, format_specifier_count, argument_count, relevant_function_call_str))
+ continue
sys.exit(exit_code)
diff --git a/test/lint/lint-format-strings.sh b/test/lint/lint-format-strings.sh
index c994ae3f4d..cb630c78ad 100755
--- a/test/lint/lint-format-strings.sh
+++ b/test/lint/lint-format-strings.sh
@@ -13,6 +13,7 @@ export LC_ALL=C
FUNCTION_NAMES_AND_NUMBER_OF_LEADING_ARGUMENTS=(
"FatalError,0"
"fprintf,1"
+ "tfm::format,1" # Assuming tfm::::format(std::ostream&, ...
"LogConnectFailure,1"
"LogPrint,1"
"LogPrintf,0"
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index 2b6c78c2c8..9a1aa766f7 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -8,7 +8,6 @@ KNOWN_VIOLATIONS=(
"src/dbwrapper.cpp:.*vsnprintf"
"src/httprpc.cpp.*trim"
"src/init.cpp:.*atoi"
- "src/init.cpp:.*fprintf"
"src/qt/rpcconsole.cpp:.*atoi"
"src/rest.cpp:.*strtol"
"src/test/dbwrapper_tests.cpp:.*snprintf"
@@ -85,7 +84,7 @@ LOCALE_DEPENDENT_FUNCTIONS=(
mbtowc # LC_CTYPE
mktime
normalize # boost::locale::normalize
-# printf # LC_NUMERIC
+ printf # LC_NUMERIC
putwc
putwchar
scanf # LC_NUMERIC
@@ -189,8 +188,7 @@ GIT_GREP_OUTPUT=$(git grep -E "[^a-zA-Z0-9_\`'\"<>](${REGEXP_LOCALE_DEPENDENT_FU
EXIT_CODE=0
for LOCALE_DEPENDENT_FUNCTION in "${LOCALE_DEPENDENT_FUNCTIONS[@]}"; do
MATCHES=$(grep -E "[^a-zA-Z0-9_\`'\"<>]${LOCALE_DEPENDENT_FUNCTION}(_r|_s)?[^a-zA-Z0-9_\`'\"<>]" <<< "${GIT_GREP_OUTPUT}" | \
- grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}" | \
- grep -vE 'fprintf\(.*(stdout|stderr)')
+ grep -vE "\.(c|cpp|h):\s*(//|\*|/\*|\").*${LOCALE_DEPENDENT_FUNCTION}")
if [[ ${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES} != "" ]]; then
MATCHES=$(grep -vE "${REGEXP_IGNORE_EXTERNAL_DEPENDENCIES}" <<< "${MATCHES}")
fi
diff --git a/test/lint/lint-python-dead-code.sh b/test/lint/lint-python-dead-code.sh
index 863caa9d5c..588ba428d7 100755
--- a/test/lint/lint-python-dead-code.sh
+++ b/test/lint/lint-python-dead-code.sh
@@ -15,5 +15,5 @@ fi
vulture \
--min-confidence 60 \
- --ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,get_ecdh_key,get_privkey,is_compressed,is_fullyvalid,msg_generic,on_*,optionxform,restype,set_privkey,profile_with_perf" \
+ --ignore-names "argtypes,connection_lost,connection_made,converter,data_received,daemon,errcheck,is_compressed,is_valid,verify_ecdsa,msg_generic,on_*,optionxform,restype,profile_with_perf" \
$(git ls-files -- "*.py" ":(exclude)contrib/" ":(exclude)test/functional/data/invalid_txs.py")
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index f5b851aeab..a76806003f 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -90,4 +90,10 @@ elif PYTHONWARNINGS="ignore" flake8 --version | grep -q "Python 2"; then
exit 0
fi
-PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") "${@:-.}"
+PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; echo "${enabled[*]}") $(
+ if [[ $# == 0 ]]; then
+ git ls-files "*.py"
+ else
+ echo "$@"
+ fi
+)
diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt
index f0415443db..a25de2435b 100644
--- a/test/lint/lint-spelling.ignore-words.txt
+++ b/test/lint/lint-spelling.ignore-words.txt
@@ -5,3 +5,10 @@ mut
objext
unselect
useable
+wit
+unparseable
+copyable
+cachable
+errorstring
+keyserver
+homogenous
diff --git a/test/sanitizer_suppressions/lsan b/test/sanitizer_suppressions/lsan
index 6f15c0f1d4..90a92a5115 100644
--- a/test/sanitizer_suppressions/lsan
+++ b/test/sanitizer_suppressions/lsan
@@ -4,3 +4,6 @@ leak:libqminimal
leak:libQt5Core
leak:libQt5Gui
leak:libQt5Widgets
+
+# false-positive due to use of secure_allocator<>
+leak:GetRNGState
diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan
index d55119b266..643272de52 100644
--- a/test/sanitizer_suppressions/ubsan
+++ b/test/sanitizer_suppressions/ubsan
@@ -15,6 +15,7 @@ unsigned-integer-overflow:coded_stream.h
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