diff options
37 files changed, 595 insertions, 129 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 84cd596bbd..d7ce2224e9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -55,5 +55,5 @@ test_script: - ps: src\bench_bitcoin.exe -evals=1 -scaling=0 - ps: python test\util\bitcoin-util-test.py - cmd: python test\util\rpcauth-test.py -- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude "wallet_multiwallet,wallet_multiwallet.py --usecli" +- cmd: python test\functional\test_runner.py --force --quiet --combinedlogslen=4000 --exclude wallet_multiwallet deploy: off diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..00d5478c4e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ +Pull requests without a rationale and clear improvement may be closed +immediately. + +Please provide clear motivation for your patch and explain how it improves +Bitcoin Core user experience or Bitcoin Core developer experience +significantly. + +* Any test improvements or new tests that improve coverage are always welcome. +* All other changes should have accompanying unit tests (see `src/test/`) or + functional tests (see `test/`). Contributors should note which tests cover + modified code. If no tests exist for a region of modified code, new tests + should accompany the change. +* Bug fixes are most welcome when they come with steps to reproduce or an + explanation of the potential issue as well as reasoning for the way the bug + was fixed. +* Features are welcome, but might be rejected due to design or scope issues. + If a feature is based on a lot of dependencies, contributors should first + consider building the system outside of Bitcoin Core, if possible. +* Refactoring changes are only accepted if they are required for a feature or + bug fix or otherwise improve developer experience significantly. For example, + most "code style" refactoring changes require a thorough explanation why they + are useful, what downsides they have and why they *significantly* improve + developer experience or avoid serious programming bugs. Note that code style + is often a subjective matter. Unless they are explicitly mentioned to be + preferred in the [developer notes](/doc/developer-notes.md), stylistic code + changes are usually rejected. + +Bitcoin Core has a thorough review process and even the most trivial change +needs to pass a lot of eyes and requires non-zero or even substantial time +effort to review. There is a huge lack of active reviewers on the project, so +patches often sit for a long time. diff --git a/configure.ac b/configure.ac index 4d84aacce1..72bd785e2e 100644 --- a/configure.ac +++ b/configure.ac @@ -406,6 +406,18 @@ AC_ARG_WITH([utils], [build_bitcoin_utils=$withval], [build_bitcoin_utils=yes]) +AC_ARG_ENABLE([util-cli], + [AS_HELP_STRING([--enable-util-cli], + [build bitcoin-cli])], + [build_bitcoin_cli=$enableval], + [build_bitcoin_cli=$build_bitcoin_utils]) + +AC_ARG_ENABLE([util-tx], + [AS_HELP_STRING([--enable-util-tx], + [build bitcoin-tx])], + [build_bitcoin_tx=$enableval], + [build_bitcoin_tx=$build_bitcoin_utils]) + AC_ARG_WITH([libs], [AS_HELP_STRING([--with-libs], [build libraries (default=yes)])], @@ -886,7 +898,7 @@ BITCOIN_QT_INIT dnl sets $bitcoin_enable_qt, $bitcoin_enable_qt_test, $bitcoin_enable_qt_dbus BITCOIN_QT_CONFIGURE([$use_pkgconfig]) -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then +if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then use_boost=no else use_boost=yes @@ -1074,7 +1086,7 @@ if test x$use_pkgconfig = xyes; then if test x$use_qr != xno; then BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) fi - if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then + if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests != xnonononono; then PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)]) if test x$TARGET_OS != xwindows; then PKG_CHECK_MODULES([EVENT_PTHREADS], [libevent_pthreads],, [AC_MSG_ERROR(libevent_pthreads not found.)]) @@ -1099,7 +1111,7 @@ else AC_CHECK_HEADER([openssl/ssl.h],, AC_MSG_ERROR(libssl headers missing),) AC_CHECK_LIB([ssl], [main],SSL_LIBS=-lssl, AC_MSG_ERROR(libssl missing)) - if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then + if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests != xnonononono; then AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),) AC_CHECK_LIB([event],[main],EVENT_LIBS=-levent,AC_MSG_ERROR(libevent missing)) if test x$TARGET_OS != xwindows; then @@ -1164,7 +1176,7 @@ dnl univalue check need_bundled_univalue=yes -if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnonononono; then +if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoind$bitcoin_enable_qt$use_tests$use_bench = xnononononono; then need_bundled_univalue=no else @@ -1214,9 +1226,13 @@ AC_MSG_CHECKING([whether to build bitcoind]) AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes]) AC_MSG_RESULT($build_bitcoind) -AC_MSG_CHECKING([whether to build utils (bitcoin-cli bitcoin-tx)]) -AM_CONDITIONAL([BUILD_BITCOIN_UTILS], [test x$build_bitcoin_utils = xyes]) -AC_MSG_RESULT($build_bitcoin_utils) +AC_MSG_CHECKING([whether to build bitcoin-cli]) +AM_CONDITIONAL([BUILD_BITCOIN_CLI], [test x$build_bitcoin_cli = xyes]) +AC_MSG_RESULT($build_bitcoin_cli) + +AC_MSG_CHECKING([whether to build bitcoin-tx]) +AM_CONDITIONAL([BUILD_BITCOIN_TX], [test x$build_bitcoin_tx = xyes]) +AC_MSG_RESULT($build_bitcoin_tx) AC_MSG_CHECKING([whether to build libraries]) AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test x$build_bitcoin_libs = xyes]) @@ -1342,7 +1358,7 @@ else AC_MSG_RESULT([no]) fi -if test x$build_bitcoin_utils$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnononononono; then +if test x$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$use_bench$use_tests = xnonononononono; then AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-bench or --enable-tests]) fi diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 5286f89c30..d15f147cd7 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -120,6 +120,7 @@ define $(package)_extract_cmds endef define $(package)_preprocess_cmds + sed -i.old "s|FT_Get_Font_Format|FT_Get_X11_Font_Format|" qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp && \ sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ 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 && \ diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 08ff4d6ac1..9b36319e64 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -8,6 +8,10 @@ if ENABLE_QT dist_man1_MANS+=bitcoin-qt.1 endif -if BUILD_BITCOIN_UTILS - dist_man1_MANS+=bitcoin-cli.1 bitcoin-tx.1 +if BUILD_BITCOIN_CLI + dist_man1_MANS+=bitcoin-cli.1 +endif + +if BUILD_BITCOIN_TX + dist_man1_MANS+=bitcoin-tx.1 endif diff --git a/doc/release-notes-14282.md b/doc/release-notes-14282.md new file mode 100644 index 0000000000..e6d8e0b70c --- /dev/null +++ b/doc/release-notes-14282.md @@ -0,0 +1,6 @@ +Low-level RPC changes +---------------------- + +`-usehd` was removed in version 0.16. From that version onwards, all new +wallets created are hierarchical deterministic wallets. Version 0.18 makes +specifying `-usehd` invalid config. diff --git a/doc/release-notes/release-notes-0.14.3.md b/doc/release-notes/release-notes-0.14.3.md new file mode 100644 index 0000000000..8259152f0b --- /dev/null +++ b/doc/release-notes/release-notes-0.14.3.md @@ -0,0 +1,118 @@ +Bitcoin Core version *0.14.3* is now available from: + + <https://bitcoin.org/bin/bitcoin-core-0.14.3/> + +This is a new minor version release, including various bugfixes and +performance improvements. + +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/> + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. + +Microsoft ended support for Windows XP on [April 8th, 2014](https://www.microsoft.com/en-us/WindowsForBusiness/end-of-xp-support), +No attempt is made to prevent installing or running the software on Windows XP, you +can still do so at your own risk but be aware that there are known instabilities and issues. +Please do not report issues about Windows XP to the issue tracker. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + +Notable changes +=============== + +Denial-of-Service vulnerability CVE-2018-17144 + ------------------------------- + +A denial-of-service vulnerability exploitable by miners has been discovered in +Bitcoin Core versions 0.14.0 up to 0.16.2. It is recommended to upgrade any of +the vulnerable versions to 0.14.3, 0.15.2 or 0.16.3 as soon as possible. + +Known Bugs +========== + +Since 0.14.0 the approximate transaction fee shown in Bitcoin-Qt when using coin +control and smart fee estimation does not reflect any change in target from the +smart fee slider. It will only present an approximate fee calculated using the +default target. The fee calculated using the correct target is still applied to +the transaction and shown in the final send confirmation dialog. + +0.14.3 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, refactors and string updates. For convenience in locating +the code changes and accompanying discussion, both the pull request and +git merge commit are mentioned. + +### Consensus +- #14247 `52965fb` Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar) + +### RPC and other APIs + +- #10445 `87a21d5` Fix: make CCoinsViewDbCursor::Seek work for missing keys (Pieter Wuille, Gregory Maxwell) +- #9853 Return correct error codes in setban(), fundrawtransaction(), removeprunedfunds(), bumpfee(), blockchain.cpp (John Newbery) + + +### P2P protocol and network code + +- #10234 `d289b56` [net] listbanned RPC and QT should show correct banned subnets (John Newbery) + +### Build system + + +### Miscellaneous + +- #10451 `3612219` contrib/init/bitcoind.openrcconf: Don't disable wallet by default (Luke Dashjr) +- #10250 `e23cef0` Fix some empty vector references (Pieter Wuille) +- #10196 `d28d583` PrioritiseTransaction updates the mempool tx counter (Suhas Daftuar) +- #9497 `e207342` Fix CCheckQueue IsIdle (potential) race condition and remove dangerous constructors. (Jeremy Rubin) + +### GUI + +- #9481 `7abe7bb` Give fallback fee a reasonable indent (Luke Dashjr) +- #9481 `3e4d7bf` Qt/Send: Figure a decent warning colour from theme (Luke Dashjr) +- #9481 `e207342` Show more significant warning if we fall back to the default fee (Jonas Schnelli) + +### Wallet + +- #10308 `28b8b8b` Securely erase potentially sensitive keys/values (tjps) +- #10265 `ff13f59` Make sure pindex is non-null before possibly referencing in LogPrintf call. (Karl-Johan Alm) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- Cory Fields +- CryptAxe +- fanquake +- Jeremy Rubin +- John Newbery +- Jonas Schnelli +- Gregory Maxwell +- Karl-Johan Alm +- Luke Dashjr +- MarcoFalke +- Matt Corallo +- Mikerah +- Pieter Wuille +- practicalswift +- Suhas Daftuar +- Thomas Snider +- Tjps +- Wladimir J. van der Laan + +And to those that reported security issues: + +- awemany (for CVE-2018-17144, previously credited as "anonymous reporter") + diff --git a/doc/release-notes/release-notes-0.15.2.md b/doc/release-notes/release-notes-0.15.2.md new file mode 100644 index 0000000000..1f58279051 --- /dev/null +++ b/doc/release-notes/release-notes-0.15.2.md @@ -0,0 +1,118 @@ +Bitcoin Core version *0.15.2* is now available from: + + <https://bitcoincore.org/bin/bitcoin-core-0.15.2/> + +This is a new minor version release, including various bugfixes and +performance improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + <https://github.com/bitcoin/bitcoin/issues> + +To receive security and update notifications, please subscribe to: + + <https://bitcoincore.org/en/list/announcements/join/> + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes for older versions), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on Mac) +or `bitcoind`/`bitcoin-qt` (on Linux). + +The first time you run version 0.15.0 or higher, your chainstate database will +be converted to a new format, which will take anywhere from a few minutes to +half an hour, depending on the speed of your machine. + +The file format of `fee_estimates.dat` changed in version 0.15.0. Hence, a +downgrade from version 0.15 or upgrade to version 0.15 will cause all fee +estimates to be discarded. + +Note that the block database format also changed in version 0.8.0 and there is no +automatic upgrade code from before version 0.8 to version 0.15.0. Upgrading +directly from 0.7.x and earlier without redownloading the blockchain is not supported. +However, as usual, old wallet versions are still supported. + +Downgrading warning +------------------- + +The chainstate database for this release is not compatible with previous +releases, so if you run 0.15 and then decide to switch back to any +older version, you will need to run the old release with the `-reindex-chainstate` +option to rebuild the chainstate data structures in the old format. + +If your node has pruning enabled, this will entail re-downloading and +processing the entire blockchain. + +Compatibility +============== + +Bitcoin Core is extensively tested on multiple operating systems using +the Linux kernel, macOS 10.8+, and Windows Vista and later. Windows XP is not supported. + +Bitcoin Core should also work on most other Unix-like systems but is not +frequently tested on them. + + +Notable changes +=============== + +Denial-of-Service vulnerability CVE-2018-17144 +------------------------------- + +A denial-of-service vulnerability exploitable by miners has been discovered in +Bitcoin Core versions 0.14.0 up to 0.16.2. It is recommended to upgrade any of +the vulnerable versions to 0.15.2 or 0.16.3 as soon as possible. + +0.15.2 Change log +================= + +### Build system + +- #11995 `9bb1a16` depends: Fix Qt build with XCode 9.2(fanquake) +- #12946 `93b9a61` depends: Fix Qt build with XCode 9.3(fanquake) +- #13544 `9fd3e00` depends: Update Qt download url (fanquake) +- #11847 `cb7ef31` Make boost::multi_index comparators const (sdaftuar) + +### Consensus +- #14247 `4b8a3f5` Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar) + +### RPC +- #11676 `7af2457` contrib/init: Update openrc-run filename (Luke Dashjr) +- #11277 `7026845` Fix uninitialized URI in batch RPC requests (Russell Yanofsky) + +### Wallet +- #11289 `3f1db56` Wrap dumpwallet warning and note scripts aren't dumped (MeshCollider) +- #11289 `42ea47d` Add wallet backup text to import*, add* and dumpwallet RPCs (MeshCollider) +- #11590 `6372a75` [Wallet] always show help-line of wallet encryption calls (Jonas Schnelli) + +### bitcoin-tx + +- #11554 `a69cc07` Sanity-check script sizes in bitcoin-tx (TheBlueMatt) + +### Tests +- #11277 `3a6cdd4` Add test for multiwallet batch RPC calls (Russell Yanofsky) +- #11647 `1c8c7f8` Add missing batch rpc calls to python coverage logs (Russell Yanofsky) +- #11277 `1036c43` Add missing multiwallet rpc calls to python coverage logs (Russell Yanofsky) +- #11277 `305f768` Limit AuthServiceProxyWrapper.\_\_getattr\_\_ wrapping (Russell Yanofsky) +- #11277 `2eea279` Make AuthServiceProxy.\_batch method usable (Russell Yanofsky) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- fanquake +- Jonas Schnelli +- Luke Dashjr +- Matt Corallo +- MeshCollider +- Russell Yanofsky +- Suhas Daftuar +- Wladimir J. van der Laan + +And to those that reported security issues: + +- awemany (for CVE-2018-17144, previously credited as "anonymous reporter") + diff --git a/src/Makefile.am b/src/Makefile.am index a1b9b4cb82..7a2e9fa5e8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,8 +83,11 @@ if BUILD_BITCOIND bin_PROGRAMS += bitcoind endif -if BUILD_BITCOIN_UTILS - bin_PROGRAMS += bitcoin-cli bitcoin-tx +if BUILD_BITCOIN_CLI + bin_PROGRAMS += bitcoin-cli +endif +if BUILD_BITCOIN_TX + bin_PROGRAMS += bitcoin-tx endif .PHONY: FORCE check-symbols check-security diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 269a6ff805..8a537ed4f6 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -174,8 +174,10 @@ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: $(BITCOIN_TESTS:.cpp=.cpp.test) +if BUILD_BITCOIN_TX @echo "Running test/util/bitcoin-util-test.py..." $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py +endif @echo "Running test/util/rpcauth-test.py..." $(PYTHON) $(top_builddir)/test/util/rpcauth-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check diff --git a/src/amount.h b/src/amount.h index 2bd367cba2..449fd1b15f 100644 --- a/src/amount.h +++ b/src/amount.h @@ -12,7 +12,6 @@ typedef int64_t CAmount; static const CAmount COIN = 100000000; -static const CAmount CENT = 1000000; /** No amount larger than this (in satoshi) is valid. * diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index db303eeead..b8d82c0a89 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -12,8 +12,8 @@ // FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp. // // Helper: create two dummy transactions, each with -// two outputs. The first has 11 and 50 CENT outputs -// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs +// two outputs. The first has 11 and 50 COIN outputs +// paid to a TX_PUBKEY, the second 21 and 22 COIN outputs // paid to a TX_PUBKEYHASH. // static std::vector<CMutableTransaction> @@ -31,16 +31,16 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) // Create some dummy input transactions dummyTransactions[0].vout.resize(2); - dummyTransactions[0].vout[0].nValue = 11 * CENT; + dummyTransactions[0].vout[0].nValue = 11 * COIN; dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - dummyTransactions[0].vout[1].nValue = 50 * CENT; + dummyTransactions[0].vout[1].nValue = 50 * COIN; dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG; AddCoins(coinsRet, dummyTransactions[0], 0); dummyTransactions[1].vout.resize(2); - dummyTransactions[1].vout[0].nValue = 21 * CENT; + dummyTransactions[1].vout[0].nValue = 21 * COIN; dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); - dummyTransactions[1].vout[1].nValue = 22 * CENT; + dummyTransactions[1].vout[1].nValue = 22 * COIN; dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); AddCoins(coinsRet, dummyTransactions[1], 0); @@ -72,7 +72,7 @@ static void CCoinsCaching(benchmark::State& state) t1.vin[2].prevout.n = 1; t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4); t1.vout.resize(2); - t1.vout[0].nValue = 90 * CENT; + t1.vout[0].nValue = 90 * COIN; t1.vout[0].scriptPubKey << OP_1; // Benchmark. @@ -80,7 +80,7 @@ static void CCoinsCaching(benchmark::State& state) bool success = AreInputsStandard(t1, coins); assert(success); CAmount value = coins.GetValueIn(t1); - assert(value == (50 + 21 + 22) * CENT); + assert(value == (50 + 21 + 22) * COIN); } } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 9ee3e8eee7..a3fcb87675 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -240,10 +240,10 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu throw std::runtime_error("TX input missing separator"); // extract and validate TXID - std::string strTxid = vStrInputParts[0]; - if ((strTxid.size() != 64) || !IsHex(strTxid)) + uint256 txid; + if (!ParseHashStr(vStrInputParts[0], txid)) { throw std::runtime_error("invalid TX input txid"); - uint256 txid(uint256S(strTxid)); + } static const unsigned int minTxOutSz = 9; static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz); @@ -590,7 +590,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) if (!prevOut.checkObject(types)) throw std::runtime_error("prevtxs internal object typecheck fail"); - uint256 txid = ParseHashStr(prevOut["txid"].get_str(), "txid"); + uint256 txid; + if (!ParseHashStr(prevOut["txid"].get_str(), txid)) { + throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')"); + } const int nOut = prevOut["vout"].get_int(); if (nOut < 0) diff --git a/src/core_io.h b/src/core_io.h index d53a45c0cb..2c3b64d81e 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -25,7 +25,16 @@ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDeco bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true); bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); -uint256 ParseHashStr(const std::string&, const std::string& strName); + +/** + * Parse a hex string into 256 bits + * @param[in] strHex a hex-formatted, 64-character string + * @param[out] result the result of the parasing + * @returns true if successful, false if not + * + * @see ParseHashV for an RPC-oriented version of this + */ +bool ParseHashStr(const std::string& strHex, uint256& result); std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error); int ParseSighashString(const UniValue& sighash); diff --git a/src/core_read.cpp b/src/core_read.cpp index b02016c014..301f99bc1c 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -193,14 +193,13 @@ bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, return true; } -uint256 ParseHashStr(const std::string& strHex, const std::string& strName) +bool ParseHashStr(const std::string& strHex, uint256& result) { - if (!IsHex(strHex)) // Note: IsHex("") is false - throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); + if ((strHex.size() != 64) || !IsHex(strHex)) + return false; - uint256 result; result.SetHex(strHex); - return result; + return true; } std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName) diff --git a/src/init.cpp b/src/init.cpp index 00d97629f7..f9efaf7dc1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -323,7 +323,7 @@ void SetupServerArgs() // Hidden Options std::vector<std::string> hidden_args = {"-h", "-help", - "-dbcrashratio", "-forcecompactdb", "-usehd", + "-dbcrashratio", "-forcecompactdb", // GUI args. These will be overwritten by SetupUIArgs for the GUI "-allowselfsignedrootcertificates", "-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-rootcertificates=<file>", "-splash", "-uiplatform"}; @@ -149,6 +149,7 @@ public: nLocalServices = connOptions.nLocalServices; nMaxConnections = connOptions.nMaxConnections; nMaxOutbound = std::min(connOptions.nMaxOutbound, connOptions.nMaxConnections); + m_use_addrman_outgoing = connOptions.m_use_addrman_outgoing; nMaxAddnode = connOptions.nMaxAddnode; nMaxFeeler = connOptions.nMaxFeeler; nBestHeight = connOptions.nBestHeight; @@ -174,6 +175,7 @@ public: void Stop(); void Interrupt(); bool GetNetworkActive() const { return fNetworkActive; }; + bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; void SetNetworkActive(bool active); void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false); bool CheckIncomingNonce(uint64_t nonce); @@ -416,6 +418,7 @@ private: int nMaxOutbound; int nMaxAddnode; int nMaxFeeler; + bool m_use_addrman_outgoing; std::atomic<int> nBestHeight; CClientUIInterface* clientInterface; NetEventsInterface* m_msgproc; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b48a3bd221..a1b6e021ae 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3144,8 +3144,6 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) NodeId worst_peer = -1; int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max(); - LOCK(cs_main); - connman->ForEachNode([&](CNode* pnode) { AssertLockHeld(cs_main); @@ -3193,6 +3191,8 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams) { + LOCK(cs_main); + if (connman == nullptr) return; int64_t time_in_seconds = GetTime(); @@ -3200,10 +3200,9 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params EvictExtraOutboundPeers(time_in_seconds); if (time_in_seconds > m_stale_tip_check_time) { - LOCK(cs_main); // Check whether our tip is stale, and if so, allow using an extra // outbound peer - if (TipMayBeStale(consensusParams)) { + if (!fImporting && !fReindex && connman->GetNetworkActive() && connman->GetUseAddrmanOutgoing() && TipMayBeStale(consensusParams)) { LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update); connman->SetTryNewOutboundPeer(true); } else if (connman->GetTryNewOutboundPeer()) { diff --git a/src/net_processing.h b/src/net_processing.h index 04904399dd..0113e25f7e 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -9,6 +9,9 @@ #include <net.h> #include <validationinterface.h> #include <consensus/params.h> +#include <sync.h> + +extern CCriticalSection cs_main; /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; @@ -65,7 +68,7 @@ public: /** Evict extra outbound peers. If we think our tip may be stale, connect to an extra outbound */ void CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams); /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ - void EvictExtraOutboundPeers(int64_t time_in_seconds); + void EvictExtraOutboundPeers(int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); private: int64_t m_stale_tip_check_time; //!< Next time to check for stale tip diff --git a/src/rest.cpp b/src/rest.cpp index 7792844992..1850c0b7a6 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -105,15 +105,6 @@ static std::string AvailableDataFormatsString() return formats; } -static bool ParseHashStr(const std::string& strReq, uint256& v) -{ - if (!IsHex(strReq) || (strReq.size() != 64)) - return false; - - v.SetHex(strReq); - return true; -} - static bool CheckWarmup(HTTPRequest* req) { std::string statusmessage; diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp index 773de343ea..4941ebd483 100644 --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -114,7 +114,8 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) unsigned int pos = 0; /*int block_height =*/ test[pos++].get_int(); - /*uint256 block_hash =*/ ParseHashStr(test[pos++].get_str(), "block_hash"); + uint256 block_hash; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), block_hash)); CBlock block; BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str())); @@ -129,9 +130,11 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test) tx_undo.vprevout.emplace_back(txout, 0, false); } - uint256 prev_filter_header_basic = ParseHashStr(test[pos++].get_str(), "prev_filter_header_basic"); + uint256 prev_filter_header_basic; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), prev_filter_header_basic)); std::vector<unsigned char> filter_basic = ParseHex(test[pos++].get_str()); - uint256 filter_header_basic = ParseHashStr(test[pos++].get_str(), "filter_header_basic"); + uint256 filter_header_basic; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), filter_header_basic)); BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo); BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic); diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index b87d9bea5d..3872767133 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -37,6 +37,8 @@ static inline uint64_t InsecureRandBits(int bits) { return insecure_rand_ctx.ran static inline uint64_t InsecureRandRange(uint64_t range) { return insecure_rand_ctx.randrange(range); } static inline bool InsecureRandBool() { return insecure_rand_ctx.randbool(); } +static constexpr CAmount CENT{1000000}; + /** Basic testing setup. * This just configures logging and chain parameters. */ diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index a9af59a11d..326ef9b27a 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -48,7 +48,7 @@ bool ParseMoney(const char* pszIn, CAmount& nRet) if (*p == '.') { p++; - int64_t nMult = CENT*10; + int64_t nMult = COIN / 10; while (isdigit(*p) && (nMult > 0)) { nUnits += nMult * (*p++ - '0'); diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 6d755d0969..5348401f45 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -10,7 +10,7 @@ #include <random.h> //! target minimum change amount -static const CAmount MIN_CHANGE = CENT; +static constexpr CAmount MIN_CHANGE{COIN / 100}; //! final minimum change amount after paying for fees static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index cca50a4ee4..7d0219201e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3109,6 +3109,8 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) // Sign the transaction LOCK2(cs_main, pwallet->cs_wallet); + EnsureWalletIsUnlocked(pwallet); + return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 678d8ddd4d..afe47d986e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3989,10 +3989,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name, if (fFirstRun) { // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key - if (!gArgs.GetBoolArg("-usehd", true)) { - InitError(strprintf(_("Error creating %s: You can't create non-HD wallets with this version."), walletFile)); - return nullptr; - } walletInstance->SetMinVersion(FEATURE_LATEST); if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { @@ -4020,16 +4016,6 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const std::string& name, if (!walletInstance->mapKeys.empty() || !walletInstance->mapCryptedKeys.empty()) { InitWarning(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile)); } - } else if (gArgs.IsArgSet("-usehd")) { - bool useHD = gArgs.GetBoolArg("-usehd", true); - if (walletInstance->IsHDEnabled() && !useHD) { - InitError(strprintf(_("Error loading %s: You can't disable HD on an already existing HD wallet"), walletFile)); - return nullptr; - } - if (!walletInstance->IsHDEnabled() && useHD) { - InitError(strprintf(_("Error loading %s: You can't enable HD on an already existing non-HD wallet"), walletFile)); - return nullptr; - } } if (!gArgs.GetArg("-addresstype", "").empty() && !ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) { diff --git a/test/config.ini.in b/test/config.ini.in index a1119dc739..28abee2a3d 100644 --- a/test/config.ini.in +++ b/test/config.ini.in @@ -14,6 +14,6 @@ RPCAUTH=@abs_top_srcdir@/share/rpcauth/rpcauth.py [components] # Which components are enabled. These are commented out by `configure` if they were disabled when running config. @ENABLE_WALLET_TRUE@ENABLE_WALLET=true -@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true +@BUILD_BITCOIN_CLI_TRUE@ENABLE_CLI=true @BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true @ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true diff --git a/test/functional/README.md b/test/functional/README.md index 6929ab5991..d40052ac93 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -60,6 +60,11 @@ don't have test cases for. - When calling RPCs with lots of arguments, consider using named keyword arguments instead of positional arguments to make the intent of the call clear to readers. +- Many of the core test framework classes such as `CBlock` and `CTransaction` + don't allow new attributes to be added to their objects at runtime like + typical Python objects allow. This helps prevent unpredictable side effects + from typographical errors or usage of the objects outside of their intended + purpose. #### RPC and P2P definitions @@ -72,7 +77,7 @@ P2P messages. These can be found in the following source files: #### Using the P2P interface -- `mininode.py` contains all the definitions for objects that pass +- `messages.py` contains all the definitions for objects that pass over the network (`CBlock`, `CTransaction`, etc, along with the network-level wrappers for them, `msg_block`, `msg_tx`, etc). diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index de12ab1ed6..afbbfa8992 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -205,7 +205,7 @@ class SegWitTest(BitcoinTestFramework): height = self.nodes[0].getblockcount() + 1 block_time = self.nodes[0].getblockheader(tip)["mediantime"] + 1 block = create_block(int(tip, 16), create_coinbase(height), block_time) - block.version = version + block.nVersion = version block.rehash() return block @@ -769,12 +769,16 @@ class SegWitTest(BitcoinTestFramework): # will require a witness to spend a witness program regardless of # segwit activation. Note that older bitcoind's that are not # segwit-aware would also reject this for failing CLEANSTACK. - test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) + with self.nodes[0].assert_debug_log( + expected_msgs=(spend_tx.hash, 'was not accepted: non-mandatory-script-verify-flag (Witness program was passed an empty witness)')): + test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) - # Try to put the witness script in the script_sig, should also fail. - spend_tx.vin[0].script_sig = CScript([p2wsh_pubkey, b'a']) + # Try to put the witness script in the scriptSig, should also fail. + spend_tx.vin[0].scriptSig = CScript([p2wsh_pubkey, b'a']) spend_tx.rehash() - test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) + with self.nodes[0].assert_debug_log( + expected_msgs=('Not relaying invalid transaction {}'.format(spend_tx.hash), 'was not accepted: mandatory-script-verify-flag-failed (Script evaluated without error but finished with a false/empty top stack element)')): + test_transaction_acceptance(self.nodes[0], self.test_node, spend_tx, with_witness=False, accepted=False) # Now put the witness script in the witness, should succeed after # segwit activates. diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 5c07f2ccae..291538df64 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -45,6 +45,14 @@ class SignRawTransactionsTest(BitcoinTestFramework): # 2) No script verification error occurred assert 'errors' not in rawTxSigned + def test_with_lock_outputs(self): + """Test correct error reporting when trying to sign a locked output""" + self.nodes[0].encryptwallet("password") + + rawTx = '020000000156b958f78e3f24e0b2f4e4db1255426b0902027cb37e3ddadb52e37c3557dddb0000000000ffffffff01c0a6b929010000001600149a2ee8c77140a053f36018ac8124a6ececc1668a00000000' + + assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].signrawtransactionwithwallet, rawTx) + def script_verification_error_test(self): """Create and sign a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script. @@ -138,6 +146,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): def run_test(self): self.successful_signing_test() self.script_verification_error_test() + self.test_with_lock_outputs() if __name__ == '__main__': diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 0a3907cba4..8e9372767d 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -13,7 +13,11 @@ CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....: msg_block, msg_tx, msg_headers, etc.: data structures that represent network messages -ser_*, deser_*: functions that handle serialization/deserialization.""" +ser_*, deser_*: functions that handle serialization/deserialization. + +Classes use __slots__ to ensure extraneous attributes aren't accidentally added +by tests, compromising their intended effect. +""" from codecs import encode import copy import hashlib @@ -185,7 +189,10 @@ def ToHex(obj): # Objects that map to bitcoind objects, which can be serialized/deserialized -class CAddress(): + +class CAddress: + __slots__ = ("ip", "nServices", "pchReserved", "port", "time") + def __init__(self): self.time = 0 self.nServices = 1 @@ -215,7 +222,10 @@ class CAddress(): return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices, self.ip, self.port) -class CInv(): + +class CInv: + __slots__ = ("hash", "type") + typemap = { 0: "Error", 1: "TX", @@ -244,7 +254,9 @@ class CInv(): % (self.typemap[self.type], self.hash) -class CBlockLocator(): +class CBlockLocator: + __slots__ = ("nVersion", "vHave") + def __init__(self): self.nVersion = MY_VERSION self.vHave = [] @@ -264,7 +276,9 @@ class CBlockLocator(): % (self.nVersion, repr(self.vHave)) -class COutPoint(): +class COutPoint: + __slots__ = ("hash", "n") + def __init__(self, hash=0, n=0): self.hash = hash self.n = n @@ -283,7 +297,9 @@ class COutPoint(): return "COutPoint(hash=%064x n=%i)" % (self.hash, self.n) -class CTxIn(): +class CTxIn: + __slots__ = ("nSequence", "prevout", "scriptSig") + def __init__(self, outpoint=None, scriptSig=b"", nSequence=0): if outpoint is None: self.prevout = COutPoint() @@ -311,7 +327,9 @@ class CTxIn(): self.nSequence) -class CTxOut(): +class CTxOut: + __slots__ = ("nValue", "scriptPubKey") + def __init__(self, nValue=0, scriptPubKey=b""): self.nValue = nValue self.scriptPubKey = scriptPubKey @@ -332,7 +350,9 @@ class CTxOut(): bytes_to_hex_str(self.scriptPubKey)) -class CScriptWitness(): +class CScriptWitness: + __slots__ = ("stack",) + def __init__(self): # stack is a vector of strings self.stack = [] @@ -347,7 +367,9 @@ class CScriptWitness(): return True -class CTxInWitness(): +class CTxInWitness: + __slots__ = ("scriptWitness",) + def __init__(self): self.scriptWitness = CScriptWitness() @@ -364,7 +386,9 @@ class CTxInWitness(): return self.scriptWitness.is_null() -class CTxWitness(): +class CTxWitness: + __slots__ = ("vtxinwit",) + def __init__(self): self.vtxinwit = [] @@ -392,7 +416,10 @@ class CTxWitness(): return True -class CTransaction(): +class CTransaction: + __slots__ = ("hash", "nLockTime", "nVersion", "sha256", "vin", "vout", + "wit") + def __init__(self, tx=None): if tx is None: self.nVersion = 1 @@ -496,7 +523,10 @@ class CTransaction(): % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) -class CBlockHeader(): +class CBlockHeader: + __slots__ = ("hash", "hashMerkleRoot", "hashPrevBlock", "nBits", "nNonce", + "nTime", "nVersion", "sha256") + def __init__(self, header=None): if header is None: self.set_null() @@ -565,6 +595,8 @@ class CBlockHeader(): class CBlock(CBlockHeader): + __slots__ = ("vtx",) + def __init__(self, header=None): super(CBlock, self).__init__(header) self.vtx = [] @@ -636,7 +668,9 @@ class CBlock(CBlockHeader): time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx)) -class PrefilledTransaction(): +class PrefilledTransaction: + __slots__ = ("index", "tx") + def __init__(self, index=0, tx = None): self.index = index self.tx = tx @@ -664,8 +698,12 @@ class PrefilledTransaction(): def __repr__(self): return "PrefilledTransaction(index=%d, tx=%s)" % (self.index, repr(self.tx)) + # This is what we send on the wire, in a cmpctblock message. -class P2PHeaderAndShortIDs(): +class P2PHeaderAndShortIDs: + __slots__ = ("header", "nonce", "prefilled_txn", "prefilled_txn_length", + "shortids", "shortids_length") + def __init__(self): self.header = CBlockHeader() self.nonce = 0 @@ -703,9 +741,11 @@ class P2PHeaderAndShortIDs(): def __repr__(self): return "P2PHeaderAndShortIDs(header=%s, nonce=%d, shortids_length=%d, shortids=%s, prefilled_txn_length=%d, prefilledtxn=%s" % (repr(self.header), self.nonce, self.shortids_length, repr(self.shortids), self.prefilled_txn_length, repr(self.prefilled_txn)) + # P2P version of the above that will use witness serialization (for compact # block version 2) class P2PHeaderAndShortWitnessIDs(P2PHeaderAndShortIDs): + __slots__ = () def serialize(self): return super(P2PHeaderAndShortWitnessIDs, self).serialize(with_witness=True) @@ -715,9 +755,12 @@ def calculate_shortid(k0, k1, tx_hash): expected_shortid &= 0x0000ffffffffffff return expected_shortid + # This version gets rid of the array lengths, and reinterprets the differential # encoding into indices that can be used for lookup. -class HeaderAndShortIDs(): +class HeaderAndShortIDs: + __slots__ = ("header", "nonce", "prefilled_txn", "shortids", "use_witness") + def __init__(self, p2pheaders_and_shortids = None): self.header = CBlockHeader() self.nonce = 0 @@ -778,7 +821,8 @@ class HeaderAndShortIDs(): return "HeaderAndShortIDs(header=%s, nonce=%d, shortids=%s, prefilledtxn=%s" % (repr(self.header), self.nonce, repr(self.shortids), repr(self.prefilled_txn)) -class BlockTransactionsRequest(): +class BlockTransactionsRequest: + __slots__ = ("blockhash", "indexes") def __init__(self, blockhash=0, indexes = None): self.blockhash = blockhash @@ -818,7 +862,8 @@ class BlockTransactionsRequest(): return "BlockTransactionsRequest(hash=%064x indexes=%s)" % (self.blockhash, repr(self.indexes)) -class BlockTransactions(): +class BlockTransactions: + __slots__ = ("blockhash", "transactions") def __init__(self, blockhash=0, transactions = None): self.blockhash = blockhash @@ -840,7 +885,10 @@ class BlockTransactions(): def __repr__(self): return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions)) -class CPartialMerkleTree(): + +class CPartialMerkleTree: + __slots__ = ("fBad", "nTransactions", "vBits", "vHash") + def __init__(self): self.nTransactions = 0 self.vHash = [] @@ -868,7 +916,10 @@ class CPartialMerkleTree(): def __repr__(self): return "CPartialMerkleTree(nTransactions=%d, vHash=%s, vBits=%s)" % (self.nTransactions, repr(self.vHash), repr(self.vBits)) -class CMerkleBlock(): + +class CMerkleBlock: + __slots__ = ("header", "txn") + def __init__(self): self.header = CBlockHeader() self.txn = CPartialMerkleTree() @@ -888,7 +939,9 @@ class CMerkleBlock(): # Objects that correspond to messages on the wire -class msg_version(): +class msg_version: + __slots__ = ("addrFrom", "addrTo", "nNonce", "nRelay", "nServices", + "nStartingHeight", "nTime", "nVersion", "strSubVer") command = b"version" def __init__(self): @@ -945,7 +998,8 @@ class msg_version(): self.strSubVer, self.nStartingHeight, self.nRelay) -class msg_verack(): +class msg_verack: + __slots__ = () command = b"verack" def __init__(self): @@ -961,7 +1015,8 @@ class msg_verack(): return "msg_verack()" -class msg_addr(): +class msg_addr: + __slots__ = ("addrs",) command = b"addr" def __init__(self): @@ -977,7 +1032,8 @@ class msg_addr(): return "msg_addr(addrs=%s)" % (repr(self.addrs)) -class msg_inv(): +class msg_inv: + __slots__ = ("inv",) command = b"inv" def __init__(self, inv=None): @@ -996,7 +1052,8 @@ class msg_inv(): return "msg_inv(inv=%s)" % (repr(self.inv)) -class msg_getdata(): +class msg_getdata: + __slots__ = ("inv",) command = b"getdata" def __init__(self, inv=None): @@ -1012,7 +1069,8 @@ class msg_getdata(): return "msg_getdata(inv=%s)" % (repr(self.inv)) -class msg_getblocks(): +class msg_getblocks: + __slots__ = ("locator", "hashstop") command = b"getblocks" def __init__(self): @@ -1035,7 +1093,8 @@ class msg_getblocks(): % (repr(self.locator), self.hashstop) -class msg_tx(): +class msg_tx: + __slots__ = ("tx",) command = b"tx" def __init__(self, tx=CTransaction()): @@ -1050,13 +1109,16 @@ class msg_tx(): def __repr__(self): return "msg_tx(tx=%s)" % (repr(self.tx)) + class msg_witness_tx(msg_tx): + __slots__ = () def serialize(self): return self.tx.serialize_with_witness() -class msg_block(): +class msg_block: + __slots__ = ("block",) command = b"block" def __init__(self, block=None): @@ -1074,9 +1136,12 @@ class msg_block(): def __repr__(self): return "msg_block(block=%s)" % (repr(self.block)) + # for cases where a user needs tighter control over what is sent over the wire # note that the user must supply the name of the command, and the data -class msg_generic(): +class msg_generic: + __slots__ = ("command", "data") + def __init__(self, command, data=None): self.command = command self.data = data @@ -1087,13 +1152,16 @@ class msg_generic(): def __repr__(self): return "msg_generic()" -class msg_witness_block(msg_block): +class msg_witness_block(msg_block): + __slots__ = () def serialize(self): r = self.block.serialize(with_witness=True) return r -class msg_getaddr(): + +class msg_getaddr: + __slots__ = () command = b"getaddr" def __init__(self): @@ -1109,7 +1177,8 @@ class msg_getaddr(): return "msg_getaddr()" -class msg_ping(): +class msg_ping: + __slots__ = ("nonce",) command = b"ping" def __init__(self, nonce=0): @@ -1127,7 +1196,8 @@ class msg_ping(): return "msg_ping(nonce=%08x)" % self.nonce -class msg_pong(): +class msg_pong: + __slots__ = ("nonce",) command = b"pong" def __init__(self, nonce=0): @@ -1145,7 +1215,8 @@ class msg_pong(): return "msg_pong(nonce=%08x)" % self.nonce -class msg_mempool(): +class msg_mempool: + __slots__ = () command = b"mempool" def __init__(self): @@ -1160,7 +1231,9 @@ class msg_mempool(): def __repr__(self): return "msg_mempool()" -class msg_sendheaders(): + +class msg_sendheaders: + __slots__ = () command = b"sendheaders" def __init__(self): @@ -1180,7 +1253,8 @@ class msg_sendheaders(): # number of entries # vector of hashes # hash_stop (hash of last desired block header, 0 to get as many as possible) -class msg_getheaders(): +class msg_getheaders: + __slots__ = ("hashstop", "locator",) command = b"getheaders" def __init__(self): @@ -1205,7 +1279,8 @@ class msg_getheaders(): # headers message has # <count> <vector of block headers> -class msg_headers(): +class msg_headers: + __slots__ = ("headers",) command = b"headers" def __init__(self, headers=None): @@ -1225,7 +1300,8 @@ class msg_headers(): return "msg_headers(headers=%s)" % repr(self.headers) -class msg_reject(): +class msg_reject: + __slots__ = ("code", "data", "message", "reason") command = b"reject" REJECT_MALFORMED = 1 @@ -1256,7 +1332,9 @@ class msg_reject(): return "msg_reject: %s %d %s [%064x]" \ % (self.message, self.code, self.reason, self.data) -class msg_feefilter(): + +class msg_feefilter: + __slots__ = ("feerate",) command = b"feefilter" def __init__(self, feerate=0): @@ -1273,7 +1351,9 @@ class msg_feefilter(): def __repr__(self): return "msg_feefilter(feerate=%08x)" % self.feerate -class msg_sendcmpct(): + +class msg_sendcmpct: + __slots__ = ("announce", "version") command = b"sendcmpct" def __init__(self): @@ -1293,7 +1373,9 @@ class msg_sendcmpct(): def __repr__(self): return "msg_sendcmpct(announce=%s, version=%lu)" % (self.announce, self.version) -class msg_cmpctblock(): + +class msg_cmpctblock: + __slots__ = ("header_and_shortids",) command = b"cmpctblock" def __init__(self, header_and_shortids = None): @@ -1311,7 +1393,9 @@ class msg_cmpctblock(): def __repr__(self): return "msg_cmpctblock(HeaderAndShortIDs=%s)" % repr(self.header_and_shortids) -class msg_getblocktxn(): + +class msg_getblocktxn: + __slots__ = ("block_txn_request",) command = b"getblocktxn" def __init__(self): @@ -1329,7 +1413,9 @@ class msg_getblocktxn(): def __repr__(self): return "msg_getblocktxn(block_txn_request=%s)" % (repr(self.block_txn_request)) -class msg_blocktxn(): + +class msg_blocktxn: + __slots__ = ("block_transactions",) command = b"blocktxn" def __init__(self): @@ -1346,7 +1432,10 @@ class msg_blocktxn(): def __repr__(self): return "msg_blocktxn(block_transactions=%s)" % (repr(self.block_transactions)) + class msg_witness_blocktxn(msg_blocktxn): + __slots__ = () + def serialize(self): r = b"" r += self.block_transactions.serialize(with_witness=True) diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 375d6334f7..2fe44010ba 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -26,7 +26,7 @@ def hash160(s): _opcode_instances = [] class CScriptOp(int): """A single script opcode""" - __slots__ = [] + __slots__ = () @staticmethod def encode_op_pushdata(d): @@ -361,8 +361,11 @@ class CScriptTruncatedPushDataError(CScriptInvalidError): self.data = data super(CScriptTruncatedPushDataError, self).__init__(msg) + # This is used, eg, for blockchain heights in coinbase scripts (bip34) -class CScriptNum(): +class CScriptNum: + __slots__ = ("value",) + def __init__(self, d=0): self.value = d @@ -393,6 +396,8 @@ class CScript(bytes): iter(script) however does iterate by opcode. """ + __slots__ = () + @classmethod def __coerce_instance(cls, other): # Coerce other into bytes diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 9a589240a8..97710bd6cd 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -525,7 +525,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): config = configparser.ConfigParser() config.read_file(open(self.options.configfile)) - return config["components"].getboolean("ENABLE_UTILS") + return config["components"].getboolean("ENABLE_CLI") def is_wallet_compiled(self): """Checks whether the wallet module was compiled.""" diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 28437f8925..d9960460d9 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -285,11 +285,13 @@ def main(): # Remove the test cases that the user has explicitly asked to exclude. if args.exclude: - exclude_tests = [re.sub("\.py$", "", test) + (".py" if ".py" not in test else "") for test in args.exclude.split(',')] + exclude_tests = [test.split('.py')[0] for test in args.exclude.split(',')] for exclude_test in exclude_tests: - if exclude_test in test_list: - test_list.remove(exclude_test) - else: + # Remove <test_name>.py and <test_name>.py --arg from the test list + exclude_list = [test for test in test_list if test.split('.py')[0] == exclude_test] + for exclude_item in exclude_list: + test_list.remove(exclude_item) + if not exclude_list: print("{}WARNING!{} Test '{}' not found in current test list.".format(BOLD[1], BOLD[0], exclude_test)) if not test_list: diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 48e71f6c40..eb42531693 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -25,12 +25,6 @@ class WalletHDTest(BitcoinTestFramework): self.skip_if_no_wallet() def run_test(self): - # Make sure can't switch off usehd after wallet creation - self.stop_node(1) - self.nodes[1].assert_start_raises_init_error(['-usehd=0'], "Error: Error loading : You can't disable HD on an already existing HD wallet") - self.start_node(1) - connect_nodes_bi(self.nodes, 0, 1) - # Make sure we use hd, keep masterkeyid masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] assert_equal(masterkeyid, self.nodes[1].getwalletinfo()['hdmasterkeyid']) diff --git a/test/lint/check-doc.py b/test/lint/check-doc.py index 7b056dab32..b0d9f87958 100755 --- a/test/lint/check-doc.py +++ b/test/lint/check-doc.py @@ -22,7 +22,7 @@ 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_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', '-usehd']) +SET_DOC_OPTIONAL = set(['-h', '-help', '-dbcrashratio', '-forcecompactdb']) def main(): diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index f2213f4f2e..761923a818 100644 --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -105,6 +105,30 @@ { "exec": "./bitcoin-tx", "args": ["-create", + "in=Z897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid invalid hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid valid hex but too short" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f12:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid valid hex but too long" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", "replaceable=0foo"], "return_code": 1, @@ -282,6 +306,42 @@ }, { "exec": "./bitcoin-tx", "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not 'Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412')", + "description": "Tests the check for invalid txid due to invalid hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594')", + "description": "Tests the check for invalid txid valid hex, but too short" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512')", + "description": "Tests the check for invalid txid valid hex, but too long" + }, + { "exec": "./bitcoin-tx", + "args": ["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"], "output_cmp": "txcreateoutpubkey1.hex", "description": "Creates a new transaction with a single pay-to-pubkey output" |