diff options
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | .travis.yml | 9 | ||||
-rw-r--r-- | CONTRIBUTING.md | 6 | ||||
-rw-r--r-- | Makefile.am | 76 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | configure.ac | 40 | ||||
-rwxr-xr-x | contrib/devtools/copyright_header.py | 2 | ||||
-rwxr-xr-x | contrib/devtools/github-merge.py | 45 | ||||
-rw-r--r-- | contrib/gitian-descriptors/gitian-win.yml | 9 | ||||
-rwxr-xr-x | contrib/macdeploy/detached-sig-create.sh | 2 | ||||
-rw-r--r-- | contrib/rpm/bitcoin.spec | 6 | ||||
-rwxr-xr-x | contrib/testgen/gen_base58_test_vectors.py | 2 | ||||
-rw-r--r-- | contrib/verify-commits/trusted-sha512-root-commit | 2 | ||||
-rwxr-xr-x | contrib/verify-commits/verify-commits.sh | 126 | ||||
-rwxr-xr-x | contrib/windeploy/detached-sig-create.sh | 34 | ||||
-rw-r--r-- | contrib/windeploy/win-codesign.cert | 99 | ||||
-rwxr-xr-x | contrib/zmq/zmq_sub3.4.py | 2 | ||||
-rw-r--r-- | depends/packages/zlib.mk | 4 | ||||
-rw-r--r-- | doc/README.md | 2 | ||||
-rw-r--r-- | doc/developer-notes.md | 4 | ||||
-rw-r--r-- | doc/gitian-building.md | 2 | ||||
-rw-r--r-- | doc/release-notes.md | 49 | ||||
-rw-r--r-- | doc/release-notes/release-notes-0.14.0.md | 873 | ||||
-rw-r--r-- | doc/release-process.md | 34 | ||||
-rw-r--r-- | qa/README.md | 87 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/Makefile.bench.include | 3 | ||||
-rw-r--r-- | src/Makefile.qttest.include | 22 | ||||
-rw-r--r-- | src/Makefile.test.include | 63 | ||||
-rw-r--r-- | src/base58.cpp | 2 | ||||
-rw-r--r-- | src/bench/bench.h | 2 | ||||
-rw-r--r-- | src/bench/coin_selection.cpp | 2 | ||||
-rw-r--r-- | src/bench/prevector_destructor.cpp | 36 | ||||
-rw-r--r-- | src/bitcoin-tx.cpp | 16 | ||||
-rw-r--r-- | src/blockencodings.cpp | 2 | ||||
-rw-r--r-- | src/bloom.cpp | 4 | ||||
-rw-r--r-- | src/chainparams.cpp | 3 | ||||
-rw-r--r-- | src/chainparams.h | 3 | ||||
-rw-r--r-- | src/checkqueue.h | 22 | ||||
-rw-r--r-- | src/coins.h | 1 | ||||
-rw-r--r-- | src/compat.h | 11 | ||||
-rw-r--r-- | src/core_write.cpp | 4 | ||||
-rw-r--r-- | src/dbwrapper.cpp | 61 | ||||
-rw-r--r-- | src/dbwrapper.h | 4 | ||||
-rw-r--r-- | src/httpserver.cpp | 8 | ||||
-rw-r--r-- | src/init.cpp | 51 | ||||
-rw-r--r-- | src/key.h | 2 | ||||
-rw-r--r-- | src/miner.cpp | 17 | ||||
-rw-r--r-- | src/miner.h | 2 | ||||
-rw-r--r-- | src/net.cpp | 28 | ||||
-rw-r--r-- | src/net.h | 2 | ||||
-rw-r--r-- | src/netbase.cpp | 2 | ||||
-rw-r--r-- | src/pow.cpp | 5 | ||||
-rw-r--r-- | src/prevector.h | 17 | ||||
-rw-r--r-- | src/qt/forms/debugwindow.ui | 2 | ||||
-rw-r--r-- | src/qt/forms/sendcoinsdialog.ui | 36 | ||||
-rw-r--r-- | src/qt/guiutil.cpp | 2 | ||||
-rw-r--r-- | src/qt/rpcconsole.cpp | 7 | ||||
-rw-r--r-- | src/qt/sendcoinsdialog.cpp | 17 | ||||
-rw-r--r-- | src/qt/test/paymentservertests.cpp | 2 | ||||
-rw-r--r-- | src/qt/test/rpcnestedtests.cpp | 4 | ||||
-rw-r--r-- | src/qt/test/test_main.cpp | 40 | ||||
-rw-r--r-- | src/qt/test/wallettests.cpp | 107 | ||||
-rw-r--r-- | src/qt/test/wallettests.h | 15 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 11 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 2 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 74 | ||||
-rw-r--r-- | src/rpc/client.cpp | 6 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 42 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 112 | ||||
-rw-r--r-- | src/rpc/net.cpp | 44 | ||||
-rw-r--r-- | src/rpc/protocol.cpp | 8 | ||||
-rw-r--r-- | src/rpc/protocol.h | 6 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 80 | ||||
-rw-r--r-- | src/rpc/server.cpp | 63 | ||||
-rw-r--r-- | src/rpc/server.h | 3 | ||||
-rw-r--r-- | src/script/interpreter.cpp | 26 | ||||
-rw-r--r-- | src/script/ismine.cpp | 10 | ||||
-rw-r--r-- | src/script/script.cpp | 4 | ||||
-rw-r--r-- | src/script/sign.cpp | 28 | ||||
-rw-r--r-- | src/script/standard.cpp | 24 | ||||
-rw-r--r-- | src/streams.h | 4 | ||||
-rw-r--r-- | src/sync.cpp | 2 | ||||
-rw-r--r-- | src/sync.h | 1 | ||||
-rw-r--r-- | src/test/README.md | 9 | ||||
-rw-r--r-- | src/test/addrman_tests.cpp | 2 | ||||
-rwxr-xr-x | src/test/bitcoin-util-test.py | 45 | ||||
-rw-r--r-- | src/test/buildenv.py.in | 2 | ||||
-rw-r--r-- | src/test/checkqueue_tests.cpp | 442 | ||||
-rw-r--r-- | src/test/cuckoocache_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/dbwrapper_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/key_tests.cpp | 28 | ||||
-rw-r--r-- | src/test/merkle_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/script_tests.cpp | 33 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 28 | ||||
-rw-r--r-- | src/test/test_bitcoin_main.cpp | 26 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 4 | ||||
-rw-r--r-- | src/tinyformat.h | 9 | ||||
-rw-r--r-- | src/torcontrol.cpp | 24 | ||||
-rw-r--r-- | src/txmempool.cpp | 2 | ||||
-rw-r--r-- | src/txmempool.h | 8 | ||||
-rw-r--r-- | src/util.cpp | 40 | ||||
-rw-r--r-- | src/util.h | 20 | ||||
-rw-r--r-- | src/utilmoneystr.cpp | 8 | ||||
-rw-r--r-- | src/utilstrencodings.cpp | 50 | ||||
-rw-r--r-- | src/utiltime.cpp | 2 | ||||
-rw-r--r-- | src/validation.cpp | 10 | ||||
-rw-r--r-- | src/validation.h | 2 | ||||
-rw-r--r-- | src/validationinterface.h | 7 | ||||
-rw-r--r-- | src/versionbits.cpp | 2 | ||||
-rw-r--r-- | src/wallet/coincontrol.h | 4 | ||||
-rw-r--r-- | src/wallet/db.cpp | 43 | ||||
-rw-r--r-- | src/wallet/rpcdump.cpp | 76 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 310 | ||||
-rw-r--r-- | src/wallet/test/wallet_tests.cpp | 10 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 396 | ||||
-rw-r--r-- | src/wallet/wallet.h | 60 | ||||
-rw-r--r-- | src/wallet/walletdb.cpp | 74 | ||||
-rw-r--r-- | src/wallet/walletdb.h | 8 | ||||
-rw-r--r-- | src/zmq/zmqpublishnotifier.cpp | 3 | ||||
-rw-r--r-- | test/README.md | 97 | ||||
-rw-r--r-- | test/functional/.gitignore (renamed from qa/rpc-tests/.gitignore) | 0 | ||||
-rw-r--r-- | test/functional/README.md (renamed from qa/rpc-tests/README.md) | 0 | ||||
-rwxr-xr-x | test/functional/abandonconflict.py (renamed from qa/rpc-tests/abandonconflict.py) | 16 | ||||
-rwxr-xr-x | test/functional/assumevalid.py (renamed from qa/rpc-tests/assumevalid.py) | 109 | ||||
-rwxr-xr-x | test/functional/bip65-cltv-p2p.py (renamed from qa/rpc-tests/bip65-cltv-p2p.py) | 2 | ||||
-rwxr-xr-x | test/functional/bip65-cltv.py (renamed from qa/rpc-tests/bip65-cltv.py) | 8 | ||||
-rwxr-xr-x | test/functional/bip68-112-113-p2p.py (renamed from qa/rpc-tests/bip68-112-113-p2p.py) | 2 | ||||
-rwxr-xr-x | test/functional/bip68-sequence.py (renamed from qa/rpc-tests/bip68-sequence.py) | 70 | ||||
-rwxr-xr-x | test/functional/bip9-softforks.py (renamed from qa/rpc-tests/bip9-softforks.py) | 2 | ||||
-rwxr-xr-x | test/functional/bipdersig-p2p.py (renamed from qa/rpc-tests/bipdersig-p2p.py) | 2 | ||||
-rwxr-xr-x | test/functional/bipdersig.py (renamed from qa/rpc-tests/bipdersig.py) | 8 | ||||
-rwxr-xr-x | test/functional/blockchain.py (renamed from qa/rpc-tests/blockchain.py) | 6 | ||||
-rwxr-xr-x | test/functional/bumpfee.py (renamed from qa/rpc-tests/bumpfee.py) | 135 | ||||
-rwxr-xr-x | test/functional/combine_logs.py | 114 | ||||
-rw-r--r-- | test/functional/combined_log_template.html | 40 | ||||
-rw-r--r-- | test/functional/config.ini.in (renamed from qa/pull-tester/tests_config.ini.in) | 2 | ||||
-rwxr-xr-x | test/functional/create_cache.py (renamed from qa/rpc-tests/create_cache.py) | 2 | ||||
-rwxr-xr-x | test/functional/decodescript.py (renamed from qa/rpc-tests/decodescript.py) | 0 | ||||
-rwxr-xr-x | test/functional/disablewallet.py (renamed from qa/rpc-tests/disablewallet.py) | 17 | ||||
-rwxr-xr-x | test/functional/forknotify.py (renamed from qa/rpc-tests/forknotify.py) | 0 | ||||
-rwxr-xr-x | test/functional/fundrawtransaction.py (renamed from qa/rpc-tests/fundrawtransaction.py) | 81 | ||||
-rwxr-xr-x | test/functional/getblocktemplate_longpoll.py (renamed from qa/rpc-tests/getblocktemplate_longpoll.py) | 6 | ||||
-rwxr-xr-x | test/functional/getblocktemplate_proposals.py (renamed from qa/rpc-tests/getblocktemplate_proposals.py) | 4 | ||||
-rwxr-xr-x | test/functional/getchaintips.py (renamed from qa/rpc-tests/getchaintips.py) | 0 | ||||
-rwxr-xr-x | test/functional/httpbasics.py (renamed from qa/rpc-tests/httpbasics.py) | 0 | ||||
-rwxr-xr-x | test/functional/import-rescan.py (renamed from qa/rpc-tests/import-rescan.py) | 13 | ||||
-rwxr-xr-x | test/functional/importmulti.py (renamed from qa/rpc-tests/importmulti.py) | 63 | ||||
-rwxr-xr-x | test/functional/importprunedfunds.py (renamed from qa/rpc-tests/importprunedfunds.py) | 16 | ||||
-rwxr-xr-x | test/functional/invalidateblock.py (renamed from qa/rpc-tests/invalidateblock.py) | 34 | ||||
-rwxr-xr-x | test/functional/invalidblockrequest.py (renamed from qa/rpc-tests/invalidblockrequest.py) | 0 | ||||
-rwxr-xr-x | test/functional/invalidtxrequest.py (renamed from qa/rpc-tests/invalidtxrequest.py) | 0 | ||||
-rwxr-xr-x | test/functional/keypool.py (renamed from qa/rpc-tests/keypool.py) | 59 | ||||
-rwxr-xr-x | test/functional/listsinceblock.py (renamed from qa/rpc-tests/listsinceblock.py) | 2 | ||||
-rwxr-xr-x | test/functional/listtransactions.py (renamed from qa/rpc-tests/listtransactions.py) | 4 | ||||
-rwxr-xr-x | test/functional/maxblocksinflight.py (renamed from qa/rpc-tests/maxblocksinflight.py) | 14 | ||||
-rwxr-xr-x | test/functional/maxuploadtarget.py (renamed from qa/rpc-tests/maxuploadtarget.py) | 20 | ||||
-rwxr-xr-x | test/functional/mempool_limit.py (renamed from qa/rpc-tests/mempool_limit.py) | 2 | ||||
-rwxr-xr-x | test/functional/mempool_packages.py (renamed from qa/rpc-tests/mempool_packages.py) | 33 | ||||
-rwxr-xr-x | test/functional/mempool_reorg.py (renamed from qa/rpc-tests/mempool_reorg.py) | 18 | ||||
-rwxr-xr-x | test/functional/mempool_resurrect_test.py (renamed from qa/rpc-tests/mempool_resurrect_test.py) | 2 | ||||
-rwxr-xr-x | test/functional/mempool_spendcoinbase.py (renamed from qa/rpc-tests/mempool_spendcoinbase.py) | 4 | ||||
-rwxr-xr-x | test/functional/merkle_blocks.py (renamed from qa/rpc-tests/merkle_blocks.py) | 10 | ||||
-rwxr-xr-x | test/functional/multi_rpc.py (renamed from qa/rpc-tests/multi_rpc.py) | 2 | ||||
-rwxr-xr-x | test/functional/nodehandling.py (renamed from qa/rpc-tests/nodehandling.py) | 14 | ||||
-rwxr-xr-x | test/functional/nulldummy.py (renamed from qa/rpc-tests/nulldummy.py) | 41 | ||||
-rwxr-xr-x | test/functional/p2p-acceptblock.py (renamed from qa/rpc-tests/p2p-acceptblock.py) | 48 | ||||
-rwxr-xr-x | test/functional/p2p-compactblocks.py (renamed from qa/rpc-tests/p2p-compactblocks.py) | 54 | ||||
-rwxr-xr-x | test/functional/p2p-feefilter.py (renamed from qa/rpc-tests/p2p-feefilter.py) | 8 | ||||
-rwxr-xr-x | test/functional/p2p-fullblocktest.py (renamed from qa/rpc-tests/p2p-fullblocktest.py) | 0 | ||||
-rwxr-xr-x | test/functional/p2p-leaktests.py (renamed from qa/rpc-tests/p2p-leaktests.py) | 6 | ||||
-rwxr-xr-x | test/functional/p2p-mempool.py (renamed from qa/rpc-tests/p2p-mempool.py) | 4 | ||||
-rwxr-xr-x | test/functional/p2p-segwit.py (renamed from qa/rpc-tests/p2p-segwit.py) | 76 | ||||
-rwxr-xr-x | test/functional/p2p-timeouts.py (renamed from qa/rpc-tests/p2p-timeouts.py) | 7 | ||||
-rwxr-xr-x | test/functional/p2p-versionbits-warning.py (renamed from qa/rpc-tests/p2p-versionbits-warning.py) | 4 | ||||
-rwxr-xr-x | test/functional/preciousblock.py (renamed from qa/rpc-tests/preciousblock.py) | 33 | ||||
-rwxr-xr-x | test/functional/prioritise_transaction.py (renamed from qa/rpc-tests/prioritise_transaction.py) | 18 | ||||
-rwxr-xr-x | test/functional/proxy_test.py (renamed from qa/rpc-tests/proxy_test.py) | 12 | ||||
-rwxr-xr-x | test/functional/pruning.py (renamed from qa/rpc-tests/pruning.py) | 117 | ||||
-rwxr-xr-x | test/functional/rawtransactions.py (renamed from qa/rpc-tests/rawtransactions.py) | 22 | ||||
-rwxr-xr-x | test/functional/receivedby.py (renamed from qa/rpc-tests/receivedby.py) | 0 | ||||
-rwxr-xr-x | test/functional/reindex.py (renamed from qa/rpc-tests/reindex.py) | 4 | ||||
-rwxr-xr-x | test/functional/replace-by-fee.py (renamed from qa/rpc-tests/replace-by-fee.py) | 131 | ||||
-rwxr-xr-x | test/functional/rest.py (renamed from qa/rpc-tests/rest.py) | 2 | ||||
-rwxr-xr-x | test/functional/rpcbind_test.py (renamed from qa/rpc-tests/rpcbind_test.py) | 26 | ||||
-rwxr-xr-x | test/functional/rpcnamedargs.py (renamed from qa/rpc-tests/rpcnamedargs.py) | 0 | ||||
-rwxr-xr-x | test/functional/segwit.py (renamed from qa/rpc-tests/segwit.py) | 220 | ||||
-rwxr-xr-x | test/functional/sendheaders.py (renamed from qa/rpc-tests/sendheaders.py) | 26 | ||||
-rwxr-xr-x | test/functional/signmessages.py (renamed from qa/rpc-tests/signmessages.py) | 0 | ||||
-rwxr-xr-x | test/functional/signrawtransactions.py (renamed from qa/rpc-tests/signrawtransactions.py) | 0 | ||||
-rwxr-xr-x | test/functional/smartfees.py (renamed from qa/rpc-tests/smartfees.py) | 85 | ||||
-rw-r--r-- | test/functional/test_framework/__init__.py (renamed from qa/rpc-tests/test_framework/__init__.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/address.py (renamed from qa/rpc-tests/test_framework/address.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/authproxy.py (renamed from qa/rpc-tests/test_framework/authproxy.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/bignum.py (renamed from qa/rpc-tests/test_framework/bignum.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/blockstore.py (renamed from qa/rpc-tests/test_framework/blockstore.py) | 6 | ||||
-rw-r--r-- | test/functional/test_framework/blocktools.py (renamed from qa/rpc-tests/test_framework/blocktools.py) | 0 | ||||
-rwxr-xr-x | test/functional/test_framework/comptool.py (renamed from qa/rpc-tests/test_framework/comptool.py) | 21 | ||||
-rw-r--r-- | test/functional/test_framework/coverage.py (renamed from qa/rpc-tests/test_framework/coverage.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/key.py (renamed from qa/rpc-tests/test_framework/key.py) | 0 | ||||
-rwxr-xr-x | test/functional/test_framework/mininode.py (renamed from qa/rpc-tests/test_framework/mininode.py) | 148 | ||||
-rw-r--r-- | test/functional/test_framework/netutil.py (renamed from qa/rpc-tests/test_framework/netutil.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/script.py (renamed from qa/rpc-tests/test_framework/script.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/siphash.py (renamed from qa/rpc-tests/test_framework/siphash.py) | 0 | ||||
-rw-r--r-- | test/functional/test_framework/socks5.py (renamed from qa/rpc-tests/test_framework/socks5.py) | 8 | ||||
-rwxr-xr-x | test/functional/test_framework/test_framework.py (renamed from qa/rpc-tests/test_framework/test_framework.py) | 96 | ||||
-rw-r--r-- | test/functional/test_framework/util.py (renamed from qa/rpc-tests/test_framework/util.py) | 21 | ||||
-rwxr-xr-x | test/functional/test_runner.py (renamed from qa/pull-tester/rpc-tests.py) | 108 | ||||
-rwxr-xr-x | test/functional/txn_clone.py (renamed from qa/rpc-tests/txn_clone.py) | 0 | ||||
-rwxr-xr-x | test/functional/txn_doublespend.py (renamed from qa/rpc-tests/txn_doublespend.py) | 0 | ||||
-rwxr-xr-x | test/functional/wallet-accounts.py (renamed from qa/rpc-tests/wallet-accounts.py) | 0 | ||||
-rwxr-xr-x | test/functional/wallet-dump.py (renamed from qa/rpc-tests/wallet-dump.py) | 6 | ||||
-rwxr-xr-x | test/functional/wallet-hd.py (renamed from qa/rpc-tests/wallet-hd.py) | 21 | ||||
-rwxr-xr-x | test/functional/wallet.py (renamed from qa/rpc-tests/wallet.py) | 24 | ||||
-rwxr-xr-x | test/functional/walletbackup.py (renamed from qa/rpc-tests/walletbackup.py) | 16 | ||||
-rwxr-xr-x | test/functional/zapwallettxes.py (renamed from qa/rpc-tests/zapwallettxes.py) | 2 | ||||
-rwxr-xr-x | test/functional/zmq_test.py (renamed from qa/rpc-tests/zmq_test.py) | 3 | ||||
-rw-r--r-- | test/util/bctest.py (renamed from src/test/bctest.py) | 6 | ||||
-rwxr-xr-x | test/util/bitcoin-util-test.py | 36 | ||||
-rw-r--r-- | test/util/buildenv.py.in | 4 | ||||
-rw-r--r-- | test/util/data/bitcoin-util-test.json (renamed from src/test/data/bitcoin-util-test.json) | 0 | ||||
-rw-r--r-- | test/util/data/blanktxv1.hex (renamed from src/test/data/blanktxv1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/blanktxv1.json (renamed from src/test/data/blanktxv1.json) | 0 | ||||
-rw-r--r-- | test/util/data/blanktxv2.hex (renamed from src/test/data/blanktxv2.hex) | 0 | ||||
-rw-r--r-- | test/util/data/blanktxv2.json (renamed from src/test/data/blanktxv2.json) | 0 | ||||
-rw-r--r-- | test/util/data/tt-delin1-out.hex (renamed from src/test/data/tt-delin1-out.hex) | 0 | ||||
-rw-r--r-- | test/util/data/tt-delin1-out.json (renamed from src/test/data/tt-delin1-out.json) | 0 | ||||
-rw-r--r-- | test/util/data/tt-delout1-out.hex (renamed from src/test/data/tt-delout1-out.hex) | 0 | ||||
-rw-r--r-- | test/util/data/tt-delout1-out.json (renamed from src/test/data/tt-delout1-out.json) | 0 | ||||
-rw-r--r-- | test/util/data/tt-locktime317000-out.hex (renamed from src/test/data/tt-locktime317000-out.hex) | 0 | ||||
-rw-r--r-- | test/util/data/tt-locktime317000-out.json (renamed from src/test/data/tt-locktime317000-out.json) | 0 | ||||
-rw-r--r-- | test/util/data/tx394b54bb.hex (renamed from src/test/data/tx394b54bb.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreate1.hex (renamed from src/test/data/txcreate1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreate1.json (renamed from src/test/data/txcreate1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreate2.hex (renamed from src/test/data/txcreate2.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreate2.json (renamed from src/test/data/txcreate2.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata1.hex (renamed from src/test/data/txcreatedata1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata1.json (renamed from src/test/data/txcreatedata1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata2.hex (renamed from src/test/data/txcreatedata2.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata2.json (renamed from src/test/data/txcreatedata2.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata_seq0.hex (renamed from src/test/data/txcreatedata_seq0.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata_seq0.json (renamed from src/test/data/txcreatedata_seq0.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata_seq1.hex (renamed from src/test/data/txcreatedata_seq1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatedata_seq1.json (renamed from src/test/data/txcreatedata_seq1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig1.hex (renamed from src/test/data/txcreatemultisig1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig1.json (renamed from src/test/data/txcreatemultisig1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig2.hex (renamed from src/test/data/txcreatemultisig2.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig2.json (renamed from src/test/data/txcreatemultisig2.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig3.hex (renamed from src/test/data/txcreatemultisig3.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig3.json (renamed from src/test/data/txcreatemultisig3.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig4.hex (renamed from src/test/data/txcreatemultisig4.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatemultisig4.json (renamed from src/test/data/txcreatemultisig4.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreateoutpubkey1.hex (renamed from src/test/data/txcreateoutpubkey1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreateoutpubkey1.json (renamed from src/test/data/txcreateoutpubkey1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreateoutpubkey2.hex (renamed from src/test/data/txcreateoutpubkey2.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreateoutpubkey2.json (renamed from src/test/data/txcreateoutpubkey2.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreateoutpubkey3.hex (renamed from src/test/data/txcreateoutpubkey3.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreateoutpubkey3.json (renamed from src/test/data/txcreateoutpubkey3.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript1.hex (renamed from src/test/data/txcreatescript1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript1.json (renamed from src/test/data/txcreatescript1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript2.hex (renamed from src/test/data/txcreatescript2.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript2.json (renamed from src/test/data/txcreatescript2.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript3.hex (renamed from src/test/data/txcreatescript3.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript3.json (renamed from src/test/data/txcreatescript3.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript4.hex (renamed from src/test/data/txcreatescript4.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatescript4.json (renamed from src/test/data/txcreatescript4.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatesignv1.hex (renamed from src/test/data/txcreatesignv1.hex) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatesignv1.json (renamed from src/test/data/txcreatesignv1.json) | 0 | ||||
-rw-r--r-- | test/util/data/txcreatesignv2.hex (renamed from src/test/data/txcreatesignv2.hex) | 0 |
270 files changed, 4561 insertions, 2443 deletions
diff --git a/.gitignore b/.gitignore index 479889cb78..f1e9ca20c1 100644 --- a/.gitignore +++ b/.gitignore @@ -101,9 +101,9 @@ coverage_percent.txt linux-coverage-build linux-build win32-build -qa/pull-tester/tests_config.py -qa/pull-tester/tests_config.ini -qa/cache/* +test/functional/config.ini +test/util/buildenv.py +test/cache/* !src/leveldb*/Makefile diff --git a/.travis.yml b/.travis.yml index ce6cdc2db0..d8395255bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,7 +32,7 @@ env: # bitcoind - HOST=x86_64-unknown-linux-gnu PACKAGES="bc python3-zmq" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-zmq --enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" # No wallet - - HOST=x86_64-unknown-linux-gnu PACKAGES="python3" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + - HOST=x86_64-unknown-linux-gnu PACKAGES="python3 xvfb" DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" # Cross-Mac - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" OSX_SDK=10.11 GOAL="deploy" @@ -50,8 +50,10 @@ before_script: - if [ -n "$OSX_SDK" -a ! -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C depends/SDKs -xf depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS + # Start xvfb if needed, as documented at https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI + - if [ "$RUN_TESTS" = "true" -a "${DEP_OPTS#*NO_QT=1}" = "$DEP_OPTS" ]; then export DISPLAY=:99.0; /sbin/start-stop-daemon --start --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac; fi script: - - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi + - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then while read LINE; do travis_retry gpg --keyserver hkp://subset.pool.sks-keyservers.net --recv-keys $LINE; done < contrib/verify-commits/trusted-keys; fi - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then git fetch --unshallow; fi - if [ "$CHECK_DOC" = 1 -a "$TRAVIS_REPO_SLUG" = "bitcoin/bitcoin" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then contrib/verify-commits/verify-commits.sh; fi - export TRAVIS_COMMIT_LOG=`git log --format=fuller -1` @@ -68,7 +70,8 @@ script: - make $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL V=1 ; false ) - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS check VERBOSE=1; fi - - if [ "$RUN_TESTS" = "true" ]; then qa/pull-tester/rpc-tests.py --coverage; fi + - if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then extended="--extended --exclude pruning"; fi + - if [ "$RUN_TESTS" = "true" ]; then test/functional/test_runner.py --coverage --quiet ${extended}; fi after_script: - echo $TRAVIS_COMMIT_RANGE - echo $TRAVIS_COMMIT_LOG diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc8d58d97d..0766d89f55 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -130,7 +130,7 @@ pull requests which attempt to do too much, are overly large, or overly complex as this makes review difficult. -###Features +### Features When adding a new feature, thought must be given to the long term technical debt and maintenance that feature may require after inclusion. Before proposing a new @@ -139,7 +139,7 @@ maintain it (including bug fixing). If features get orphaned with no maintainer in the future, they may be removed by the Repository Maintainer. -###Refactoring +### Refactoring Refactoring is a necessary part of any software project's evolution. The following guidelines cover refactoring pull requests for the project. @@ -187,7 +187,7 @@ other kinds of patches because of increased peer review and consensus building requirements. -###Peer Review +### Peer Review Anyone may participate in peer review which is expressed by comments in the pull request. Typically reviewers will review the code for obvious errors, as well as diff --git a/Makefile.am b/Makefile.am index 1ee2dfb734..e82704dbdf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -61,7 +61,7 @@ OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \ COVERAGE_INFO = baseline_filtered_combined.info baseline.info \ leveldb_baseline.info test_bitcoin_filtered.info total_coverage.info \ - baseline_filtered.info rpc_test.info rpc_test_filtered.info \ + baseline_filtered.info functional_test.info functional_test_filtered.info \ leveldb_baseline_filtered.info test_bitcoin_coverage.info test_bitcoin.info dist-hook: @@ -194,20 +194,20 @@ test_bitcoin.info: baseline_filtered_combined.info test_bitcoin_filtered.info: test_bitcoin.info $(LCOV) -r $< "/usr/include/*" -o $@ -rpc_test.info: test_bitcoin_filtered.info - -@TIMEOUT=15 python qa/pull-tester/rpc-tests.py $(EXTENDED_RPC_TESTS) - $(LCOV) -c -d $(abs_builddir)/src --t rpc-tests -o $@ +functional_test.info: test_bitcoin_filtered.info + -@TIMEOUT=15 python test/functional/test_runner.py $(EXTENDED_FUNCTIONAL_TESTS) + $(LCOV) -c -d $(abs_builddir)/src --t functional-tests -o $@ $(LCOV) -z -d $(abs_builddir)/src $(LCOV) -z -d $(abs_builddir)/src/leveldb -rpc_test_filtered.info: rpc_test.info +functional_test_filtered.info: functional_test.info $(LCOV) -r $< "/usr/include/*" -o $@ test_bitcoin_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -o $@ -total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info rpc_test_filtered.info - $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a rpc_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt +total_coverage.info: baseline_filtered_combined.info test_bitcoin_filtered.info functional_test_filtered.info + $(LCOV) -a baseline_filtered.info -a leveldb_baseline_filtered.info -a test_bitcoin_filtered.info -a functional_test_filtered.info -o $@ | $(GREP) "\%" | $(AWK) '{ print substr($$3,2,50) "/" $$5 }' > coverage_percent.txt test_bitcoin.coverage/.dirstamp: test_bitcoin_coverage.info $(GENHTML) -s $< -o $(@D) @@ -223,14 +223,70 @@ endif dist_noinst_SCRIPTS = autogen.sh -EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-tests $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) +EXTRA_DIST = $(top_srcdir)/share/genbuild.sh test/functional/test_runner.py test/functional $(DIST_CONTRIB) $(DIST_DOCS) $(WINDOWS_PACKAGING) $(OSX_PACKAGING) $(BIN_CHECKS) + +EXTRA_DIST += \ + test/util/bctest.py \ + test/util/bitcoin-util-test.py \ + test/util/data/bitcoin-util-test.json \ + test/util/data/blanktxv1.hex \ + test/util/data/blanktxv1.json \ + test/util/data/blanktxv2.hex \ + test/util/data/blanktxv2.json \ + test/util/data/tt-delin1-out.hex \ + test/util/data/tt-delin1-out.json \ + test/util/data/tt-delout1-out.hex \ + test/util/data/tt-delout1-out.json \ + test/util/data/tt-locktime317000-out.hex \ + test/util/data/tt-locktime317000-out.json \ + test/util/data/tx394b54bb.hex \ + test/util/data/txcreate1.hex \ + test/util/data/txcreate1.json \ + test/util/data/txcreate2.hex \ + test/util/data/txcreate2.json \ + test/util/data/txcreatedata1.hex \ + test/util/data/txcreatedata1.json \ + test/util/data/txcreatedata2.hex \ + test/util/data/txcreatedata2.json \ + test/util/data/txcreatedata_seq0.hex \ + test/util/data/txcreatedata_seq0.json \ + test/util/data/txcreatedata_seq1.hex \ + test/util/data/txcreatedata_seq1.json \ + test/util/data/txcreatemultisig1.hex \ + test/util/data/txcreatemultisig1.json \ + test/util/data/txcreatemultisig2.hex \ + test/util/data/txcreatemultisig2.json \ + test/util/data/txcreatemultisig3.hex \ + test/util/data/txcreatemultisig3.json \ + test/util/data/txcreatemultisig4.hex \ + test/util/data/txcreatemultisig4.json \ + test/util/data/txcreateoutpubkey1.hex \ + test/util/data/txcreateoutpubkey1.json \ + test/util/data/txcreateoutpubkey2.hex \ + test/util/data/txcreateoutpubkey2.json \ + test/util/data/txcreateoutpubkey3.hex \ + test/util/data/txcreateoutpubkey3.json \ + test/util/data/txcreatescript1.hex \ + test/util/data/txcreatescript1.json \ + test/util/data/txcreatescript2.hex \ + test/util/data/txcreatescript2.json \ + test/util/data/txcreatescript3.hex \ + test/util/data/txcreatescript3.json \ + test/util/data/txcreatescript4.hex \ + test/util/data/txcreatescript4.json \ + test/util/data/txcreatesignv1.hex \ + test/util/data/txcreatesignv1.json \ + test/util/data/txcreatesignv2.hex CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER) +# This file is problematic for out-of-tree builds if it exists. +DISTCLEANFILES = test/util/buildenv.pyc + .INTERMEDIATE: $(COVERAGE_INFO) DISTCHECK_CONFIGURE_FLAGS = --enable-man clean-local: - rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ qa/tmp/ cache/ $(OSX_APP) - rm -rf qa/pull-tester/__pycache__ + rm -rf coverage_percent.txt test_bitcoin.coverage/ total.coverage/ test/tmp/ cache/ $(OSX_APP) + rm -rf test/functional/__pycache__ @@ -54,9 +54,9 @@ submit new unit tests for old code. Unit tests can be compiled and run (assuming they weren't disabled in configure) with: `make check`. Further details on running and extending unit tests can be found in [/src/test/README.md](/src/test/README.md). -There are also [regression and integration tests](/qa) of the RPC interface, written +There are also [regression and integration tests](/test), written in Python, that are run automatically on the build server. -These tests can be run (if the [test dependencies](/qa) are installed) with: `qa/pull-tester/rpc-tests.py` +These tests can be run (if the [test dependencies](/test) are installed) with: `test/functional/test_runner.py` The Travis CI system makes sure that every pull request is built for Windows, Linux, and OS X, and that unit/sanity tests are run automatically. diff --git a/configure.ac b/configure.ac index d25bebeb1a..2a9ee018a0 100644 --- a/configure.ac +++ b/configure.ac @@ -124,10 +124,10 @@ AC_ARG_ENABLE(bench, [use_bench=$enableval], [use_bench=yes]) -AC_ARG_ENABLE([extended-rpc-tests], - AS_HELP_STRING([--enable-extended-rpc-tests],[enable expensive RPC tests when using lcov (default no)]), - [use_extended_rpc_tests=$enableval], - [use_extended_rpc_tests=no]) +AC_ARG_ENABLE([extended-functional-tests], + AS_HELP_STRING([--enable-extended-functional-tests],[enable expensive functional tests when using lcov (default no)]), + [use_extended_functional_tests=$enableval], + [use_extended_functional_tests=no]) AC_ARG_WITH([qrencode], [AS_HELP_STRING([--with-qrencode], @@ -414,8 +414,8 @@ if test x$use_pkgconfig = xyes; then ]) fi -if test x$use_extended_rpc_tests != xno; then - AC_SUBST(EXTENDED_RPC_TESTS, -extended) +if test x$use_extended_functional_tests != xno; then + AC_SUBST(EXTENDED_FUNCTIONAL_TESTS, --extended) fi if test x$use_lcov = xyes; then @@ -558,6 +558,22 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]], [ AC_MSG_RESULT(no)] ) +dnl Check for MSG_DONTWAIT +AC_MSG_CHECKING(for MSG_DONTWAIT) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/socket.h>]], + [[ int f = MSG_DONTWAIT; ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MSG_DONTWAIT, 1,[Define this symbol if you have MSG_DONTWAIT]) ], + [ AC_MSG_RESULT(no)] +) + +dnl Check for malloc_info (for memory statistics information in getmemoryinfo) +AC_MSG_CHECKING(for getmemoryinfo) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]], + [[ int f = malloc_info(0, NULL); ]])], + [ AC_MSG_RESULT(yes); AC_DEFINE(HAVE_MALLOC_INFO, 1,[Define this symbol if you have malloc_info]) ], + [ AC_MSG_RESULT(no)] +) + AC_MSG_CHECKING([for visibility attribute]) AC_LINK_IFELSE([AC_LANG_SOURCE([ int foo_def( void ) __attribute__((visibility("default"))); @@ -1131,10 +1147,12 @@ AC_SUBST(EVENT_PTHREADS_LIBS) AC_SUBST(ZMQ_LIBS) AC_SUBST(PROTOBUF_LIBS) AC_SUBST(QR_LIBS) -AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py]) -AC_CONFIG_FILES([qa/pull-tester/tests_config.ini],[chmod +x qa/pull-tester/tests_config.ini]) +AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/functional/config.ini]) +AC_CONFIG_FILES([test/util/buildenv.py],[chmod +x test/util/buildenv.py]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) -AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py]) +AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py]) +AC_CONFIG_LINKS([test/util/bitcoin-util-test.py:test/util/bitcoin-util-test.py]) +AC_CONFIG_LINKS([test/util/bctest.py:test/util/bctest.py]) dnl boost's m4 checks do something really nasty: they export these vars. As a dnl result, they leak into secp256k1's configure and crazy things happen. @@ -1182,8 +1200,8 @@ esac dnl Replace the BUILDDIR path with the correct Windows path if compiling on Native Windows case ${OS} in *Windows*) - sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' qa/pull-tester/tests_config.py > qa/pull-tester/tests_config-2.py - mv qa/pull-tester/tests_config-2.py qa/pull-tester/tests_config.py + sed 's/BUILDDIR="\/\([[a-z]]\)/BUILDDIR="\1:/' test/functional/config.ini > test/functional/config-2.ini + mv test/functional/config-2.ini test/functional/config.ini ;; esac diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py index 9f35c378bf..6d801d3ac7 100755 --- a/contrib/devtools/copyright_header.py +++ b/contrib/devtools/copyright_header.py @@ -32,7 +32,7 @@ EXCLUDE = [ 'src/tinyformat.h', 'src/leveldb/util/env_win.cc', 'src/crypto/ctaes/bench.c', - 'qa/rpc-tests/test_framework/bignum.py', + 'test/functional/test_framework/bignum.py', # python init: '*__init__.py', ] diff --git a/contrib/devtools/github-merge.py b/contrib/devtools/github-merge.py index f1b6a12fd0..3fee39143d 100755 --- a/contrib/devtools/github-merge.py +++ b/contrib/devtools/github-merge.py @@ -78,24 +78,53 @@ def get_symlink_files(): ret.append(f.decode('utf-8').split("\t")[1]) return ret -def tree_sha512sum(): - files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', '--name-only', 'HEAD']).splitlines()) +def tree_sha512sum(commit='HEAD'): + # request metadata for entire tree, recursively + files = [] + blob_by_name = {} + for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines(): + name_sep = line.index(b'\t') + metadata = line[:name_sep].split() # perms, 'blob', blobid + assert(metadata[1] == b'blob') + name = line[name_sep+1:] + files.append(name) + blob_by_name[name] = metadata[2] + + files.sort() + # open connection to git-cat-file in batch mode to request data for all blobs + # this is much faster than launching it per file + p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE) overall = hashlib.sha512() for f in files: + blob = blob_by_name[f] + # request blob + p.stdin.write(blob + b'\n') + p.stdin.flush() + # read header: blob, "blob", size + reply = p.stdout.readline().split() + assert(reply[0] == blob and reply[1] == b'blob') + size = int(reply[2]) + # hash the blob data intern = hashlib.sha512() - fi = open(f, 'rb') - while True: - piece = fi.read(65536) - if piece: + ptr = 0 + while ptr < size: + bs = min(65536, size - ptr) + piece = p.stdout.read(bs) + if len(piece) == bs: intern.update(piece) else: - break - fi.close() + raise IOError('Premature EOF reading git cat-file output') + ptr += bs dig = intern.hexdigest() + assert(p.stdout.read(1) == b'\n') # ignore LF that follows blob data + # update overall hash with file hash overall.update(dig.encode("utf-8")) overall.update(" ".encode("utf-8")) overall.update(f) overall.update("\n".encode("utf-8")) + p.stdin.close() + if p.wait(): + raise IOError('Non-zero return value executing git cat-file') return overall.hexdigest() diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 6fead7c208..3388977e0d 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -146,6 +146,7 @@ script: | make ${MAKEOPTS} -C src check-security make deploy make install DESTDIR=${INSTALLPATH} + rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe cp -f bitcoin-*setup*.exe $OUTDIR/ cd installed mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ @@ -159,9 +160,11 @@ script: | cd ../../ rm -rf distsrc-${i} done - cd $OUTDIR - rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe - find . -name "*-setup-unsigned.exe" | 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 + cp -rf contrib/windeploy $BUILD_DIR + 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 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 diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh index 5022ea88bc..7f017bb4f1 100755 --- a/contrib/macdeploy/detached-sig-create.sh +++ b/contrib/macdeploy/detached-sig-create.sh @@ -10,7 +10,7 @@ BUNDLE="${ROOTDIR}/Bitcoin-Qt.app" CODESIGN=codesign TEMPDIR=sign.temp TEMPLIST=${TEMPDIR}/signatures.txt -OUT=signature.tar.gz +OUT=signature-osx.tar.gz OUTROOT=osx if [ ! -n "$1" ]; then diff --git a/contrib/rpm/bitcoin.spec b/contrib/rpm/bitcoin.spec index 516f42334e..cc54fcaf3d 100644 --- a/contrib/rpm/bitcoin.spec +++ b/contrib/rpm/bitcoin.spec @@ -311,10 +311,8 @@ rm -f %{buildroot}%{_bindir}/test_* %check make check -pushd src -srcdir=. test/bitcoin-util-test.py -popd -qa/pull-tester/rpc-tests.py -extended +srcdir=src test/bitcoin-util-test.py +test/functional/test_runner.py --extended %post libs -p /sbin/ldconfig diff --git a/contrib/testgen/gen_base58_test_vectors.py b/contrib/testgen/gen_base58_test_vectors.py index ac0701e6be..86366eb8e3 100755 --- a/contrib/testgen/gen_base58_test_vectors.py +++ b/contrib/testgen/gen_base58_test_vectors.py @@ -13,7 +13,7 @@ Usage: # Released under MIT License import os from itertools import islice -from base58 import b58encode, b58decode, b58encode_chk, b58decode_chk, b58chars +from base58 import b58encode_chk, b58decode_chk, b58chars import random from binascii import b2a_hex diff --git a/contrib/verify-commits/trusted-sha512-root-commit b/contrib/verify-commits/trusted-sha512-root-commit index c28f50ff78..7d41f90ad7 100644 --- a/contrib/verify-commits/trusted-sha512-root-commit +++ b/contrib/verify-commits/trusted-sha512-root-commit @@ -1 +1 @@ -f7ec7cfd38b543ba81ac7bed5b77f9a19739460b +309bf16257b2395ce502017be627186b749ee749 diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh index 40c9341445..74b7f38375 100755 --- a/contrib/verify-commits/verify-commits.sh +++ b/contrib/verify-commits/verify-commits.sh @@ -3,9 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -# Not technically POSIX-compliant due to use of "local", but almost every -# shell anyone uses today supports it, so its probably fine - DIR=$(dirname "$0") [ "/${DIR#/}" != "$DIR" ] && DIR=$(dirname "$(pwd)/$0") @@ -16,14 +13,36 @@ VERIFIED_SHA512_ROOT=$(cat "${DIR}/trusted-sha512-root-commit") REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits") HAVE_FAILED=false -IS_SIGNED () { - if [ $1 = $VERIFIED_ROOT ]; then - return 0; + +HAVE_GNU_SHA512=1 +[ ! -x "$(which sha512sum)" ] && HAVE_GNU_SHA512=0 + +if [ x"$1" = "x" ]; then + CURRENT_COMMIT="HEAD" +else + CURRENT_COMMIT="$1" +fi + +if [ "${CURRENT_COMMIT#* }" != "$CURRENT_COMMIT" ]; then + echo "Commit must not contain spaces?" > /dev/stderr + exit 1 +fi + +VERIFY_TREE=0 +if [ x"$2" = "x--tree-checks" ]; then + VERIFY_TREE=1 +fi + +NO_SHA1=1 +PREV_COMMIT="" + +while true; do + if [ "$CURRENT_COMMIT" = $VERIFIED_ROOT ]; then + echo "There is a valid path from "$CURRENT_COMMIT" to $VERIFIED_ROOT where all commits are signed!" + exit 0; fi - VERIFY_TREE=$2 - NO_SHA1=$3 - if [ $1 = $VERIFIED_SHA512_ROOT ]; then + if [ "$CURRENT_COMMIT" = $VERIFIED_SHA512_ROOT ]; then if [ "$VERIFY_TREE" = "1" ]; then echo "All Tree-SHA512s matched up to $VERIFIED_SHA512_ROOT" > /dev/stderr fi @@ -37,92 +56,77 @@ IS_SIGNED () { export BITCOIN_VERIFY_COMMITS_ALLOW_SHA1=1 fi - if [ "${REVSIG_ALLOWED#*$1}" != "$REVSIG_ALLOWED" ]; then + if [ "${REVSIG_ALLOWED#*$CURRENT_COMMIT}" != "$REVSIG_ALLOWED" ]; then export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=1 else export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=0 fi - if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit $1 > /dev/null; then - return 1; + if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit "$CURRENT_COMMIT" > /dev/null; then + if [ "$PREV_COMMIT" != "" ]; then + echo "No parent of $PREV_COMMIT was signed with a trusted key!" > /dev/stderr + echo "Parents are:" > /dev/stderr + PARENTS=$(git show -s --format=format:%P $PREV_COMMIT) + for PARENT in $PARENTS; do + git show -s $PARENT > /dev/stderr + done + else + echo "$CURRENT_COMMIT was not signed with a trusted key!" > /dev/stderr + fi + exit 1 fi - # We set $4 to 1 on the first call, always verifying the top of the tree - if [ "$VERIFY_TREE" = 1 -o "$4" = "1" ]; then + # We always verify the top of the tree + if [ "$VERIFY_TREE" = 1 -o "$PREV_COMMIT" = "" ]; then IFS_CACHE="$IFS" IFS=' ' - for LINE in $(git ls-tree --full-tree -r $1); do + for LINE in $(git ls-tree --full-tree -r "$CURRENT_COMMIT"); do case "$LINE" in "12"*) echo "Repo contains symlinks" > /dev/stderr IFS="$IFS_CACHE" - return 1 + exit 1 ;; esac done IFS="$IFS_CACHE" FILE_HASHES="" - for FILE in $(git ls-tree --full-tree -r --name-only $1 | LC_ALL=C sort); do - HASH=$(git cat-file blob $1:"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } ) + for FILE in $(git ls-tree --full-tree -r --name-only "$CURRENT_COMMIT" | LC_ALL=C sort); do + if [ "$HAVE_GNU_SHA512" = 1 ]; then + HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | sha512sum | { read FIRST OTHER; echo $FIRST; } ) + else + HASH=$(git cat-file blob "$CURRENT_COMMIT":"$FILE" | shasum -a 512 | { read FIRST OTHER; echo $FIRST; } ) + fi [ "$FILE_HASHES" != "" ] && FILE_HASHES="$FILE_HASHES"' ' FILE_HASHES="$FILE_HASHES$HASH $FILE" done + + if [ "$HAVE_GNU_SHA512" = 1 ]; then + TREE_HASH="$(echo "$FILE_HASHES" | sha512sum)" + else + TREE_HASH="$(echo "$FILE_HASHES" | shasum -a 512)" + fi HASH_MATCHES=0 - MSG="$(git show -s --format=format:%B $1 | tail -n1)" + MSG="$(git show -s --format=format:%B "$CURRENT_COMMIT" | tail -n1)" case "$MSG -" in - "Tree-SHA512: $(echo "$FILE_HASHES" | sha512sum)") + "Tree-SHA512: $TREE_HASH") HASH_MATCHES=1;; esac if [ "$HASH_MATCHES" = "0" ]; then - echo "Tree-SHA512 did not match for commit $1" > /dev/stderr - HAVE_FAILED=true - return 1 + echo "Tree-SHA512 did not match for commit $CURRENT_COMMIT" > /dev/stderr + exit 1 fi fi - local PARENTS - PARENTS=$(git show -s --format=format:%P $1) + PARENTS=$(git show -s --format=format:%P "$CURRENT_COMMIT") for PARENT in $PARENTS; do - if IS_SIGNED $PARENT $VERIFY_TREE $NO_SHA1 0; then - return 0; - fi + PREV_COMMIT="$CURRENT_COMMIT" + CURRENT_COMMIT="$PARENT" break done - if ! "$HAVE_FAILED"; then - echo "No parent of $1 was signed with a trusted key!" > /dev/stderr - echo "Parents are:" > /dev/stderr - for PARENT in $PARENTS; do - git show -s $PARENT > /dev/stderr - done - HAVE_FAILED=true - fi - return 1; -} - -if [ x"$1" = "x" ]; then - TEST_COMMIT="HEAD" -else - TEST_COMMIT="$1" -fi - -DO_CHECKOUT_TEST=0 -if [ x"$2" = "x--tree-checks" ]; then - DO_CHECKOUT_TEST=1 -fi - -IS_SIGNED "$TEST_COMMIT" "$DO_CHECKOUT_TEST" 1 1 -RES=$? -if [ "$RES" = 1 ]; then - if ! "$HAVE_FAILED"; then - echo "$TEST_COMMIT was not signed with a trusted key!" - fi -else - echo "There is a valid path from $TEST_COMMIT to $VERIFIED_ROOT where all commits are signed!" -fi - -exit $RES +done diff --git a/contrib/windeploy/detached-sig-create.sh b/contrib/windeploy/detached-sig-create.sh new file mode 100755 index 0000000000..bf4978d143 --- /dev/null +++ b/contrib/windeploy/detached-sig-create.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Copyright (c) 2014-2015 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 [ -z "$OSSLSIGNCODE" ]; then + OSSLSIGNCODE=osslsigncode +fi + +if [ ! -n "$1" ]; then + echo "usage: $0 <osslcodesign args>" + echo "example: $0 -key codesign.key" + exit 1 +fi + +OUT=signature-win.tar.gz +SRCDIR=unsigned +WORKDIR=./.tmp +OUTDIR="${WORKDIR}/out" +OUTSUBDIR="${OUTDIR}/win" +TIMESERVER=http://timestamp.comodoca.com +CERTFILE="win-codesign.cert" + +mkdir -p "${OUTSUBDIR}" +basename -a `ls -1 "${SRCDIR}"/*-unsigned.exe` | while read UNSIGNED; do + echo Signing "${UNSIGNED}" + "${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@" + "${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}" +done + +rm -f "${OUT}" +tar -C "${OUTDIR}" -czf "${OUT}" . +rm -rf "${WORKDIR}" +echo "Created ${OUT}" diff --git a/contrib/windeploy/win-codesign.cert b/contrib/windeploy/win-codesign.cert new file mode 100644 index 0000000000..200b30a3f0 --- /dev/null +++ b/contrib/windeploy/win-codesign.cert @@ -0,0 +1,99 @@ +-----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= +-----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= +-----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 +-----END CERTIFICATE----- diff --git a/contrib/zmq/zmq_sub3.4.py b/contrib/zmq/zmq_sub3.4.py index a2ff64b29b..1cb7eec0c0 100755 --- a/contrib/zmq/zmq_sub3.4.py +++ b/contrib/zmq/zmq_sub3.4.py @@ -57,7 +57,7 @@ class ZMQHandler(): msg = yield from self.zmqSubSocket.recv_multipart() topic = msg[0] body = msg[1] - sequence = "Unknown"; + sequence = "Unknown" if len(msg[-1]) == 4: msgSequence = struct.unpack('<I', msg[-1])[-1] sequence = str(msgSequence) diff --git a/depends/packages/zlib.mk b/depends/packages/zlib.mk index 7ff5d00bbd..589490800f 100644 --- a/depends/packages/zlib.mk +++ b/depends/packages/zlib.mk @@ -7,8 +7,10 @@ $(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca11 define $(package)_set_vars $(package)_build_opts= CC="$($(package)_cc)" $(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC" -$(package)_build_opts+=AR="$($(package)_ar)" $(package)_build_opts+=RANLIB="$($(package)_ranlib)" +$(package)_build_opts+=AR="$($(package)_ar)" +$(package)_build_opts_darwin+=AR="$($(package)_libtool)" +$(package)_build_opts_darwin+=ARFLAGS="-o" endef define $(package)_config_cmds diff --git a/doc/README.md b/doc/README.md index 09f32bc09e..5c00ab9150 100644 --- a/doc/README.md +++ b/doc/README.md @@ -3,7 +3,7 @@ Bitcoin Core 0.14.99 Setup --------------------- -Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. However, it downloads and stores the entire history of Bitcoin transactions (which is currently several GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. +Bitcoin Core is the original Bitcoin client and it builds the backbone of the network. It downloads and, by default, stores the entire history of Bitcoin transactions (which is currently more than 100 GBs); depending on the speed of your computer and network connection, the synchronization process can take anywhere from a few hours to a day or more. To download Bitcoin Core, visit [bitcoincore.org](https://bitcoincore.org/en/releases/). diff --git a/doc/developer-notes.md b/doc/developer-notes.md index 3a7e4f73b3..797507cd3e 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -132,7 +132,7 @@ Run with the -testnet option to run with "play bitcoins" on the test network, if are testing multi-machine code that needs to operate across the internet. If you are testing something that can run on one machine, run with the -regtest option. -In regression test mode, blocks can be created on-demand; see qa/rpc-tests/ for tests +In regression test mode, blocks can be created on-demand; see test/functional/ for tests that run in -regtest mode. **DEBUG_LOCKORDER** @@ -252,7 +252,7 @@ Wallet - *Rationale*: In RPC code that conditionally uses the wallet (such as `validateaddress`) it is easy to forget that global pointer `pwalletMain` - can be NULL. See `qa/rpc-tests/disablewallet.py` for functional tests + can be NULL. See `test/functional/disablewallet.py` for functional tests exercising the API with `-disablewallet` - Include `db_cxx.h` (BerkeleyDB header) only when `ENABLE_WALLET` is set diff --git a/doc/gitian-building.md b/doc/gitian-building.md index 442d2d605f..c2f55b5796 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -336,7 +336,7 @@ There will be a lot of warnings printed during the build of the image. These can Getting and building the inputs -------------------------------- -At this point you have two options, you can either use the automated script (found in [contrib/gitian-build.sh](/contrib/gitian-build.sh)) or you could manually do everything by following this guide. If you're using the automated script, then run it with the "--setup" command. Afterwards, run it with the "--build" command (example: "contrib/gitian-building.sh -b signer 0.13.0"). Otherwise ignore this. +At this point you have two options, you can either use the automated script (found in [contrib/gitian-build.sh](/contrib/gitian-build.sh)) or you could manually do everything by following this guide. If you're using the automated script, then run it with the "--setup" command. Afterwards, run it with the "--build" command (example: "contrib/gitian-build.sh -b signer 0.13.0"). Otherwise ignore this. Follow the instructions in [doc/release-process.md](release-process.md#fetch-and-create-inputs-first-time-or-when-dependency-versions-change) in the bitcoin repository under 'Fetch and create inputs' to install sources which require diff --git a/doc/release-notes.md b/doc/release-notes.md index eaa0b330eb..af792118d6 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -33,6 +33,55 @@ frequently tested on them. Notable changes =============== +Low-level RPC changes +--------------------- + +- Error codes have been updated to be more accurate for the following error cases: + - `getblock` now returns RPC_MISC_ERROR if the block can't be found on disk (for + example if the block has been pruned). Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the node is not in pruned mode. Previously returned RPC_METHOD_NOT_FOUND. + - `pruneblockchain` now returns RPC_INVALID_PARAMETER if the blocks cannot be pruned + because the supplied timestamp is too late. Previously returned RPC_INTERNAL_ERROR. + - `pruneblockchain` now returns RPC_MISC_ERROR if the blocks cannot be pruned + because the blockchain is too short. Previously returned RPC_INTERNAL_ERROR. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the supplied IP address + or subnet is invalid. Previously returned RPC_CLIENT_NODE_ALREADY_ADDED. + - `setban` now returns RPC_CLIENT_INVALID_IP_OR_SUBNET if the user tries to unban + a node that has not previously been banned. Previously returned RPC_MISC_ERROR. + - `removeprunedfunds` now returns RPC_WALLET_ERROR if bitcoind is unable to remove + the transaction. Previously returned RPC_INTERNAL_ERROR. + - `removeprunedfunds` now returns RPC_INVALID_PARAMETER if the transaction does not + exist in the wallet. Previously returned RPC_INTERNAL_ERROR. + - `fundrawtransaction` now returns RPC_INVALID_ADDRESS_OR_KEY if an invalid change + address is provided. Previously returned RPC_INVALID_PARAMETER. + - `fundrawtransaction` now returns RPC_WALLET_ERROR if bitcoind is unable to create + the transaction. The error message provides further details. Previously returned + RPC_INTERNAL_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the wallet. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_INVALID_PARAMETER if the provided transaction has + descendants in the mempool. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has + has been mined or conflicts with a mined transaction. Previously returned + RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction is not + BIP 125 replaceable. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has already + been bumped by a different transaction. Previously returned RPC_INVALID_REQUEST. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction contains + inputs which don't belong to this wallet. Previously returned RPC_INVALID_ADDRESS_OR_KEY. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has multiple change + outputs. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the provided transaction has no change + output. Previously returned RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too high. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the fee is too low. Previously returned + RPC_MISC_ERROR. + - `bumpfee` now returns RPC_WALLET_ERROR if the change output is too small to bump the + fee. Previously returned RPC_MISC_ERROR. + Credits ======= diff --git a/doc/release-notes/release-notes-0.14.0.md b/doc/release-notes/release-notes-0.14.0.md new file mode 100644 index 0000000000..c41f22979b --- /dev/null +++ b/doc/release-notes/release-notes-0.14.0.md @@ -0,0 +1,873 @@ +Bitcoin Core version 0.14.0 is now available from: + + <https://bitcoin.org/bin/bitcoin-core-0.14.0/> + +This is a new major version release, including new features, 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/> + +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 +=============== + +Performance Improvements +-------------- + +Validation speed and network propagation performance have been greatly +improved, leading to much shorter sync and initial block download times. + +- The script signature cache has been reimplemented as a "cuckoo cache", + allowing for more signatures to be cached and faster lookups. +- Assumed-valid blocks have been introduced which allows script validation to + be skipped for ancestors of known-good blocks, without changing the security + model. See below for more details. +- In some cases, compact blocks are now relayed before being fully validated as + per BIP152. +- P2P networking has been refactored with a focus on concurrency and + throughput. Network operations are no longer bottlenecked by validation. As a + result, block fetching is several times faster than previous releases in many + cases. +- The UTXO cache now claims unused mempool memory. This speeds up initial block + download as UTXO lookups are a major bottleneck there, and there is no use for + the mempool at that stage. + + +Manual Pruning +-------------- + +Bitcoin Core has supported automatically pruning the blockchain since 0.11. Pruning +the blockchain allows for significant storage space savings as the vast majority of +the downloaded data can be discarded after processing so very little of it remains +on the disk. + +Manual block pruning can now be enabled by setting `-prune=1`. Once that is set, +the RPC command `pruneblockchain` can be used to prune the blockchain up to the +specified height or timestamp. + +`getinfo` Deprecated +-------------------- + +The `getinfo` RPC command has been deprecated. Each field in the RPC call +has been moved to another command's output with that command also giving +additional information that `getinfo` did not provide. The following table +shows where each field has been moved to: + +|`getinfo` field | Moved to | +|------------------|-------------------------------------------| +`"version"` | `getnetworkinfo()["version"]` +`"protocolversion"`| `getnetworkinfo()["protocolversion"]` +`"walletversion"` | `getwalletinfo()["walletversion"]` +`"balance"` | `getwalletinfo()["balance"]` +`"blocks"` | `getblockchaininfo()["blocks"]` +`"timeoffset"` | `getnetworkinfo()["timeoffset"]` +`"connections"` | `getnetworkinfo()["connections"]` +`"proxy"` | `getnetworkinfo()["networks"][0]["proxy"]` +`"difficulty"` | `getblockchaininfo()["difficulty"]` +`"testnet"` | `getblockchaininfo()["chain"] == "test"` +`"keypoololdest"` | `getwalletinfo()["keypoololdest"]` +`"keypoolsize"` | `getwalletinfo()["keypoolsize"]` +`"unlocked_until"` | `getwalletinfo()["unlocked_until"]` +`"paytxfee"` | `getwalletinfo()["paytxfee"]` +`"relayfee"` | `getnetworkinfo()["relayfee"]` +`"errors"` | `getnetworkinfo()["warnings"]` + +ZMQ On Windows +-------------- + +Previously the ZeroMQ notification system was unavailable on Windows +due to various issues with ZMQ. These have been fixed upstream and +now ZMQ can be used on Windows. Please see [this document](https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md) for +help with using ZMQ in general. + +Nested RPC Commands in Debug Console +------------------------------------ + +The ability to nest RPC commands has been added to the debug console. This +allows users to have the output of a command become the input to another +command without running the commands separately. + +The nested RPC commands use bracket syntax (i.e. `getwalletinfo()`) and can +be nested (i.e. `getblock(getblockhash(1))`). Simple queries can be +done with square brackets where object values are accessed with either an +array index or a non-quoted string (i.e. `listunspent()[0][txid]`). Both +commas and spaces can be used to separate parameters in both the bracket syntax +and normal RPC command syntax. + +Network Activity Toggle +----------------------- + +A RPC command and GUI toggle have been added to enable or disable all p2p +network activity. The network status icon in the bottom right hand corner +is now the GUI toggle. Clicking the icon will either enable or disable all +p2p network activity. If network activity is disabled, the icon will +be grayed out with an X on top of it. + +Additionally the `setnetworkactive` RPC command has been added which does +the same thing as the GUI icon. The command takes one boolean parameter, +`true` enables networking and `false` disables it. + +Out-of-sync Modal Info Layer +---------------------------- + +When Bitcoin Core is out-of-sync on startup, a semi-transparent information +layer will be shown over top of the normal display. This layer contains +details about the current sync progress and estimates the amount of time +remaining to finish syncing. This layer can also be hidden and subsequently +unhidden by clicking on the progress bar at the bottom of the window. + +Support for JSON-RPC Named Arguments +------------------------------------ + +Commands sent over the JSON-RPC interface and through the `bitcoin-cli` binary +can now use named arguments. This follows the [JSON-RPC specification](http://www.jsonrpc.org/specification) +for passing parameters by-name with an object. + +`bitcoin-cli` has been updated to support this by parsing `name=value` arguments +when the `-named` option is given. + +Some examples: + + src/bitcoin-cli -named help command="help" + src/bitcoin-cli -named getblockhash height=0 + src/bitcoin-cli -named getblock blockhash=000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f + src/bitcoin-cli -named sendtoaddress address="(snip)" amount="1.0" subtractfeefromamount=true + +The order of arguments doesn't matter in this case. Named arguments are also +useful to leave out arguments that should stay at their default value. The +rarely-used arguments `comment` and `comment_to` to `sendtoaddress`, for example, can +be left out. However, this is not yet implemented for many RPC calls, this is +expected to land in a later release. + +The RPC server remains fully backwards compatible with positional arguments. + +Opt into RBF When Sending +------------------------- + +A new startup option, `-walletrbf`, has been added to allow users to have all +transactions sent opt into RBF support. The default value for this option is +currently `false`, so transactions will not opt into RBF by default. The new +`bumpfee` RPC can be used to replace transactions that opt into RBF. + +Sensitive Data Is No Longer Stored In Debug Console History +----------------------------------------------------------- + +The debug console maintains a history of previously entered commands that can be +accessed by pressing the Up-arrow key so that users can easily reuse previously +entered commands. Commands which have sensitive information such as passphrases and +private keys will now have a `(...)` in place of the parameters when accessed through +the history. + +Retaining the Mempool Across Restarts +------------------------------------- + +The mempool will be saved to the data directory prior to shutdown +to a `mempool.dat` file. This file preserves the mempool so that when the node +restarts the mempool can be filled with transactions without waiting for new transactions +to be created. This will also preserve any changes made to a transaction through +commands such as `prioritisetransaction` so that those changes will not be lost. + +Final Alert +----------- + +The Alert System was [disabled and deprecated](https://bitcoin.org/en/alert/2016-11-01-alert-retirement) in Bitcoin Core 0.12.1 and removed in 0.13.0. +The Alert System was retired with a maximum sequence final alert which causes any nodes +supporting the Alert System to display a static hard-coded "Alert Key Compromised" message which also +prevents any other alerts from overriding it. This final alert is hard-coded into this release +so that all old nodes receive the final alert. + +GUI Changes +----------- + + - After resetting the options by clicking the `Reset Options` button + in the options dialog or with the `-resetguioptions` startup option, + the user will be prompted to choose the data directory again. This + is to ensure that custom data directories will be kept after the + option reset which clears the custom data directory set via the choose + datadir dialog. + + - Multiple peers can now be selected in the list of peers in the debug + window. This allows for users to ban or disconnect multiple peers + simultaneously instead of banning them one at a time. + + - An indicator has been added to the bottom right hand corner of the main + window to indicate whether the wallet being used is a HD wallet. This + icon will be grayed out with an X on top of it if the wallet is not a + HD wallet. + +Low-level RPC changes +---------------------- + + - `importprunedfunds` only accepts two required arguments. Some versions accept + an optional third arg, which was always ignored. Make sure to never pass more + than two arguments. + + - The first boolean argument to `getaddednodeinfo` has been removed. This is + an incompatible change. + + - RPC command `getmininginfo` loses the "testnet" field in favor of the more + generic "chain" (which has been present for years). + + - A new RPC command `preciousblock` has been added which marks a block as + precious. A precious block will be treated as if it were received earlier + than a competing block. + + - A new RPC command `importmulti` has been added which receives an array of + JSON objects representing the intention of importing a public key, a + private key, an address and script/p2sh + + - Use of `getrawtransaction` for retrieving confirmed transactions with unspent + outputs has been deprecated. For now this will still work, but in the future + it may change to only be able to retrieve information about transactions in + the mempool or if `txindex` is enabled. + + - A new RPC command `getmemoryinfo` has been added which will return information + about the memory usage of Bitcoin Core. This was added in conjunction with + optimizations to memory management. See [Pull #8753](https://github.com/bitcoin/bitcoin/pull/8753) + for more information. + + - A new RPC command `bumpfee` has been added which allows replacing an + unconfirmed wallet transaction that signaled RBF (see the `-walletrbf` + startup option above) with a new transaction that pays a higher fee, and + should be more likely to get confirmed quickly. + +HTTP REST Changes +----------------- + + - UTXO set query (`GET /rest/getutxos/<checkmempool>/<txid>-<n>/<txid>-<n> + /.../<txid>-<n>.<bin|hex|json>`) responses were changed to return status + code `HTTP_BAD_REQUEST` (400) instead of `HTTP_INTERNAL_SERVER_ERROR` (500) + when requests contain invalid parameters. + +Minimum Fee Rate Policies +------------------------- + +Since the changes in 0.12 to automatically limit the size of the mempool and improve the performance of block creation in mining code it has not been important for relay nodes or miners to set `-minrelaytxfee`. With this release the following concepts that were tied to this option have been separated out: +- incremental relay fee used for calculating BIP 125 replacement and mempool limiting. (1000 satoshis/kB) +- calculation of threshold for a dust output. (effectively 3 * 1000 satoshis/kB) +- minimum fee rate of a package of transactions to be included in a block created by the mining code. If miners wish to set this minimum they can use the new `-blockmintxfee` option. (defaults to 1000 satoshis/kB) + +The `-minrelaytxfee` option continues to exist but is recommended to be left unset. + +Fee Estimation Changes +---------------------- + +- Since 0.13.2 fee estimation for a confirmation target of 1 block has been + disabled. The fee slider will no longer be able to choose a target of 1 block. + This is only a minor behavior change as there was often insufficient + data for this target anyway. `estimatefee 1` will now always return -1 and + `estimatesmartfee 1` will start searching at a target of 2. + +- The default target for fee estimation is changed to 6 blocks in both the GUI + (previously 25) and for RPC calls (previously 2). + +Removal of Priority Estimation +------------------------------ + +- Estimation of "priority" needed for a transaction to be included within a target + number of blocks has been removed. The RPC calls are deprecated and will either + return -1 or 1e24 appropriately. The format for `fee_estimates.dat` has also + changed to no longer save these priority estimates. It will automatically be + converted to the new format which is not readable by prior versions of the + software. + +- Support for "priority" (coin age) transaction sorting for mining is + considered deprecated in Core and will be removed in the next major version. + This is not to be confused with the `prioritisetransaction` RPC which will remain + supported by Core for adding fee deltas to transactions. + +P2P connection management +-------------------------- + +- Peers manually added through the `-addnode` option or `addnode` RPC now have their own + limit of eight connections which does not compete with other inbound or outbound + connection usage and is not subject to the limitation imposed by the `-maxconnections` + option. + +- New connections to manually added peers are performed more quickly. + +Introduction of assumed-valid blocks +------------------------------------- + +- A significant portion of the initial block download time is spent verifying + scripts/signatures. Although the verification must pass to ensure the security + of the system, no other result from this verification is needed: If the node + knew the history of a given block were valid it could skip checking scripts + for its ancestors. + +- A new configuration option 'assumevalid' is provided to express this knowledge + to the software. Unlike the 'checkpoints' in the past this setting does not + force the use of a particular chain: chains that are consistent with it are + processed quicker, but other chains are still accepted if they'd otherwise + be chosen as best. Also unlike 'checkpoints' the user can configure which + block history is assumed true, this means that even outdated software can + sync more quickly if the setting is updated by the user. + +- Because the validity of a chain history is a simple objective fact it is much + easier to review this setting. As a result the software ships with a default + value adjusted to match the current chain shortly before release. The use + of this default value can be disabled by setting -assumevalid=0 + +Fundrawtransaction change address reuse +---------------------------------------- + +- Before 0.14, `fundrawtransaction` was by default wallet stateless. In + almost all cases `fundrawtransaction` does add a change-output to the + outputs of the funded transaction. Before 0.14, the used keypool key was + never marked as change-address key and directly returned to the keypool + (leading to address reuse). Before 0.14, calling `getnewaddress` + directly after `fundrawtransaction` did generate the same address as + the change-output address. + +- Since 0.14, fundrawtransaction does reserve the change-output-key from + the keypool by default (optional by setting `reserveChangeKey`, default = + `true`) + +- Users should also consider using `getrawchangeaddress()` in conjunction + with `fundrawtransaction`'s `changeAddress` option. + +Unused mempool memory used by coincache +---------------------------------------- + +- Before 0.14, memory reserved for mempool (using the `-maxmempool` option) + went unused during initial block download, or IBD. In 0.14, the UTXO DB cache + (controlled with the `-dbcache` option) borrows memory from the mempool + when there is extra memory available. This may result in an increase in + memory usage during IBD for those previously relying on only the `-dbcache` + option to limit memory during that time. + +0.14.0 Change log +================= + +Detailed release notes follow. This overview includes changes that affect +behavior, not code moves, minor refactors and string updates. For convenience +in locating the code changes and accompanying discussion, both the pull request +and git merge commit are mentioned. + +### RPC and other APIs +- #8421 `b77bb95` httpserver: drop boost dependency (theuni) +- #8638 `f061415` rest.cpp: change `HTTP_INTERNAL_SERVER_ERROR` to `HTTP_BAD_REQUEST` (djpnewton) +- #8272 `91990ee` Make the dummy argument to getaddednodeinfo optional (sipa) +- #8722 `bb843ad` bitcoin-cli: More detailed error reporting (laanwj) +- #6996 `7f71a3c` Add preciousblock RPC (sipa) +- #8788 `97c7f73` Give RPC commands more information about the RPC request (jonasschnelli) +- #7948 `5d2c8e5` Augment getblockchaininfo bip9\_softforks data (mruddy) +- #8980 `0e22855` importmulti: Avoid using boost::variant::operator!=, which is only in newer boost versions (luke-jr) +- #9025 `4d8558a` Getrawtransaction should take a bool for verbose (jnewbery) +- #8811 `5754e03` Add support for JSON-RPC named arguments (laanwj) +- #9520 `2456a83` Deprecate non-txindex getrawtransaction and better warning (sipa) +- #9518 `a65ced1` Return height of last block pruned by pruneblockchain RPC (ryanofsky) +- #9222 `7cb024e` Add 'subtractFeeFromAmount' option to 'fundrawtransaction' (dooglus) +- #8456 `2ef52d3` Simplified `bumpfee` command (mrbandrews) +- #9516 `727a798` Bug-fix: listsinceblock: use fork point as reference for blocks in reorg'd chains (kallewoof) +- #9640 `7bfb770` Bumpfee: bugfixes for error handling and feerate calculation (sdaftuar) +- #9673 `8d6447e` Set correct metadata on bumpfee wallet transactions (ryanofsky) +- #9650 `40f7e27` Better handle invalid parameters to signrawtransaction (TheBlueMatt) +- #9682 `edc9e63` Require timestamps for importmulti keys (ryanofsky) +- #9108 `d8e8b06` Use importmulti timestamp when importing watch only keys (on top of #9682) (ryanofsky) +- #9756 `7a93af8` Return error when importmulti called with invalid address (ryanofsky) +- #9778 `ad168ef` Add two hour buffer to manual pruning (morcos) +- #9761 `9828f9a` Use 2 hour grace period for key timestamps in importmulti rescans (ryanofsky) +- #9474 `48d7e0d` Mark the minconf parameter to move as ignored (sipa) +- #9619 `861cb0c` Bugfix: RPC/Mining: GBT should return 1 MB sizelimit before segwit activates (luke-jr) +- #9773 `9072395` Return errors from importmulti if complete rescans are not successful (ryanofsky) + +### Block and transaction handling +- #8391 `37d83bb` Consensus: Remove ISM (NicolasDorier) +- #8365 `618c9dd` Treat high-sigop transactions as larger rather than rejecting them (sipa) +- #8814 `14b7b3f` wallet, policy: ParameterInteraction: Don't allow 0 fee (MarcoFalke) +- #8515 `9bdf526` A few mempool removal optimizations (sipa) +- #8448 `101c642` Store mempool and prioritization data to disk (sipa) +- #7730 `3c03dc2` Remove priority estimation (morcos) +- #9111 `fb15610` Remove unused variable `UNLIKELY_PCT` from fees.h (fanquake) +- #9133 `434e683` Unset fImporting for loading mempool (morcos) +- #9179 `b9a87b4` Set `DEFAULT_LIMITFREERELAY` = 0 kB/minute (MarcoFalke) +- #9239 `3fbf079` Disable fee estimates for 1-block target (morcos) +- #7562 `1eef038` Bump transaction version default to 2 (btcdrak) +- #9313,#9367 If we don't allow free txs, always send a fee filter (morcos) +- #9346 `b99a093` Batch construct batches (sipa) +- #9262 `5a70572` Prefer coins that have fewer ancestors, sanity check txn before ATMP (instagibbs) +- #9288 `1ce7ede` Fix a bug if the min fee is 0 for FeeFilterRounder (morcos) +- #9395 `0fc1c31` Add test for `-walletrejectlongchains` (morcos) +- #9107 `7dac1e5` Safer modify new coins (morcos) +- #9312 `a72f76c` Increase mempool expiry time to 2 weeks (morcos) +- #8610 `c252685` Share unused mempool memory with coincache (sipa) +- #9138 `f646275` Improve fee estimation (morcos) +- #9408 `46b249e` Allow shutdown during LoadMempool, dump only when necessary (jonasschnelli) +- #9310 `8c87f17` Assert FRESH validity in CCoinsViewCache::BatchWrite (ryanofsky) +- #7871 `e2e624d` Manual block file pruning (mrbandrews) +- #9507 `0595042` Fix use-after-free in CTxMemPool::removeConflicts() (sdaftuar) +- #9380 `dd98f04` Separate different uses of minimum fees (morcos) +- #9596 `71148b8` bugfix save feeDelta instead of priorityDelta in DumpMempool (morcos) +- #9371 `4a1dc35` Notify on removal (morcos) +- #9519 `9b4d267` Exclude RBF replacement txs from fee estimation (morcos) +- #8606 `e2a1a1e` Fix some locks (sipa) +- #8681 `6898213` Performance Regression Fix: Pre-Allocate txChanged vector (JeremyRubin) +- #8223 `744d265` c++11: Use std::unique\_ptr for block creation (domob1812) +- #9125 `7490ae8` Make CBlock a vector of shared\_ptr of CTransactions (sipa) +- #8930 `93566e0` Move orphan processing to ActivateBestChain (TheBlueMatt) +- #8580 `46904ee` Make CTransaction actually immutable (sipa) +- #9240 `a1dcf2e` Remove txConflicted (morcos) +- #8589 `e8cfe1e` Inline CTxInWitness inside CTxIn (sipa) +- #9349 `2db4cbc` Make CScript (and prevector) c++11 movable (sipa) +- #9252 `ce5c1f4` Release cs\_main before calling ProcessNewBlock, or processing headers (cmpctblock handling) (sdaftuar) +- #9283 `869781c` A few more CTransactionRef optimizations (sipa) +- #9499 `9c9af5a` Use recent-rejects, orphans, and recently-replaced txn for compact-block-reconstruction (TheBlueMatt) +- #9813 `3972a8e` Read/write mempool.dat as a binary (paveljanik) + +### P2P protocol and network code +- #8128 `1030fa7` Turn net structures into dumb storage classes (theuni) +- #8282 `026c6ed` Feeler connections to increase online addrs in the tried table (EthanHeilman) +- #8462 `53f8f22` Move AdvertiseLocal debug output to net category (Mirobit) +- #8612 `84decb5` Check for compatibility with download in FindNextBlocksToDownload (sipa) +- #8594 `5b2ea29` Do not add random inbound peers to addrman (gmaxwell) +- #8085 `6423116` Begin encapsulation (theuni) +- #8715 `881d7ea` only delete CConnman if it's been created (theuni) +- #8707 `f07424a` Fix maxuploadtarget setting (theuni) +- #8661 `d2e4655` Do not set an addr time penalty when a peer advertises itself (gmaxwell) +- #8822 `9bc6a6b` Consistent checksum handling (laanwj) +- #8936 `1230890` Report NodeId in misbehaving debug (rebroad) +- #8968 `3cf496d` Don't hold cs\_main when calling ProcessNewBlock from a cmpctblock (TheBlueMatt) +- #9002 `e1d1f57` Make connect=0 disable automatic outbound connections (gmaxwell) +- #9050 `fcf61b8` Make a few values immutable, and use deterministic randomness for the localnonce (theuni) +- #8969 `3665483` Decouple peer-processing-logic from block-connection-logic (#2) (TheBlueMatt) +- #8708 `c8c572f` have CConnman handle message sending (theuni) +- #8709 `1e50d22` Allow filterclear messages for enabling TX relay only (rebroad) +- #9045 `9f554e0` Hash P2P messages as they are received instead of at process-time (TheBlueMatt) +- #9026 `dc6b940` Fix handling of invalid compact blocks (sdaftuar) +- #8996 `ab914a6` Network activity toggle (luke-jr) +- #9131 `62af164` fNetworkActive is not protected by a lock, use an atomic (jonasschnelli) +- #8872 `0c577f2` Remove block-request logic from INV message processing (TheBlueMatt) +- #8690 `791b58d` Do not fully sort all nodes for addr relay (sipa) +- #9128 `76fec09` Decouple CConnman and message serialization (theuni) +- #9226 `3bf06e9` Remove fNetworkNode and pnodeLocalHost (gmaxwell) +- #9352 `a7f7651` Attempt reconstruction from all compact block announcements (sdaftuar) +- #9319 `a55716a` Break addnode out from the outbound connection limits (gmaxwell) +- #9261 `2742568` Add unstored orphans with rejected parents to recentRejects (morcos) +- #9441 `8b66bf7` Massive speedup. Net locks overhaul (theuni) +- #9375 `3908fc4` Relay compact block messages prior to full block connection (TheBlueMatt) +- #9400 `8a445c5` Set peers as HB peers upon full block validation (instagibbs) +- #9561 `6696b46` Wake message handling thread when we receive a new block (TheBlueMatt) +- #9535 `82274c0` Split CNode::cs\_vSend: message processing and message sending (TheBlueMatt) +- #9606 `3f9f962` Consistently use GetTimeMicros() for inactivity checks (sdaftuar) +- #9594 `fd70211` Send final alert message to older peers after connecting (gmaxwell) +- #9626 `36966a1` Clean up a few CConnman cs\_vNodes/CNode things (TheBlueMatt) +- #9609 `4966917` Fix remaining net assertions (theuni) +- #9671 `7821db3` Fix super-unlikely race introduced in 236618061a445d2cb11e72 (TheBlueMatt) +- #9730 `33f3b21` Remove bitseed.xf2.org form the dns seed list (jonasschnelli) +- #9698 `2447c10` Fix socket close race (theuni) +- #9708 `a06ede9` Clean up all known races/platform-specific UB at the time PR was opened (TheBlueMatt) +- #9715 `b08656e` Disconnect peers which we do not receive VERACKs from within 60 sec (TheBlueMatt) +- #9720 `e87ce95` Fix banning and disallow sending messages before receiving verack (theuni) +- #9268 `09c4fd1` Fix rounding privacy leak introduced in #9260 (TheBlueMatt) +- #9075 `9346f84` Decouple peer-processing-logic from block-connection-logic (#3) (TheBlueMatt) +- #8688 `047ded0` Move static global randomizer seeds into CConnman (sipa) +- #9289 `d9ae1ce` net: drop boost::thread\_group (theuni) + +### Validation +- #9014 `d04aeba` Fix block-connection performance regression (TheBlueMatt) +- #9299 `d52ce89` Remove no longer needed check for premature v2 txs (morcos) +- #9273 `b68685a` Remove unused `CDiskBlockPos*` argument from ProcessNewBlock (TheBlueMatt) +- #8895 `b83264d` Better SigCache Implementation (JeremyRubin) +- #9490 `e126d0c` Replace FindLatestBefore used by importmulti with FindEarliestAtLeast (gmaxwell) +- #9484 `812714f` Introduce assumevalid setting to skip validation presumed valid scripts (gmaxwell) +- #9511 `7884956` Don't overwrite validation state with corruption check (morcos) +- #9765 `1e92e04` Harden against mistakes handling invalid blocks (sdaftuar) +- #9779 `3c02b95` Update nMinimumChainWork and defaultAssumeValid (gmaxwell) +- #8524 `19b0f33` Precompute sighashes (sipa) +- #9791 `1825a03` Avoid VLA in hash.h (sipa) + +### Build system +- #8238 `6caf3ee` ZeroMQ 4.1.5 && ZMQ on Windows (fanquake) +- #8520 `b40e19c` Remove check for `openssl/ec.h` (laanwj) +- #8617 `de07fdc` Include instructions to extract Mac OS X SDK on Linux using 7zip and SleuthKit (luke-jr) +- #8566 `7b98895` Easy to use gitian building script (achow101) +- #8604 `f256843` build,doc: Update for 0.13.0+ and OpenBSD 5.9 (laanwj) +- #8640 `2663e51` depends: Remove Qt46 package (fanquake) +- #8645 `8ea4440` Remove unused Qt 4.6 patch (droark) +- #8608 `7e9ab95` Install manpages via make install, also add some autogenerated manpages (nomnombtc) +- #8781 `ca69ef4` contrib: delete `qt_translations.py` (MarcoFalke) +- #8783 `64dc645` share: remove qt/protobuf.pri (MarcoFalke) +- #8423 `3166dff` depends: expat 2.2.0, ccache 3.3.1, fontconfig 2.12.1 (fanquake) +- #8791 `b694b0d` travis: cross-mac: explicitly enable gui (MarcoFalke) +- #8820 `dc64141` depends: Fix Qt compilation with Xcode 8 (fanquake) +- #8730 `489a6ab` depends: Add libevent compatibility patch for windows (laanwj) +- #8819 `c841816` depends: Boost 1.61.0 (fanquake) +- #8826 `f560d95` Do not include `env_win.cc` on non-Windows systems (paveljanik) +- #8948 `e077e00` Reorder Windows gitian build order to match Linux (Michagogo) +- #8568 `078900d` new var `DIST_CONTRIB` adds useful things for packagers from contrib (nomnombtc) +- #9114 `21e6c6b` depends: Set `OSX_MIN_VERSION` to 10.8 (fanquake) +- #9140 `018a4eb` Bugfix: Correctly replace generated headers and fail cleanly (luke-jr) +- #9156 `a8b2a82` Add compile and link options echo to configure (jonasschnelli) +- #9393 `03d85f6` Include cuckoocache header in Makefile (MarcoFalke) +- #9420 `bebe369` Fix linker error when configured with --enable-lcov (droark) +- #9412 `53442af` Fix 'make deploy' for OSX (jonasschnelli) +- #9475 `7014506` Let autoconf detect presence of `EVP_MD_CTX_new` (luke-jr) +- #9513 `bbf193f` Fix qt distdir builds (theuni) +- #9471 `ca615e6` depends: libevent 2.1.7rc (fanquake) +- #9468 `f9117f2` depends: Dependency updates for 0.14.0 (fanquake) +- #9469 `01c4576` depends: Qt 5.7.1 (fanquake) +- #9574 `5ac6687` depends: Fix QT build on OSX (fanquake) +- #9646 `720b579` depends: Fix cross build for qt5.7 (theuni) +- #9705 `6a55515` Add options to override BDB cflags/libs (laanwj) +- #8249 `4e1567a` Enable (and check for) 64-bit ASLR on Windows (laanwj) +- #9758 `476cc47` Selectively suppress deprecation warnings (jonasschnelli) +- #9783 `6d61a2b` release: bump gitian descriptors for a new 0.14 package cache (theuni) +- #9789 `749fe95` build: add --enable-werror and warn on vla's (theuni) +- #9831 `99fd85c` build: force a c++ standard to be specified (theuni) + +### GUI +- #8192 `c503863` Remove URLs from About dialog translations (fanquake) +- #8540 `36404ae` Fix random segfault when closing "Choose data directory" dialog (laanwj) +- #8517 `2468292` Show wallet HD state in statusbar (jonasschnelli) +- #8463 `62a5a8a` Remove Priority from coincontrol dialog (MarcoFalke) +- #7579 `0606f95` Show network/chain errors in the GUI (jonasschnelli) +- #8583 `c19f8a4` Show XTHIN in GUI (rebroad) +- #7783 `4335d5a` RPC-Console: support nested commands and simple value queries (jonasschnelli) +- #8672 `6052d50` Show transaction size in transaction details window (Cocosoft) +- #8777 `fec6af7` WalletModel: Expose disablewallet (MarcoFalke) +- #8371 `24f72e9` Add out-of-sync modal info layer (jonasschnelli) +- #8885 `b2fec4e` Fix ban from qt console (theuni) +- #8821 `bf8e68a` sync-overlay: Don't block during reindex (MarcoFalke) +- #8906 `088d1f4` sync-overlay: Don't show progress twice (MarcoFalke) +- #8918 `47ace42` Add "Copy URI" to payment request context menu (luke-jr) +- #8925 `f628d9a` Display minimum ping in debug window (rebroad) +- #8774 `3e942a7` Qt refactors to better abstract wallet access (luke-jr) +- #8985 `7b1bfa3` Use pindexBestHeader instead of setBlockIndexCandidates for NotifyHeaderTip() (jonasschnelli) +- #8989 `d2143dc` Overhaul smart-fee slider, adjust default confirmation target (jonasschnelli) +- #9043 `273bde3` Return useful error message on ATMP failure (MarcoFalke) +- #9088 `4e57824` Reduce ambiguity of warning message (rebroad) +- #8874 `e984730` Multiple Selection for peer and ban tables (achow101) +- #9145 `924745d` Make network disabled icon 50% opaque (MarcoFalke) +- #9130 `ac489b2` Mention the new network toggle functionality in the tooltip (paveljanik) +- #9218 `4d955fc` Show progress overlay when clicking spinner icon (laanwj) +- #9280 `e15660c` Show ModalOverlay by pressing the progress bar, allow hiding (jonasschnelli) +- #9296 `fde7d99` Fix missed change to WalletTx structure (morcos) +- #9266 `2044e37` Bugfix: Qt/RPCConsole: Put column enum in the right places (luke-jr) +- #9255 `9851a84` layoutAboutToChange signal is called layoutAboutToBeChanged (laanwj) +- #9330 `47e6a19` Console: add security warning (jonasschnelli) +- #9329 `db45ad8` Console: allow empty arguments (jonasschnelli) +- #8877 `6dc4c43` Qt RPC console: history sensitive-data filter, and saving input line when browsing history (luke-jr) +- #9462 `649cf5f` Do not translate tilde character (MarcoFalke) +- #9457 `123ea73` Select more files for translation (MarcoFalke) +- #9413 `fd7d8c7` CoinControl: Allow non-wallet owned change addresses (jonasschnelli) +- #9461 `b250686` Improve progress display during headers-sync and peer-finding (jonasschnelli) +- #9588 `5086452` Use nPowTargetSpacing constant (MarcoFalke) +- #9637 `d9e4d1d` Fix transaction details output-index to reflect vout index (jonasschnelli) +- #9718 `36f9d3a` Qt/Intro: Various fixes (luke-jr) +- #9735 `ec66d06` devtools: Handle Qt formatting characters edge-case in update-translations.py (laanwj) +- #9755 `a441db0` Bugfix: Qt/Options: Restore persistent "restart required" notice (luke-jr) +- #9817 `7d75a5a` Fix segfault crash when shutdown the GUI in disablewallet mode (jonasschnelli) + +### Wallet +- #8152 `b9c1cd8` Remove `CWalletDB*` parameter from CWallet::AddToWallet (pstratem) +- #8432 `c7e05b3` Make CWallet::fFileBacked private (pstratem) +- #8445 `f916700` Move CWallet::setKeyPool to private section of CWallet (pstratem) +- #8564 `0168019` Remove unused code/conditions in ReadAtCursor (jonasschnelli) +- #8601 `37ac678` Add option to opt into full-RBF when sending funds (rebase, original by petertodd) (laanwj) +- #8494 `a5b20ed` init, wallet: ParameterInteraction() iff wallet enabled (MarcoFalke) +- #8760 `02ac669` init: Get rid of some `ENABLE_WALLET` (MarcoFalke) +- #8696 `a1f8d3e` Wallet: Remove last external reference to CWalletDB (pstratem) +- #8768 `886e8c9` init: Get rid of fDisableWallet (MarcoFalke) +- #8486 `ab0b411` Add high transaction fee warnings (MarcoFalke) +- #8851 `940748b` Move key derivation logic from GenerateNewKey to DeriveNewChildKey (pstratem) +- #8287 `e10af96` Set fLimitFree = true (MarcoFalke) +- #8928 `c587577` Fix init segfault where InitLoadWallet() calls ATMP before genesis (TheBlueMatt) +- #7551 `f2d7056` Add importmulti RPC call (pedrobranco) +- #9016 `0dcb888` Return useful error message on ATMP failure (instagibbs) +- #8753 `f8723d2` Locked memory manager (laanwj) +- #8828 `a4fd8df` Move CWalletDB::ReorderTransactions to CWallet (pstratem) +- #8977 `6a1343f` Refactor wallet/init interaction (Reaccept wtx, flush thread) (jonasschnelli) +- #9036 `ed0cc50` Change default confirm target from 2 to 6 (laanwj) +- #9071 `d1871da` Declare wallet.h functions inline (sipa) +- #9132 `f54e460` Make strWalletFile const (jonasschnelli) +- #9141 `5ea5e04` Remove unnecessary calls to CheckFinalTx (jonasschnelli) +- #9165 `c01f16a` SendMoney: use already-calculated balance (instagibbs) +- #9311 `a336d13` Flush wallet after abandontransaction (morcos) +- #8717 `38e4887` Addition of ImmatureCreditCached to MarkDirty() (spencerlievens) +- #9446 `510c0d9` SetMerkleBranch: remove unused code, remove cs\_main lock requirement (jonasschnelli) +- #8776 `2a524b8` Wallet refactoring leading up to multiwallet (luke-jr) +- #9465 `a7d55c9` Do not perform ECDSA signing in the fee calculation inner loop (gmaxwell) +- #9404 `12e3112` Smarter coordination of change and fee in CreateTransaction (morcos) +- #9377 `fb75cd0` fundrawtransaction: Keep change-output keys by default, make it optional (jonasschnelli) +- #9578 `923dc44` Add missing mempool lock for CalculateMemPoolAncestors (TheBlueMatt) +- #9227 `02464da` Make nWalletDBUpdated atomic to avoid a potential race (pstratem) +- #9764 `f8af89a` Prevent "overrides a member function but is not marked 'override'" warnings (laanwj) +- #9771 `e43a585` Add missing cs\_wallet lock that triggers new lock held assertion (ryanofsky) +- #9316 `3097ea4` Disable free transactions when relay is disabled (MarcoFalke) +- #9615 `d2c9e4d` Wallet incremental fee (morcos) +- #9760 `40c754c` Remove importmulti always-true check (ryanofsky) + +### Tests and QA +- #8270 `6e5e5ab` Tests: Use portable #! in python scripts (/usr/bin/env) (ChoHag) +- #8534,#8504 Remove java comparison tool (laanwj,MarcoFalke) +- #8482 `740cff5` Use single cache dir for chains (MarcoFalke) +- #8450 `21857d2` Replace `rpc_wallet_tests.cpp` with python RPC unit tests (pstratem) +- #8671 `ddc3080` Minimal fix to slow prevector tests as stopgap measure (JeremyRubin) +- #8680 `666eaf0` Address Travis spurious failures (theuni) +- #8789 `e31a43c` pull-tester: Only print output when failed (MarcoFalke) +- #8810 `14e8f99` tests: Add exception error message for JSONRPCException (laanwj) +- #8830 `ef0801b` test: Add option to run bitcoin-util-test.py manually (jnewbery) +- #8881 `e66cc1d` Add some verbose logging to bitcoin-util-test.py (jnewbery) +- #8922 `0329511` Send segwit-encoded blocktxn messages in p2p-compactblocks (TheBlueMatt) +- #8873 `74dc388` Add microbenchmarks to profile more code paths (ryanofsky) +- #9032 `6a8be7b` test: Add format-dependent comparison to bctest (laanwj) +- #9023 `774db92` Add logging to bitcoin-util-test.py (jnewbery) +- #9065 `c9bdf9a` Merge `doc/unit-tests.md` into `src/test/README.md` (laanwj) +- #9069 `ed64bce` Clean up bctest.py and bitcoin-util-test.py (jnewbery) +- #9095 `b8f43e3` test: Fix test\_random includes (MarcoFalke) +- #8894 `faec09b` Testing: Include fRelay in mininode version messages (jnewbery) +- #9097 `e536499` Rework `sync_*` and preciousblock.py (MarcoFalke) +- #9049 `71bc39e` Remove duplicatable duplicate-input check from CheckTransaction (TheBlueMatt) +- #9136 `b422913` sync\_blocks cleanup (ryanofsky) +- #9151 `4333b1c` proxy\_test: Calculate hardcoded port numbers (MarcoFalke) +- #9206 `e662d28` Make test constant consistent with consensus.h (btcdrak) +- #9139 `0de7fd3` Change sync\_blocks to pick smarter maxheight (on top of #9196) (ryanofsky) +- #9100 `97ec6e5` tx\_valid: re-order inputs to how they are encoded (dcousens) +- #9202 `e56cf67` bench: Add support for measuring CPU cycles (laanwj) +- #9223 `5412c08` unification of Bloom filter representation (s-matthew-english) +- #9257 `d7ba4a2` Dump debug logs on travis failures (sdaftuar) +- #9221 `9e4bb31` Get rid of duplicate code (MarcoFalke) +- #9274 `919db03` Use cached utxo set to fix performance regression (MarcoFalke) +- #9276 `ea33f19` Some minor testing cleanups (morcos) +- #9291 `8601784` Remove mapOrphanTransactionsByPrev from DoS\_tests (sipa) +- #9309 `76fcd9d` Wallet needs to stay unlocked for whole test (morcos) +- #9172 `5bc209c` Resurrect pstratem's "Simple fuzzing framework" (laanwj) +- #9331 `c6fd923` Add test for rescan feature of wallet key import RPCs (ryanofsky) +- #9354 `b416095` Make fuzzer actually test CTxOutCompressor (sipa) +- #9390,#9416 travis: make distdir (MarcoFalke) +- #9308 `0698639` test: Add CCoinsViewCache Access/Modify/Write tests (ryanofsky) +- #9406 `0f921e6` Re-enable a blank v1 Tx JSON test (droark) +- #9435 `dbc8a8c` Removed unused variable in test, fixing warning (ryanofsky) +- #9436 `dce853e` test: Include tx data in `EXTRA_DIST` (MarcoFalke) +- #9525 `02e5308` test: Include tx data in `EXTRA_DIST` (MarcoFalke) +- #9498 `054d664` Basic CCheckQueue Benchmarks (JeremyRubin) +- #9554 `0b96abc` test: Avoid potential NULL pointer dereference in `addrman_tests.cpp` (practicalswift) +- #9628 `f895023` Increase a sync\_blocks timeout in pruning.py (sdaftuar) +- #9638 `a7ea2f8` Actually test assertions in pruning.py (MarcoFalke) +- #9647 `e99f0d7` Skip RAII event tests if libevent is built without `event_set_mem_functions` (luke-jr) +- #9691 `fc67cd2` Init ECC context for `test_bitcoin_fuzzy` (gmaxwell) +- #9712 `d304fef` bench: Fix initialization order in registration (laanwj) +- #9707 `b860915` Fix RPC failure testing (jnewbery) +- #9269 `43e8150` Align struct COrphan definition (sipa) +- #9820 `599c69a` Fix pruning test broken by 2 hour manual prune window (ryanofsky) +- #9824 `260c71c` qa: Check return code when stopping nodes (MarcoFalke) +- #9875 `50953c2` tests: Fix dangling pwalletMain pointer in wallet tests (laanwj) +- #9839 `eddaa6b` [qa] Make import-rescan.py watchonly check reliable (ryanofsky) + +### Documentation +- #8332 `806b9e7` Clarify witness branches in transaction.h serialization (dcousens) +- #8935 `0306978` Documentation: Building on Windows with WSL (pooleja) +- #9144 `c98f6b3` Correct waitforblockheight example help text (fanquake) +- #9407 `041331e` Added missing colons in when running help command (anditto) +- #9378 `870cd2b` Add documentation for CWalletTx::fFromMe member (ryanofsky) +- #9297 `0b73807` Various RPC help outputs updated (Mirobit) +- #9613 `07421cf` Clarify getbalance help string to explain interaction with bumpfee (ryanofsky) +- #9663 `e30d928` Clarify listunspent amount description (instagibbs) +- #9396 `d65a13b` Updated listsinceblock rpc documentation (accraze) +- #8747 `ce43630` rpc: Fix transaction size comments and RPC help text (jnewbery) +- #8058 `bbd9740` Doc: Add issue template (AmirAbrams) +- #8567 `85d4e21` Add default port numbers to REST doc (djpnewton) +- #8624 `89de153` build: Mention curl (MarcoFalke) +- #8786 `9da7366` Mandatory copyright agreement (achow101) +- #8823 `7b05af6` Add privacy recommendation when running hidden service (laanwj) +- #9433 `caa2f10` Update the Windows build notes (droark) +- #8879 `f928050` Rework docs (MarcoFalke) +- #8887 `61d191f` Improve GitHub issue template (fanquake) +- #8787 `279bbad` Add missing autogen to example builds (AmirAbrams) +- #8892 `d270c30` Add build instructions for FreeBSD (laanwj) +- #8890 `c71a654` Update Doxygen configuration file (fanquake) +- #9207 `fa1f944` Move comments above bash command in build-unix (AmirAbrams) +- #9219 `c4522e7` Improve windows build instructions using Linux subsystem (laanwj) +- #8954 `932d02a` contrib: Add README for pgp keys (MarcoFalke) +- #9093 `2fae5b9` release-process: Mention GitHub release and archived release notes (MarcoFalke) +- #8743 `bae178f` Remove old manpages from contrib/debian in favour of doc/man (fanquake) +- #9550 `4105cb6` Trim down the XP notice and say more about what we support (gmaxwell) +- #9246 `9851498` Developer docs about existing subtrees (gmaxwell) +- #9401 `c2ea1e6` Make rpcauth help message clearer, add example in example .conf (instagibbs) +- #9022,#9033 Document dropping OS X 10.7 support (fanquake, MarcoFalke) +- #8771 `bc9e3ab` contributing: Mention not to open several pulls (luke-jr) +- #8852 `7b784cc` Mention Gitian building script in doc (Laudaa) (laanwj) +- #8915 `03dd707` Add copyright/patent issues to possible NACK reasons (petertodd) +- #8965 `23e03f8` Mention that PPA doesn't support Debian (anduck) +- #9115 `bfc7aad` Mention reporting security issues responsibly (paveljanik) +- #9840 `08e0690` Update sendfrom RPC help to correct coin selection misconception (ryanofsky) +- #9865 `289204f` Change bitcoin address in RPC help message (marijnfs) + +### Miscellaneous +- #8274 `7a2d402` util: Update tinyformat (laanwj) +- #8291 `5cac8b1` util: CopyrightHolders: Check for untranslated substitution (MarcoFalke) +- #8557 `44691f3` contrib: Rework verifybinaries (MarcoFalke) +- #8621 `e8ed6eb` contrib: python: Don't use shell=True (MarcoFalke) +- #8813 `fb24d7e` bitcoind: Daemonize using daemon(3) (laanwj) +- #9004 `67728a3` Clarify `listenonion` (unsystemizer) +- #8674 `bae81b8` tools for analyzing, updating and adding copyright headers in source files (isle2983) +- #8976 `8c6218a` libconsensus: Add input validation of flags (laanwj) +- #9112 `46027e8` Avoid ugly exception in log on unknown inv type (laanwj) +- #8837 `2108911` Allow bitcoin-tx to parse partial transactions (jnewbery) +- #9204 `74ced54` Clarify CreateTransaction error messages (instagibbs) +- #9265 `31bcc66` bitcoin-cli: Make error message less confusing (laanwj) +- #9303 `72bf1b3` Update comments in ctaes (sipa) +- #9417 `c4b7d4f` Do not evaluate hidden LogPrint arguments (sipa) +- #9506 `593a00c` RFC: Improve style for if indentation (sipa) +- #8883 `d5d4ad8` Add all standard TXO types to bitcoin-tx (jnewbery) +- #9531 `23281a4` Release notes for estimation changes (morcos) +- #9486 `f62bc10` Make peer=%d log prints consistent (TheBlueMatt) +- #9552 `41cb05c` Add IPv6 support to qos.sh (jamesmacwhite) +- #9542 `e9e7993` Docs: Update CONTRIBUTING.md (jnewbery) +- #9649 `53ab12d` Remove unused clang format dev script (MarcoFalke) +- #9625 `77bd8c4` Increase minimum debug.log size to 10MB after shrink (morcos) +- #9070 `7b22e50` Lockedpool fixes (kazcw) +- #8779 `7008e28` contrib: Delete spendfrom (MarcoFalke) +- #9587,#8793,#9496,#8191,#8109,#8655,#8472,#8677,#8981,#9124 Avoid shadowing of variables (paveljanik) +- #9063 `f2a6e82` Use deprecated `MAP_ANON` if `MAP_ANONYMOUS` is not defined (paveljanik) +- #9060 `1107653` Fix bloom filter init to isEmpty = true (robmcl4) +- #8613 `613bda4` LevelDB 1.19 (sipa) +- #9225 `5488514` Fix some benign races (TheBlueMatt) +- #8736 `5fa7b07` base58: Improve DecodeBase58 performance (wjx) +- #9039 `e81df49` Various serialization simplifcations and optimizations (sipa) +- #9010 `a143b88` Split up AppInit2 into multiple phases, daemonize after datadir lock errors (laanwj) +- #9230 `c79e52a` Fix some benign races in timestamp logging (TheBlueMatt) +- #9183,#9260 Mrs Peacock in The Library with The Candlestick (killed main.{h,cpp}) (TheBlueMatt) +- #9236 `7f72568` Fix races for strMiscWarning and `fLargeWork*Found`, make QT runawayException use GetWarnings (gmaxwell) +- #9243 `7aa7004` Clean up mapArgs and mapMultiArgs Usage (TheBlueMatt) +- #9387 `cfe41d7` RAII of libevent stuff using unique ptrs with deleters (kallewoof) +- #9472 `fac0f30` Disentangle progress estimation from checkpoints and update it (sipa) +- #9512 `6012967` Fix various things -fsanitize complains about (sipa) +- #9373,#9580 Various linearization script issues (droark) +- #9674 `dd163f5` Lock debugging: Always enforce strict lock ordering (try or not) (TheBlueMatt) +- #8453,#9334 Update to latest libsecp256k1 (laanwj,sipa) +- #9656 `7c93952` Check verify-commits on pushes to master (TheBlueMatt) +- #9679 `a351162` Access WorkQueue::running only within the cs lock (TheBlueMatt) +- #9777 `8dee822` Handle unusual maxsigcachesize gracefully (jnewbery) +- #8863,#8807 univalue: Pull subtree (MarcoFalke) +- #9798 `e22c067` Fix Issue #9775 (Check returned value of fopen) (kirit93) +- #9856 `69832aa` Terminate immediately when allocation fails (theuni) + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- accraze +- adlawren +- Alex Morcos +- Alexey Vesnin +- Amir Abrams +- Anders Øyvind Urke-Sætre +- Anditto Heristyo +- Andrew Chow +- anduck +- Anthony Towns +- Brian Deery +- BtcDrak +- Chris Moore +- Chris Stewart +- Christian Barcenas +- Christian Decker +- Cory Fields +- crowning- +- CryptAxe +- CryptoVote +- Dagur Valberg Johannsson +- Daniel Cousens +- Daniel Kraft +- Derek Miller +- djpnewton +- Don Patterson +- Doug +- Douglas Roark +- Ethan Heilman +- fsb4000 +- Gaurav Rana +- Geoffrey Tsui +- Greg Walker +- Gregory Maxwell +- Gregory Sanders +- Hampus Sjöberg +- isle2983 +- Ivo van der Sangen +- James White +- Jameson Lopp +- Jeremy Rubin +- Jiaxing Wang +- jnewbery +- John Newbery +- Johnson Lau +- Jon Lund Steffensen +- Jonas Schnelli +- jonnynewbs +- Jorge Timón +- Justin Camarena +- Karl-Johan Alm +- Kaz Wesley +- kirit93 +- Koki Takahashi +- Lauda +- leijurv +- lizhi +- Luke Dashjr +- maiiz +- MarcoFalke +- Marijn Stollenga +- Marty Jones +- Masahiko Hyuga +- Matt Corallo +- Matthew King +- matthias +- Micha +- Michael Ford +- Michael Rotarius +- Mitchell Cash +- mrbandrews +- mruddy +- Nicolas DORIER +- nomnombtc +- Patrick Strateman +- Pavel JanÃk +- Pedro Branco +- Peter Todd +- Pieter Wuille +- poole\_party +- practicalswift +- R E Broadley +- randy-waterhouse +- Richard Kiss +- Robert McLaughlin +- rodasmith +- Russell Yanofsky +- S. Matthew English +- Sev +- Spencer Lievens +- Stanislas Marion +- Steven +- Suhas Daftuar +- Thomas Snider +- UdjinM6 +- unsystemizer +- whythat +- Will Binns +- Wladimir J. van der Laan +- wodry +- Zak Wilcox + +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 399ed25c91..44d5757989 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -23,6 +23,7 @@ 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 [`BLOCK_CHAIN_SIZE`](/src/qt/intro.cpp) to the current size plus some overhead. +* Update `src/chainparams.cpp` chainTxData with statistics about the transaction count and rate. ### First time / New builders @@ -175,7 +176,38 @@ Commit your signature to gitian.sigs: git push # Assuming you can push to the gitian.sigs tree popd -Wait for Windows/OS X detached signatures: +Codesigner only: Create Windows/OS X detached signatures: +- Only one person handles codesigning. Everyone else should skip to the next step. +- Only once the Windows/OS X builds each have 3 matching signatures may they be signed with their respective release keys. + +Codesigner only: Sign the osx binary: + + transfer bitcoin-osx-unsigned.tar.gz to osx for signing + tar xf bitcoin-osx-unsigned.tar.gz + ./detached-sig-create.sh -s "Key ID" + Enter the keychain password and authorize the signature + Move signature-osx.tar.gz back to the gitian host + +Codesigner only: Sign the windows binaries: + + tar xf bitcoin-win-unsigned.tar.gz + ./detached-sig-create.sh -key /path/to/codesign.key + Enter the passphrase for the key when prompted + signature-win.tar.gz will be created + +Codesigner only: Commit the detached codesign payloads: + + cd ~/bitcoin-detached-sigs + checkout the appropriate branch for this release series + rm -rf * + tar xf signature-osx.tar.gz + tar xf signature-win.tar.gz + git add -a + git commit -m "point to ${VERSION}" + git tag -s v${VERSION} HEAD + git push the current branch and new tag + +Non-codesigners: wait for Windows/OS X detached signatures: - Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys. - Detached signatures will then be committed to the [bitcoin-detached-sigs](https://github.com/bitcoin-core/bitcoin-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries. diff --git a/qa/README.md b/qa/README.md deleted file mode 100644 index f4dce7af5c..0000000000 --- a/qa/README.md +++ /dev/null @@ -1,87 +0,0 @@ -The [pull-tester](/qa/pull-tester/) folder contains a script to call -multiple tests from the [rpc-tests](/qa/rpc-tests/) folder. - -Every pull request to the bitcoin repository is built and run through -the regression test suite. You can also run all or only individual -tests locally. - -Test dependencies -================= -Before running the tests, the following must be installed. - -Unix ----- -The python3-zmq library is required. On Ubuntu or Debian it can be installed via: -``` -sudo apt-get install python3-zmq -``` - -OS X ------- -``` -pip3 install pyzmq -``` - -Running tests -============= - -You can run any single test by calling - - qa/pull-tester/rpc-tests.py <testname> - -Or you can run any combination of tests by calling - - qa/pull-tester/rpc-tests.py <testname1> <testname2> <testname3> ... - -Run the regression test suite with - - qa/pull-tester/rpc-tests.py - -Run all possible tests with - - qa/pull-tester/rpc-tests.py --extended - -By default, tests will be run in parallel. To specify how many jobs to run, -append `--jobs=n` (default n=4). - -If you want to create a basic coverage report for the RPC test suite, append `--coverage`. - -Possible options, which apply to each individual test run: - -``` - -h, --help show this help message and exit - --nocleanup Leave bitcoinds and test.* datadir on exit or error - --noshutdown Don't stop bitcoinds after the test execution - --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli - (default: ../../src) - --tmpdir=TMPDIR Root directory for datadirs - --tracerpc Print out all RPC calls as they are made - --coveragedir=COVERAGEDIR - Write tested RPC commands into this directory -``` - -If you set the environment variable `PYTHON_DEBUG=1` you will get some debug -output (example: `PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet`). - -A 200-block -regtest blockchain and wallets for four nodes -is created the first time a regression test is run and -is stored in the cache/ directory. Each node has 25 mature -blocks (25*50=1250 BTC) in its wallet. - -After the first run, the cache/ blockchain and wallets are -copied into a temporary directory and used as the initial -test state. - -If you get into a bad state, you should be able -to recover with: - -```bash -rm -rf cache -killall bitcoind -``` - -Writing tests -============= -You are encouraged to write tests for new or existing features. -Further information about the test framework and individual RPC -tests is found in [qa/rpc-tests](/qa/rpc-tests). diff --git a/src/Makefile.am b/src/Makefile.am index e8d22313dc..8a32156884 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -167,8 +167,8 @@ BITCOIN_CORE_H = \ obj/build.h: FORCE @$(MKDIR_P) $(builddir)/obj - @$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \ - $(abs_top_srcdir) + @$(top_srcdir)/share/genbuild.sh "$(abs_top_builddir)/src/obj/build.h" \ + "$(abs_top_srcdir)" libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h # server: shared between bitcoind and bitcoin-qt diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 8c699c2f8c..3bcecab596 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -25,7 +25,8 @@ bench_bench_bitcoin_SOURCES = \ bench/base58.cpp \ bench/lockedpool.cpp \ bench/perf.cpp \ - bench/perf.h + bench/perf.h \ + bench/prevector_destructor.cpp nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_TEST_FILES) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 039f8ac547..948e13a9e1 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -11,7 +11,9 @@ TEST_QT_MOC_CPP = \ qt/test/moc_uritests.cpp if ENABLE_WALLET -TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp +TEST_QT_MOC_CPP += \ + qt/test/moc_paymentservertests.cpp \ + qt/test/moc_wallettests.cpp endif TEST_QT_H = \ @@ -19,7 +21,16 @@ TEST_QT_H = \ qt/test/rpcnestedtests.h \ qt/test/uritests.h \ qt/test/paymentrequestdata.h \ - qt/test/paymentservertests.h + qt/test/paymentservertests.h \ + qt/test/wallettests.h + +TEST_BITCOIN_CPP = \ + test/test_bitcoin.cpp \ + test/testutil.cpp + +TEST_BITCOIN_H = \ + test/test_bitcoin.h \ + test/testutil.h qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) @@ -29,10 +40,13 @@ qt_test_test_bitcoin_qt_SOURCES = \ qt/test/rpcnestedtests.cpp \ qt/test/test_main.cpp \ qt/test/uritests.cpp \ - $(TEST_QT_H) + $(TEST_QT_H) \ + $(TEST_BITCOIN_CPP) \ + $(TEST_BITCOIN_H) if ENABLE_WALLET qt_test_test_bitcoin_qt_SOURCES += \ - qt/test/paymentservertests.cpp + qt/test/paymentservertests.cpp \ + qt/test/wallettests.cpp endif nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 55a587cf87..fe0ed59fe2 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -8,60 +8,6 @@ noinst_PROGRAMS += test/test_bitcoin_fuzzy TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) - -EXTRA_DIST += \ - test/bctest.py \ - test/bitcoin-util-test.py \ - test/data/bitcoin-util-test.json \ - test/data/blanktxv1.hex \ - test/data/blanktxv1.json \ - test/data/blanktxv2.hex \ - test/data/blanktxv2.json \ - test/data/tt-delin1-out.hex \ - test/data/tt-delin1-out.json \ - test/data/tt-delout1-out.hex \ - test/data/tt-delout1-out.json \ - test/data/tt-locktime317000-out.hex \ - test/data/tt-locktime317000-out.json \ - test/data/tx394b54bb.hex \ - test/data/txcreate1.hex \ - test/data/txcreate1.json \ - test/data/txcreate2.hex \ - test/data/txcreate2.json \ - test/data/txcreatedata1.hex \ - test/data/txcreatedata1.json \ - test/data/txcreatedata2.hex \ - test/data/txcreatedata2.json \ - test/data/txcreatedata_seq0.hex \ - test/data/txcreatedata_seq0.json \ - test/data/txcreatedata_seq1.hex \ - test/data/txcreatedata_seq1.json \ - test/data/txcreatemultisig1.hex \ - test/data/txcreatemultisig1.json \ - test/data/txcreatemultisig2.hex \ - test/data/txcreatemultisig2.json \ - test/data/txcreatemultisig3.hex \ - test/data/txcreatemultisig3.json \ - test/data/txcreatemultisig4.hex \ - test/data/txcreatemultisig4.json \ - test/data/txcreateoutpubkey1.hex \ - test/data/txcreateoutpubkey1.json \ - test/data/txcreateoutpubkey2.hex \ - test/data/txcreateoutpubkey2.json \ - test/data/txcreateoutpubkey3.hex \ - test/data/txcreateoutpubkey3.json \ - test/data/txcreatescript1.hex \ - test/data/txcreatescript1.json \ - test/data/txcreatescript2.hex \ - test/data/txcreatescript2.json \ - test/data/txcreatescript3.hex \ - test/data/txcreatescript3.json \ - test/data/txcreatescript4.hex \ - test/data/txcreatescript4.json \ - test/data/txcreatesignv1.hex \ - test/data/txcreatesignv1.json \ - test/data/txcreatesignv2.hex - JSON_TEST_FILES = \ test/data/script_tests.json \ test/data/base58_keys_valid.json \ @@ -89,6 +35,7 @@ BITCOIN_TESTS =\ test/blockencodings_tests.cpp \ test/bloom_tests.cpp \ test/bswap_tests.cpp \ + test/checkqueue_tests.cpp \ test/coins_tests.cpp \ test/compress_tests.cpp \ test/crypto_tests.cpp \ @@ -126,6 +73,7 @@ BITCOIN_TESTS =\ test/streams_tests.cpp \ test/test_bitcoin.cpp \ test/test_bitcoin.h \ + test/test_bitcoin_main.cpp \ test/test_random.h \ test/testutil.cpp \ test/testutil.h \ @@ -189,9 +137,6 @@ CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno $(GENERATED_TEST_FILES) CLEANFILES += $(CLEAN_BITCOIN_TEST) -# This file is problematic for out-of-tree builds if it exists. -DISTCLEANFILES += test/buildenv.pyc - bitcoin_test: $(TEST_BINARY) bitcoin_test_check: $(TEST_BINARY) FORCE @@ -201,8 +146,8 @@ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: - @echo "Running test/bitcoin-util-test.py..." - $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(PYTHON) $(srcdir)/test/bitcoin-util-test.py + @echo "Running test/util/bitcoin-util-test.py..." + $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check diff --git a/src/base58.cpp b/src/base58.cpp index e2f475bb7f..36b3523692 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -134,7 +134,7 @@ bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) vchRet.clear(); return false; } - // re-calculate the checksum, insure it matches the included 4-byte checksum + // re-calculate the checksum, ensure it matches the included 4-byte checksum uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4); if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) { vchRet.clear(); diff --git a/src/bench/bench.h b/src/bench/bench.h index 0e7605c726..f12a41126c 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -14,7 +14,7 @@ // Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark // framework (see https://github.com/google/benchmark) -// Wny not use the Google Benchmark framework? Because adding Yet Another Dependency +// Why not use the Google Benchmark framework? Because adding Yet Another Dependency // (that uses cmake as its build system and has lots of features we don't need) isn't // worth it. diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index 29fbd34631..06882f1514 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -20,7 +20,7 @@ static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<CO CWalletTx* wtx = new CWalletTx(&wallet, MakeTransactionRef(std::move(tx))); int nAge = 6 * 24; - COutput output(wtx, nInput, nAge, true, true); + COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */); vCoins.push_back(output); } diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp new file mode 100644 index 0000000000..55af3de4fe --- /dev/null +++ b/src/bench/prevector_destructor.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2015-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. + +#include "bench.h" +#include "prevector.h" + +static void PrevectorDestructor(benchmark::State& state) +{ + while (state.KeepRunning()) { + for (auto x = 0; x < 1000; ++x) { + prevector<28, unsigned char> t0; + prevector<28, unsigned char> t1; + t0.resize(28); + t1.resize(29); + } + } +} + +static void PrevectorClear(benchmark::State& state) +{ + + while (state.KeepRunning()) { + for (auto x = 0; x < 1000; ++x) { + prevector<28, unsigned char> t0; + prevector<28, unsigned char> t1; + t0.resize(28); + t0.clear(); + t1.resize(29); + t0.clear(); + } + } +} + +BENCHMARK(PrevectorDestructor); +BENCHMARK(PrevectorClear); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 3c3646523a..61e0eb74e6 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -483,22 +483,6 @@ static bool findSighashFlags(int& flags, const std::string& flagStr) return false; } -uint256 ParseHashUO(std::map<std::string,UniValue>& o, std::string strKey) -{ - if (!o.count(strKey)) - return uint256(); - return ParseHashUV(o[strKey], strKey); -} - -std::vector<unsigned char> ParseHexUO(std::map<std::string,UniValue>& o, std::string strKey) -{ - if (!o.count(strKey)) { - std::vector<unsigned char> emptyVec; - return emptyVec; - } - return ParseHexUV(o[strKey], strKey); -} - static CAmount AmountFromValue(const UniValue& value) { if (!value.isNum() && !value.isStr()) diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index 4a311cbba2..90120b82eb 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -147,7 +147,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c // request it. // This should be rare enough that the extra bandwidth doesn't matter, // but eating a round-trip due to FillBlock failure would be annoying - // Note that we dont want duplication between extra_txn and mempool to + // Note that we don't want duplication between extra_txn and mempool to // trigger this case, so we compare witness hashes first if (txn_available[idit->second] && txn_available[idit->second]->GetWitnessHash() != extra_txn[i].second->GetWitnessHash()) { diff --git a/src/bloom.cpp b/src/bloom.cpp index 8d47cb76e8..ac3e565721 100644 --- a/src/bloom.cpp +++ b/src/bloom.cpp @@ -254,8 +254,8 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey) if (nGeneration == 4) { nGeneration = 1; } - uint64_t nGenerationMask1 = -(uint64_t)(nGeneration & 1); - uint64_t nGenerationMask2 = -(uint64_t)(nGeneration >> 1); + uint64_t nGenerationMask1 = 0 - (uint64_t)(nGeneration & 1); + uint64_t nGenerationMask2 = 0 - (uint64_t)(nGeneration >> 1); /* Wipe old entries that used this generation number. */ for (uint32_t p = 0; p < data.size(); p += 2) { uint64_t p1 = data[p], p2 = data[p + 1]; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8c38558829..1dc29826af 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -135,7 +135,6 @@ public: vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); - fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; fRequireStandard = true; fMineBlocksOnDemand = false; @@ -235,7 +234,6 @@ public: vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); - fMiningRequiresPeers = true; fDefaultConsistencyChecks = false; fRequireStandard = false; fMineBlocksOnDemand = false; @@ -307,7 +305,6 @@ public: vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //!< Regtest mode doesn't have any DNS seeds. - fMiningRequiresPeers = false; fDefaultConsistencyChecks = true; fRequireStandard = false; fMineBlocksOnDemand = true; diff --git a/src/chainparams.h b/src/chainparams.h index db524e8f8e..4fe88c691c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -61,8 +61,6 @@ public: int GetDefaultPort() const { return nDefaultPort; } const CBlock& GenesisBlock() const { return genesis; } - /** Make miner wait to have peers to avoid wasting work */ - bool MiningRequiresPeers() const { return fMiningRequiresPeers; } /** Default value for -checkmempool and -checkblockindex argument */ bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ @@ -89,7 +87,6 @@ protected: std::string strNetworkID; CBlock genesis; std::vector<SeedSpec6> vFixedSeeds; - bool fMiningRequiresPeers; bool fDefaultConsistencyChecks; bool fRequireStandard; bool fMineBlocksOnDemand; diff --git a/src/checkqueue.h b/src/checkqueue.h index 32e25d5c8c..ea12df66dd 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -127,6 +127,9 @@ private: } public: + //! Mutex to ensure only one concurrent CCheckQueueControl + boost::mutex ControlMutex; + //! Create a new check queue CCheckQueue(unsigned int nBatchSizeIn) : nIdle(0), nTotal(0), fAllOk(true), nTodo(0), fQuit(false), nBatchSize(nBatchSizeIn) {} @@ -161,12 +164,6 @@ public: { } - bool IsIdle() - { - boost::unique_lock<boost::mutex> lock(mutex); - return (nTotal == nIdle && nTodo == 0 && fAllOk == true); - } - }; /** @@ -177,16 +174,18 @@ template <typename T> class CCheckQueueControl { private: - CCheckQueue<T>* pqueue; + CCheckQueue<T> * const pqueue; bool fDone; public: - CCheckQueueControl(CCheckQueue<T>* pqueueIn) : pqueue(pqueueIn), fDone(false) + CCheckQueueControl() = delete; + CCheckQueueControl(const CCheckQueueControl&) = delete; + CCheckQueueControl& operator=(const CCheckQueueControl&) = delete; + explicit CCheckQueueControl(CCheckQueue<T> * const pqueueIn) : pqueue(pqueueIn), fDone(false) { // passed queue is supposed to be unused, or NULL if (pqueue != NULL) { - bool isIdle = pqueue->IsIdle(); - assert(isIdle); + ENTER_CRITICAL_SECTION(pqueue->ControlMutex); } } @@ -209,6 +208,9 @@ public: { if (!fDone) Wait(); + if (pqueue != NULL) { + LEAVE_CRITICAL_SECTION(pqueue->ControlMutex); + } } }; diff --git a/src/coins.h b/src/coins.h index d921f5c2a5..8ee49b33ae 100644 --- a/src/coins.h +++ b/src/coins.h @@ -290,7 +290,6 @@ public: virtual bool GetKey(uint256 &key) const = 0; virtual bool GetValue(CCoins &coins) const = 0; - /* Don't care about GetKeySize here */ virtual unsigned int GetValueSize() const = 0; virtual bool Valid() const = 0; diff --git a/src/compat.h b/src/compat.h index 28aa77eea2..e76ab94c82 100644 --- a/src/compat.h +++ b/src/compat.h @@ -47,10 +47,8 @@ #include <unistd.h> #endif -#ifdef WIN32 -#define MSG_DONTWAIT 0 -#else -typedef u_int SOCKET; +#ifndef WIN32 +typedef unsigned int SOCKET; #include "errno.h" #define WSAGetLastError() errno #define WSAEINVAL EINVAL @@ -74,11 +72,6 @@ typedef u_int SOCKET; #define MAX_PATH 1024 #endif -// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0 -#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) -#define MSG_NOSIGNAL 0 -#endif - #if HAVE_DECL_STRNLEN == 0 size_t strnlen( const char *start, size_t max_len); #endif // HAVE_DECL_STRNLEN diff --git a/src/core_write.cpp b/src/core_write.cpp index b0993a131f..a3ca87c8b5 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -114,9 +114,9 @@ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDeco return str; } -std::string EncodeHexTx(const CTransaction& tx, const int serialFlags) +std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags) { - CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serialFlags); + CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serializeFlags); ssTx << tx; return HexStr(ssTx.begin(), ssTx.end()); } diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 94ebedeb72..cd441add4b 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -14,6 +14,64 @@ #include <leveldb/filter_policy.h> #include <memenv.h> #include <stdint.h> +#include <algorithm> + +class CBitcoinLevelDBLogger : public leveldb::Logger { +public: + // This code is adapted from posix_logger.h, which is why it is using vsprintf. + // Please do not do this in normal code + virtual void Logv(const char * format, va_list ap) override { + if (!LogAcceptCategory("leveldb")) + return; + char buffer[500]; + for (int iter = 0; iter < 2; iter++) { + char* base; + int bufsize; + if (iter == 0) { + bufsize = sizeof(buffer); + base = buffer; + } + else { + bufsize = 30000; + base = new char[bufsize]; + } + char* p = base; + char* limit = base + bufsize; + + // Print the message + if (p < limit) { + va_list backup_ap; + va_copy(backup_ap, ap); + // Do not use vsnprintf elsewhere in bitcoin source code, see above. + p += vsnprintf(p, limit - p, format, backup_ap); + va_end(backup_ap); + } + + // Truncate to available space if necessary + if (p >= limit) { + if (iter == 0) { + continue; // Try again with larger buffer + } + else { + p = limit - 1; + } + } + + // Add newline if necessary + if (p == base || p[-1] != '\n') { + *p++ = '\n'; + } + + assert(p <= limit); + base[std::min(bufsize - 1, (int)(p - base))] = '\0'; + LogPrintStr(base); + if (base != buffer) { + delete[] base; + } + break; + } + } +}; static leveldb::Options GetOptions(size_t nCacheSize) { @@ -23,6 +81,7 @@ static leveldb::Options GetOptions(size_t nCacheSize) options.filter_policy = leveldb::NewBloomFilterPolicy(10); options.compression = leveldb::kNoCompression; options.max_open_files = 64; + options.info_log = new CBitcoinLevelDBLogger(); if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error // on corruption in later versions. @@ -82,6 +141,8 @@ CDBWrapper::~CDBWrapper() pdb = NULL; delete options.filter_policy; options.filter_policy = NULL; + delete options.info_log; + options.info_log = NULL; delete options.block_cache; options.block_cache = NULL; delete penv; diff --git a/src/dbwrapper.h b/src/dbwrapper.h index dd59cc00ff..414df76a7c 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -132,10 +132,6 @@ public: return true; } - unsigned int GetKeySize() { - return piter->key().size(); - } - template<typename V> bool GetValue(V& value) { leveldb::Slice slValue = piter->value(); try { diff --git a/src/httpserver.cpp b/src/httpserver.cpp index e1763c6ad2..799de1c2cb 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -146,13 +146,6 @@ public: while (numThreads > 0) cond.wait(lock); } - - /** Return current depth of queue */ - size_t Depth() - { - std::unique_lock<std::mutex> lock(cs); - return queue.size(); - } }; struct HTTPPathHandler @@ -482,6 +475,7 @@ void StopHTTPServer() LogPrint("http", "Waiting for HTTP worker threads to exit\n"); workQueue->WaitExit(); delete workQueue; + workQueue = nullptr; } if (eventBase) { LogPrint("http", "Waiting for HTTP event thread to exit\n"); diff --git a/src/init.cpp b/src/init.cpp index 93131b4f94..a76c04d003 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -265,18 +265,31 @@ void Shutdown() } /** - * Signal handlers are very limited in what they are allowed to do, so: + * Signal handlers are very limited in what they are allowed to do. + * The execution context the handler is invoked in is not guaranteed, + * so we restrict handler operations to just touching variables: */ -void HandleSIGTERM(int) +static void HandleSIGTERM(int) { fRequestShutdown = true; } -void HandleSIGHUP(int) +static void HandleSIGHUP(int) { fReopenDebugLog = true; } +#ifndef WIN32 +static void registerSignalHandler(int signal, void(*handler)(int)) +{ + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(signal, &sa, NULL); +} +#endif + bool static Bind(CConnman& connman, const CService &addr, unsigned int flags) { if (!(flags & BF_EXPLICIT) && IsLimited(addr)) return false; @@ -360,13 +373,13 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-banscore=<n>", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), DEFAULT_BANSCORE_THRESHOLD)); strUsage += HelpMessageOpt("-bantime=<n>", strprintf(_("Number of seconds to keep misbehaving peers from reconnecting (default: %u)"), DEFAULT_MISBEHAVING_BANTIME)); strUsage += HelpMessageOpt("-bind=<addr>", _("Bind to given address and always listen on it. Use [host]:port notation for IPv6")); - strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -noconnect or -connect=0 alone to disable automatic connections")); + strUsage += HelpMessageOpt("-connect=<ip>", _("Connect only to the specified node(s); -connect=0 disables automatic connections")); strUsage += HelpMessageOpt("-discover", _("Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)")); strUsage += HelpMessageOpt("-dns", _("Allow DNS lookups for -addnode, -seednode and -connect") + " " + strprintf(_("(default: %u)"), DEFAULT_NAME_LOOKUP)); - strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect/-noconnect)")); + strUsage += HelpMessageOpt("-dnsseed", _("Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect used)")); strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address")); strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), DEFAULT_FORCEDNSSEED)); - strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)")); + strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)")); strUsage += HelpMessageOpt("-listenonion", strprintf(_("Automatically create Tor hidden service (default: %d)"), DEFAULT_LISTEN_ONION)); strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS)); strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), DEFAULT_MAXRECEIVEBUFFER)); @@ -379,7 +392,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-port=<port>", strprintf(_("Listen for connections on <port> (default: %u or testnet: %u)"), Params(CBaseChainParams::MAIN).GetDefaultPort(), Params(CBaseChainParams::TESTNET).GetDefaultPort())); strUsage += HelpMessageOpt("-proxy=<ip:port>", _("Connect through SOCKS5 proxy")); strUsage += HelpMessageOpt("-proxyrandomize", strprintf(_("Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)"), DEFAULT_PROXYRANDOMIZE)); - strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); strUsage += HelpMessageOpt("-seednode=<ip>", _("Connect to a node to retrieve peer addresses, and disconnect")); strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT)); strUsage += HelpMessageOpt("-torcontrol=<ip>:<port>", strprintf(_("Tor control port to use if onion listening enabled (default: %s)"), DEFAULT_TOR_CONTROL)); @@ -394,8 +406,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6")); strUsage += HelpMessageOpt("-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")); - strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); - strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET @@ -430,7 +440,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT)); strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)"); } - std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below + std::string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, leveldb, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " + @@ -447,8 +457,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } - strUsage += HelpMessageOpt("-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))); strUsage += HelpMessageOpt("-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))); strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file")); @@ -470,6 +478,10 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY)); strUsage += HelpMessageOpt("-mempoolreplacement", strprintf(_("Enable transaction replacement in the memory pool (default: %u)"), DEFAULT_ENABLE_REPLACEMENT)); + strUsage += HelpMessageOpt("-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))); + strUsage += HelpMessageOpt("-whitelistrelay", strprintf(_("Accept relayed transactions received from whitelisted peers even when not relaying transactions (default: %d)"), DEFAULT_WHITELISTRELAY)); + strUsage += HelpMessageOpt("-whitelistforcerelay", strprintf(_("Force relay of transactions from whitelisted peers even if they violate local relay policy (default: %d)"), DEFAULT_WHITELISTFORCERELAY)); strUsage += HelpMessageGroup(_("Block creation options:")); strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); @@ -488,6 +500,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpcauth=<userpw>", _("Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times")); strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), BaseParams(CBaseChainParams::MAIN).RPCPort(), BaseParams(CBaseChainParams::TESTNET).RPCPort())); strUsage += HelpMessageOpt("-rpcallowip=<ip>", _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times")); + strUsage += HelpMessageOpt("-rpcserialversion", strprintf(_("Sets the serialization of raw transaction or block hex returned in non-verbose mode, non-segwit(0) or segwit(1) (default: %d)"), DEFAULT_RPC_SERIALIZE_VERSION)); strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS)); if (showDebug) { strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE)); @@ -848,19 +861,11 @@ bool AppInitBasicSetup() } // Clean shutdown on SIGTERM - struct sigaction sa; - sa.sa_handler = HandleSIGTERM; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); + registerSignalHandler(SIGTERM, HandleSIGTERM); + registerSignalHandler(SIGINT, HandleSIGTERM); // Reopen debug.log on SIGHUP - struct sigaction sa_hup; - sa_hup.sa_handler = HandleSIGHUP; - sigemptyset(&sa_hup.sa_mask); - sa_hup.sa_flags = 0; - sigaction(SIGHUP, &sa_hup, NULL); + registerSignalHandler(SIGHUP, HandleSIGHUP); // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly signal(SIGPIPE, SIG_IGN); @@ -45,7 +45,7 @@ private: //! The actual byte data std::vector<unsigned char, secure_allocator<unsigned char> > keydata; - //! Check whether the 32-byte array pointed to be vch is valid keydata. + //! Check whether the 32-byte array pointed to by vch is valid keydata. bool static Check(const unsigned char* vch); public: diff --git a/src/miner.cpp b/src/miner.cpp index 2249984381..e155df015a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -26,8 +26,6 @@ #include "validationinterface.h" #include <algorithm> -#include <boost/thread.hpp> -#include <boost/tuple/tuple.hpp> #include <queue> #include <utility> @@ -46,17 +44,6 @@ uint64_t nLastBlockTx = 0; uint64_t nLastBlockSize = 0; uint64_t nLastBlockWeight = 0; -class ScoreCompare -{ -public: - ScoreCompare() {} - - bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b) - { - return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than - } -}; - int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { int64_t nOldTime = pblock->nTime; @@ -137,7 +124,7 @@ void BlockAssembler::resetBlock() nFees = 0; } -std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) +std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx) { int64_t nTimeStart = GetTimeMicros(); @@ -177,7 +164,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc // -promiscuousmempoolflags is used. // TODO: replace this with a call to main to assess validity of a mempool // transaction (which in most cases can be a no-op). - fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()); + fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx; int nPackagesSelected = 0; int nDescendantsUpdated = 0; diff --git a/src/miner.h b/src/miner.h index cd225cabc1..1f3c9d652f 100644 --- a/src/miner.h +++ b/src/miner.h @@ -170,7 +170,7 @@ public: BlockAssembler(const CChainParams& params, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ - std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); + std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx=true); private: // utility functions diff --git a/src/net.cpp b/src/net.cpp index 6ff63d4730..4c5b04b785 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -44,10 +44,15 @@ // We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization. #define FEELER_SLEEP_WINDOW 1 -#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) +#if !defined(HAVE_MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif +// MSG_DONTWAIT is not available on some platforms, if it doesn't exist define it as 0 +#if !defined(HAVE_MSG_DONTWAIT) +#define MSG_DONTWAIT 0 +#endif + // Fix for ancient MinGW versions, that don't have defined these in ws2tcpip.h. // Todo: Can be removed when our pull-tester is upgraded to a modern MinGW version. #ifdef WIN32 @@ -2319,9 +2324,17 @@ void CConnman::Interrupt() interruptNet(); InterruptSocks5(true); - if (semOutbound) - for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) + if (semOutbound) { + for (int i=0; i<(nMaxOutbound + nMaxFeeler); i++) { semOutbound->post(); + } + } + + if (semAddnode) { + for (int i=0; i<nMaxAddnode; i++) { + semAddnode->post(); + } + } } void CConnman::Stop() @@ -2337,10 +2350,6 @@ void CConnman::Stop() if (threadSocketHandler.joinable()) threadSocketHandler.join(); - if (semAddnode) - for (int i=0; i<nMaxAddnode; i++) - semOutbound->post(); - if (fAddressesInitialized) { DumpData(); @@ -2402,11 +2411,6 @@ void CConnman::MarkAddressGood(const CAddress& addr) addrman.Good(addr); } -void CConnman::AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty) -{ - addrman.Add(addr, addrFrom, nTimePenalty); -} - void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty) { addrman.Add(vAddr, addrFrom, nTimePenalty); @@ -207,10 +207,8 @@ public: size_t GetAddressCount() const; void SetServices(const CService &addr, ServiceFlags nServices); void MarkAddressGood(const CAddress& addr); - void AddNewAddress(const CAddress& addr, const CAddress& addrFrom, int64_t nTimePenalty = 0); void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0); std::vector<CAddress> GetAddresses(); - void AddressCurrentlyConnected(const CService& addr); // Denial-of-service detection/prevention // The idea is to detect peers that are behaving diff --git a/src/netbase.cpp b/src/netbase.cpp index fc9a6ed0be..0f02e93e46 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -25,7 +25,7 @@ #include <boost/algorithm/string/case_conv.hpp> // for to_lower() #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() -#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL) +#if !defined(HAVE_MSG_NOSIGNAL) #define MSG_NOSIGNAL 0 #endif diff --git a/src/pow.cpp b/src/pow.cpp index e57fd866f8..e06d9662e6 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -12,12 +12,9 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { + assert(pindexLast != NULL); unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); - // Genesis block - if (pindexLast == NULL) - return nProofOfWorkLimit; - // Only change once per difficulty adjustment interval if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0) { diff --git a/src/prevector.h b/src/prevector.h index cba2e30057..177d81383e 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -11,6 +11,7 @@ #include <string.h> #include <iterator> +#include <type_traits> #pragma pack(push, 1) /** Implements a drop-in replacement for std::vector<T> which stores up to N @@ -388,10 +389,14 @@ public: iterator erase(iterator first, iterator last) { iterator p = first; char* endp = (char*)&(*end()); - while (p != last) { - (*p).~T(); - _size--; - ++p; + if (!std::is_trivially_destructible<T>::value) { + while (p != last) { + (*p).~T(); + _size--; + ++p; + } + } else { + _size -= last - p; } memmove(&(*first), &(*last), endp - ((char*)(&(*last)))); return first; @@ -432,7 +437,9 @@ public: } ~prevector() { - clear(); + if (!std::is_trivially_destructible<T>::value) { + clear(); + } if (!is_direct()) { free(_union.indirect); _union.indirect = NULL; diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 8be4a955b3..093e644bdc 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -645,7 +645,7 @@ <item> <widget class="QPushButton" name="btnClearTrafficGraph"> <property name="text"> - <string>&Clear</string> + <string>&Reset</string> </property> <property name="autoDefault"> <bool>false</bool> diff --git a/src/qt/forms/sendcoinsdialog.ui b/src/qt/forms/sendcoinsdialog.ui index ca8ecffafe..cc183908d4 100644 --- a/src/qt/forms/sendcoinsdialog.ui +++ b/src/qt/forms/sendcoinsdialog.ui @@ -760,10 +760,32 @@ </layout> </item> <item> + <widget class="QLabel" name="fallbackFeeWarningLabel"> + <property name="toolTip"> + <string>Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until your have validated the complete chain.</string> + </property> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Warning: Fee estimation is currently not possible.</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> <spacer name="horizontalSpacer_4"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::MinimumExpanding</enum> + </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> @@ -1158,6 +1180,16 @@ </item> </layout> </item> + <item> + <widget class="QCheckBox" name="optInRBF"> + <property name="text"> + <string>Request Replace-By-Fee</string> + </property> + <property name="toolTip"> + <string>Indicates that the sender may wish to replace this transaction with a new one paying higher fees (prior to being confirmed).</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -1168,8 +1200,8 @@ </property> <property name="sizeHint" stdset="0"> <size> - <width>800</width> - <height>1</height> + <width>40</width> + <height>5</height> </size> </property> </spacer> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index fd3dcac424..bb5b2d4347 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -443,7 +443,7 @@ void SubstituteFonts(const QString& language) /* 10.10 or later system */ if (language == "zh_CN" || language == "zh_TW" || language == "zh_HK") // traditional or simplified Chinese QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Heiti SC"); - else if (language == "ja") // Japanesee + else if (language == "ja") // Japanese QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Songti SC"); else QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Lucida Grande"); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 60406c2059..5167232d6a 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -175,6 +175,10 @@ bool RPCConsole::RPCParseCommandLine(std::string &strResult, const std::string & nDepthInsideSensitive = 1; filter_begin_pos = chpos; } + // Make sure stack is not empty before adding something + if (stack.empty()) { + stack.push_back(std::vector<std::string>()); + } stack.back().push_back(strArg); }; @@ -626,9 +630,12 @@ void RPCConsole::setClientModel(ClientModel *model) for (size_t i = 0; i < commandList.size(); ++i) { wordList << commandList[i].c_str(); + wordList << ("help " + commandList[i]).c_str(); } + wordList.sort(); autoCompleter = new QCompleter(wordList, this); + autoCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel); 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 1c0ed663c1..ed7eab03f3 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -23,6 +23,7 @@ #include "txmempool.h" #include "wallet/wallet.h" +#include <QFontMetrics> #include <QMessageBox> #include <QScrollBar> #include <QSettings> @@ -113,6 +114,7 @@ SendCoinsDialog::SendCoinsDialog(const PlatformStyle *_platformStyle, QWidget *p ui->groupCustomFee->button((int)std::max(0, std::min(1, settings.value("nCustomFeeRadio").toInt())))->setChecked(true); ui->customFee->setValue(settings.value("nTransactionFee").toLongLong()); ui->checkBoxMinimumFee->setChecked(settings.value("fPayOnlyMinFee").toBool()); + ui->optInRBF->setCheckState(model->getDefaultWalletRbf() ? Qt::Checked : Qt::Unchecked); minimizeFeeSection(settings.value("fFeeSectionMinimized").toBool()); } @@ -246,6 +248,8 @@ void SendCoinsDialog::on_sendButton_clicked() else ctrl.nConfirmTarget = 0; + ctrl.signalRbf = ui->optInRBF->isChecked(); + prepareStatus = model->prepareTransaction(currentTransaction, &ctrl); // process prepareStatus and on error generate message shown to user @@ -325,6 +329,13 @@ void SendCoinsDialog::on_sendButton_clicked() questionString.append(QString("<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>") .arg(alternativeUnits.join(" " + tr("or") + "<br />"))); + if (ui->optInRBF->isChecked()) + { + questionString.append("<hr /><span>"); + questionString.append(tr("This transaction signals replaceability (optin-RBF).")); + questionString.append("</span>"); + } + SendConfirmationDialog confirmationDialog(tr("Confirm send coins"), questionString.arg(formatted.join("<br />")), SEND_CONFIRM_DELAY, this); confirmationDialog.exec(); @@ -656,6 +667,11 @@ void SendCoinsDialog::updateSmartFeeLabel() std::max(CWallet::fallbackFee.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->show(); // (Smart fee not initialized yet. This usually takes a few blocks...) ui->labelFeeEstimation->setText(""); + ui->fallbackFeeWarningLabel->setVisible(true); + int lightness = ui->fallbackFeeWarningLabel->palette().color(QPalette::WindowText).lightness(); + QColor warning_colour(255 - (lightness / 5), 176 - (lightness / 3), 48 - (lightness / 14)); + ui->fallbackFeeWarningLabel->setStyleSheet("QLabel { color: " + warning_colour.name() + "; }"); + ui->fallbackFeeWarningLabel->setIndent(QFontMetrics(ui->fallbackFeeWarningLabel->font()).width("x")); } else { @@ -663,6 +679,7 @@ void SendCoinsDialog::updateSmartFeeLabel() std::max(feeRate.GetFeePerK(), CWallet::GetRequiredFee(1000))) + "/kB"); ui->labelSmartFee2->hide(); ui->labelFeeEstimation->setText(tr("Estimated to begin confirmation within %n block(s).", "", estimateFoundAtBlocks)); + ui->fallbackFeeWarningLabel->setVisible(false); } updateFeeMinimizedLabel(); diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp index 84ccfea730..08a76c7d49 100644 --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -142,7 +142,7 @@ void PaymentServerTests::paymentServerTests() byteArray = QByteArray((const char*)&data[0], data.size()); r.paymentRequest.parse(byteArray); // Ensure the request is initialized, because network "main" is default, even for - // uninizialized payment requests and that will fail our test here. + // uninitialized payment requests and that will fail our test here. QVERIFY(r.paymentRequest.IsInitialized()); QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false); diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index bd496f149c..a7b82117d8 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -148,9 +148,13 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , #endif + UnloadBlockIndex(); delete pcoinsTip; + pcoinsTip = nullptr; delete pcoinsdbview; + pcoinsdbview = nullptr; delete pblocktree; + pblocktree = nullptr; boost::filesystem::remove_all(boost::filesystem::path(path)); } diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index d44d711315..d8bcfedb7c 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -7,7 +7,6 @@ #endif #include "chainparams.h" -#include "key.h" #include "rpcnestedtests.h" #include "util.h" #include "uritests.h" @@ -15,20 +14,31 @@ #ifdef ENABLE_WALLET #include "paymentservertests.h" +#include "wallettests.h" #endif -#include <QCoreApplication> +#include <QApplication> #include <QObject> #include <QTest> #include <openssl/ssl.h> -#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000 +#if defined(QT_STATICPLUGIN) #include <QtPlugin> +#if QT_VERSION < 0x050000 Q_IMPORT_PLUGIN(qcncodecs) Q_IMPORT_PLUGIN(qjpcodecs) Q_IMPORT_PLUGIN(qtwcodecs) Q_IMPORT_PLUGIN(qkrcodecs) +#else +#if defined(QT_QPA_PLATFORM_XCB) +Q_IMPORT_PLUGIN(QXcbIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_WINDOWS) +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +#elif defined(QT_QPA_PLATFORM_COCOA) +Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); +#endif +#endif #endif extern void noui_connect(); @@ -36,7 +46,6 @@ extern void noui_connect(); // This is all you need to run all the tests int main(int argc, char *argv[]) { - ECC_Start(); SetupEnvironment(); SetupNetworking(); SelectParams(CBaseChainParams::MAIN); @@ -45,27 +54,36 @@ int main(int argc, char *argv[]) bool fInvalid = false; // Don't remove this, it's needed to access - // QCoreApplication:: in the tests - QCoreApplication app(argc, argv); + // QApplication:: and QCoreApplication:: in the tests + QApplication app(argc, argv); app.setApplicationName("Bitcoin-Qt-test"); SSL_library_init(); URITests test1; - if (QTest::qExec(&test1) != 0) + if (QTest::qExec(&test1) != 0) { fInvalid = true; + } #ifdef ENABLE_WALLET PaymentServerTests test2; - if (QTest::qExec(&test2) != 0) + if (QTest::qExec(&test2) != 0) { fInvalid = true; + } #endif RPCNestedTests test3; - if (QTest::qExec(&test3) != 0) + if (QTest::qExec(&test3) != 0) { fInvalid = true; + } CompatTests test4; - if (QTest::qExec(&test4) != 0) + if (QTest::qExec(&test4) != 0) { fInvalid = true; + } +#ifdef ENABLE_WALLET + WalletTests test5; + if (QTest::qExec(&test5) != 0) { + fInvalid = true; + } +#endif - ECC_Stop(); return fInvalid; } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp new file mode 100644 index 0000000000..36d93361dd --- /dev/null +++ b/src/qt/test/wallettests.cpp @@ -0,0 +1,107 @@ +#include "wallettests.h" + +#include "qt/bitcoinamountfield.h" +#include "qt/optionsmodel.h" +#include "qt/platformstyle.h" +#include "qt/qvalidatedlineedit.h" +#include "qt/sendcoinsdialog.h" +#include "qt/sendcoinsentry.h" +#include "qt/transactiontablemodel.h" +#include "qt/walletmodel.h" +#include "test/test_bitcoin.h" +#include "validation.h" +#include "wallet/wallet.h" + +#include <QAbstractButton> +#include <QApplication> +#include <QTimer> +#include <QVBoxLayout> + +namespace +{ +//! Press "Yes" button in modal send confirmation dialog. +void ConfirmSend() +{ + QTimer* timer = new QTimer; + timer->setSingleShot(true); + QObject::connect(timer, &QTimer::timeout, []() { + for (QWidget* widget : QApplication::topLevelWidgets()) { + if (widget->inherits("SendConfirmationDialog")) { + SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget); + QAbstractButton* button = dialog->button(QMessageBox::Yes); + button->setEnabled(true); + button->click(); + } + } + }); + timer->start(0); +} + +//! Send coins to address and return txid. +uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount) +{ + QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries"); + SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget()); + entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString())); + entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount); + uint256 txid; + boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) { + if (status == CT_NEW) txid = hash; + })); + ConfirmSend(); + QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked"); + return txid; +} + +//! Find index of txid in transaction list. +QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid) +{ + QString hash = QString::fromStdString(txid.ToString()); + int rows = model.rowCount({}); + for (int row = 0; row < rows; ++row) { + QModelIndex index = model.index(row, 0, {}); + if (model.data(index, TransactionTableModel::TxHashRole) == hash) { + return index; + } + } + return {}; +} +} + +//! Simple qt wallet tests. +void WalletTests::walletTests() +{ + // Set up wallet and chain with 101 blocks (1 mature block for spending). + TestChain100Setup test; + test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); + bitdb.MakeMock(); + CWallet wallet("wallet_test.dat"); + bool firstRun; + wallet.LoadWallet(firstRun); + { + LOCK(wallet.cs_wallet); + wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive"); + wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); + } + wallet.ScanForWalletTransactions(chainActive.Genesis(), true); + wallet.SetBroadcastTransactions(true); + + // Create widgets for sending coins and listing transactions. + std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other")); + SendCoinsDialog sendCoinsDialog(platformStyle.get()); + OptionsModel optionsModel; + WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel); + sendCoinsDialog.setModel(&walletModel); + + // Send two transactions, and verify they are added to transaction list. + TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel(); + QCOMPARE(transactionTableModel->rowCount({}), 101); + uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN); + uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN); + QCOMPARE(transactionTableModel->rowCount({}), 103); + QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); + QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); + + bitdb.Flush(true); + bitdb.Reset(); +} diff --git a/src/qt/test/wallettests.h b/src/qt/test/wallettests.h new file mode 100644 index 0000000000..342f7916c3 --- /dev/null +++ b/src/qt/test/wallettests.h @@ -0,0 +1,15 @@ +#ifndef BITCOIN_QT_TEST_WALLETTESTS_H +#define BITCOIN_QT_TEST_WALLETTESTS_H + +#include <QObject> +#include <QTest> + +class WalletTests : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void walletTests(); +}; + +#endif // BITCOIN_QT_TEST_WALLETTESTS_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 0a5a7c3e9f..ebcac53c25 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -580,7 +580,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true); + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */); vOutputs.push_back(out); } } @@ -607,7 +607,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) if (!wallet->mapWallet.count(outpoint.hash)) continue; int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; - COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true, true); + COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true /* spendable */, true /* solvable */, true /* safe */); if (outpoint.n < out.tx->tx->vout.size() && wallet->IsMine(out.tx->tx->vout[outpoint.n]) == ISMINE_SPENDABLE) vCoins.push_back(out); } @@ -619,7 +619,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) while (wallet->IsChange(cout.tx->tx->vout[cout.i]) && cout.tx->tx->vin.size() > 0 && wallet->IsMine(cout.tx->tx->vin[0])) { if (!wallet->mapWallet.count(cout.tx->tx->vin[0].prevout.hash)) break; - cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0, true, true); + cout = COutput(&wallet->mapWallet[cout.tx->tx->vin[0].prevout.hash], cout.tx->tx->vin[0].prevout.n, 0 /* depth */, true /* spendable */, true /* solvable */, true /* safe */); } CTxDestination address; @@ -706,3 +706,8 @@ int WalletModel::getDefaultConfirmTarget() const { return nTxConfirmTarget; } + +bool WalletModel::getDefaultWalletRbf() const +{ + return fWalletRbf; +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index cd7585635f..78e45dc369 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -213,6 +213,8 @@ public: int getDefaultConfirmTarget() const; + bool getDefaultWalletRbf() const; + private: CWallet *wallet; bool fHaveWatchOnly; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 24ced1a819..96254a8cb9 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -28,7 +28,6 @@ #include <mutex> #include <condition_variable> -using namespace std; struct CUpdatedBlock { @@ -154,7 +153,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx UniValue getblockcount(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getblockcount\n" "\nReturns the number of blocks in the longest blockchain.\n" "\nResult:\n" @@ -171,7 +170,7 @@ UniValue getblockcount(const JSONRPCRequest& request) UniValue getbestblockhash(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getbestblockhash\n" "\nReturns the hash of the best (tip) block in the longest blockchain.\n" "\nResult:\n" @@ -198,7 +197,7 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex) UniValue waitfornewblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "waitfornewblock (timeout)\n" "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n" @@ -236,7 +235,7 @@ UniValue waitfornewblock(const JSONRPCRequest& request) UniValue waitforblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "waitforblock <blockhash> (timeout)\n" "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n" @@ -278,7 +277,7 @@ UniValue waitforblock(const JSONRPCRequest& request) UniValue waitforblockheight(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "waitforblockheight <height> (timeout)\n" "\nWaits for (at least) block height and returns the height and hash\n" "of the current tip.\n" @@ -320,7 +319,7 @@ UniValue waitforblockheight(const JSONRPCRequest& request) UniValue getdifficulty(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getdifficulty\n" "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n" "\nResult:\n" @@ -368,7 +367,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) info.push_back(Pair("ancestorsize", e.GetSizeWithAncestors())); info.push_back(Pair("ancestorfees", e.GetModFeesWithAncestors())); const CTransaction& tx = e.GetTx(); - set<string> setDepends; + std::set<std::string> setDepends; BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (mempool.exists(txin.prevout.hash)) @@ -376,7 +375,7 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e) } UniValue depends(UniValue::VARR); - BOOST_FOREACH(const string& dep, setDepends) + BOOST_FOREACH(const std::string& dep, setDepends) { depends.push_back(dep); } @@ -401,7 +400,7 @@ UniValue mempoolToJSON(bool fVerbose = false) } else { - vector<uint256> vtxid; + std::vector<uint256> vtxid; mempool.queryHashes(vtxid); UniValue a(UniValue::VARR); @@ -415,7 +414,7 @@ UniValue mempoolToJSON(bool fVerbose = false) UniValue getrawmempool(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getrawmempool ( verbose )\n" "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nArguments:\n" @@ -446,7 +445,7 @@ UniValue getrawmempool(const JSONRPCRequest& request) UniValue getmempoolancestors(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { - throw runtime_error( + throw std::runtime_error( "getmempoolancestors txid (verbose)\n" "\nIf txid is in the mempool, returns all in-mempool ancestors.\n" "\nArguments:\n" @@ -510,7 +509,7 @@ UniValue getmempoolancestors(const JSONRPCRequest& request) UniValue getmempooldescendants(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { - throw runtime_error( + throw std::runtime_error( "getmempooldescendants txid (verbose)\n" "\nIf txid is in the mempool, returns all in-mempool descendants.\n" "\nArguments:\n" @@ -574,7 +573,7 @@ UniValue getmempooldescendants(const JSONRPCRequest& request) UniValue getmempoolentry(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) { - throw runtime_error( + throw std::runtime_error( "getmempoolentry txid\n" "\nReturns mempool data for given transaction\n" "\nArguments:\n" @@ -607,7 +606,7 @@ UniValue getmempoolentry(const JSONRPCRequest& request) UniValue getblockhash(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getblockhash height\n" "\nReturns hash of block in best-block-chain at height provided.\n" "\nArguments:\n" @@ -632,7 +631,7 @@ UniValue getblockhash(const JSONRPCRequest& request) UniValue getblockheader(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getblockheader \"hash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" "If verbose is true, returns an Object with information about blockheader <hash>.\n" @@ -691,7 +690,7 @@ UniValue getblockheader(const JSONRPCRequest& request) UniValue getblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getblock \"blockhash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbose is true, returns an Object with information about block <hash>.\n" @@ -745,10 +744,15 @@ UniValue getblock(const JSONRPCRequest& request) CBlockIndex* pblockindex = mapBlockIndex[hash]; if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); - if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + // Block not found on disk. This could be because we have the block + // header in our index but don't have the block (for example if a + // non-whitelisted node sends us an unrequested long chain of valid + // blocks, we add the headers to our index, but don't accept the + // block). + throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); if (!fVerbose) { @@ -818,7 +822,7 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) UniValue pruneblockchain(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "pruneblockchain\n" "\nArguments:\n" "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n" @@ -830,7 +834,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) + HelpExampleRpc("pruneblockchain", "1000")); if (!fPruneMode) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode."); + throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); LOCK(cs_main); @@ -844,7 +848,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) // Add a 2 hour buffer to include blocks which might have had old timestamps CBlockIndex* pindex = chainActive.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW); if (!pindex) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block with at least the specified timestamp."); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp."); } heightParam = pindex->nHeight; } @@ -852,7 +856,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) unsigned int height = (unsigned int) heightParam; unsigned int chainHeight = (unsigned int) chainActive.Height(); if (chainHeight < Params().PruneAfterHeight()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning."); + throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning."); else if (height > chainHeight) throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { @@ -867,7 +871,7 @@ UniValue pruneblockchain(const JSONRPCRequest& request) UniValue gettxoutsetinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "gettxoutsetinfo\n" "\nReturns statistics about the unspent transaction output set.\n" "Note this call may take some time.\n" @@ -907,7 +911,7 @@ UniValue gettxoutsetinfo(const JSONRPCRequest& request) UniValue gettxout(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "gettxout \"txid\" n ( include_mempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" @@ -989,7 +993,7 @@ UniValue verifychain(const JSONRPCRequest& request) int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL); int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS); if (request.fHelp || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "verifychain ( checklevel nblocks )\n" "\nVerifies blockchain database.\n" "\nArguments:\n" @@ -1075,7 +1079,7 @@ void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name, UniValue getblockchaininfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getblockchaininfo\n" "Returns an object containing various state info regarding blockchain processing.\n" "\nResult:\n" @@ -1168,7 +1172,7 @@ struct CompareBlocksByHeight UniValue getchaintips(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getchaintips\n" "Return information about all known tips in the block tree," " including the main chain as well as orphaned branches.\n" @@ -1201,7 +1205,7 @@ 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. @@ -1240,7 +1244,7 @@ UniValue getchaintips(const JSONRPCRequest& request) const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight; obj.push_back(Pair("branchlen", branchLen)); - string status; + std::string status; if (chainActive.Contains(block)) { // This block is part of the currently active chain. status = "active"; @@ -1284,7 +1288,7 @@ UniValue mempoolInfoToJSON() UniValue getmempoolinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getmempoolinfo\n" "\nReturns details on the active state of the TX memory pool.\n" "\nResult:\n" @@ -1306,7 +1310,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request) UniValue preciousblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "preciousblock \"blockhash\"\n" "\nTreats a block as if it were received before others with the same work.\n" "\nA later preciousblock call can override the effect of an earlier one.\n" @@ -1344,7 +1348,7 @@ UniValue preciousblock(const JSONRPCRequest& request) UniValue invalidateblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "invalidateblock \"blockhash\"\n" "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" "\nArguments:\n" @@ -1382,7 +1386,7 @@ UniValue invalidateblock(const JSONRPCRequest& request) UniValue reconsiderblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "reconsiderblock \"blockhash\"\n" "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n" diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index a8c5c21ef1..35bc5d6a82 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -13,8 +13,6 @@ #include <boost/algorithm/string/case_conv.hpp> // for to_lower() #include <univalue.h> -using namespace std; - class CRPCConvertParam { public: @@ -83,7 +81,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getblockheader", 1, "verbose" }, { "gettransaction", 1, "include_watchonly" }, { "getrawtransaction", 1, "verbose" }, - { "createrawtransaction", 0, "transactions" }, + { "createrawtransaction", 0, "inputs" }, { "createrawtransaction", 1, "outputs" }, { "createrawtransaction", 2, "locktime" }, { "signrawtransaction", 1, "prevtxs" }, @@ -168,7 +166,7 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal) UniValue jVal; if (!jVal.read(std::string("[")+strVal+std::string("]")) || !jVal.isArray() || jVal.size()!=1) - throw runtime_error(string("Error parsing JSON:")+strVal); + throw std::runtime_error(std::string("Error parsing JSON:")+strVal); return jVal[0]; } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4ff8f39edc..4db8ffaa7d 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -30,8 +30,6 @@ #include <univalue.h> -using namespace std; - /** * Return average network hashes per second based on the last 'lookup' blocks, * or from the last difficulty change if 'lookup' is nonpositive. @@ -77,7 +75,7 @@ UniValue GetNetworkHashPS(int lookup, int height) { UniValue getnetworkhashps(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getnetworkhashps ( nblocks height )\n" "\nReturns the estimated network hashes per second based on the last n blocks.\n" "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" @@ -149,7 +147,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG UniValue generate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "generate nblocks ( maxtries )\n" "\nMine up to nblocks blocks immediately (before the RPC call returns)\n" "\nArguments:\n" @@ -185,7 +183,7 @@ UniValue generate(const JSONRPCRequest& request) UniValue generatetoaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "generatetoaddress nblocks address (maxtries)\n" "\nMine blocks immediately to a specified address (before the RPC call returns)\n" "\nArguments:\n" @@ -208,7 +206,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request) CBitcoinAddress address(request.params[1].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); - + boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript()); coinbaseScript->reserveScript = GetScriptForDestination(address.Get()); @@ -218,7 +216,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request) UniValue getmininginfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getmininginfo\n" "\nReturns a json object containing mining-related information." "\nResult:\n" @@ -259,7 +257,7 @@ UniValue getmininginfo(const JSONRPCRequest& request) UniValue prioritisetransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 2) - throw runtime_error( + throw std::runtime_error( "prioritisetransaction <txid> <fee delta>\n" "Accepts the transaction into mined blocks at a higher (or lower) priority\n" "\nArguments:\n" @@ -315,7 +313,7 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) { UniValue getblocktemplate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getblocktemplate ( TemplateRequest )\n" "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" "It returns data needed to construct a block to work on.\n" @@ -516,12 +514,22 @@ UniValue getblocktemplate(const JSONRPCRequest& request) // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? } + const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT]; + // If the caller is indicating segwit support, then allow CreateNewBlock() + // to select witness transactions, after segwit activates (otherwise + // don't). + bool fSupportsSegwit = setClientRules.find(segwit_info.name) != setClientRules.end(); + // Update block static CBlockIndex* pindexPrev; static int64_t nStart; static std::unique_ptr<CBlockTemplate> pblocktemplate; + // Cache whether the last invocation was with segwit support, to avoid returning + // a segwit-block to a non-segwit caller. + static bool fLastTemplateSupportsSegwit = true; if (pindexPrev != chainActive.Tip() || - (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5) || + fLastTemplateSupportsSegwit != fSupportsSegwit) { // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = nullptr; @@ -530,10 +538,11 @@ UniValue getblocktemplate(const JSONRPCRequest& request) nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); CBlockIndex* pindexPrevNew = chainActive.Tip(); nStart = GetTime(); + fLastTemplateSupportsSegwit = fSupportsSegwit; // Create new block CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy); + pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy, fSupportsSegwit); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -553,7 +562,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); UniValue transactions(UniValue::VARR); - map<uint256, int64_t> setTxIndex; + std::map<uint256, int64_t> setTxIndex; int i = 0; for (const auto& it : pblock->vtx) { const CTransaction& tx = *it; @@ -683,8 +692,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); - const struct BIP9DeploymentInfo& segwit_info = VersionBitsDeploymentInfo[Consensus::DEPLOYMENT_SEGWIT]; - if (!pblocktemplate->vchCoinbaseCommitment.empty() && setClientRules.find(segwit_info.name) != setClientRules.end()) { + if (!pblocktemplate->vchCoinbaseCommitment.empty() && fSupportsSegwit) { result.push_back(Pair("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end()))); } @@ -712,7 +720,7 @@ protected: UniValue submitblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n" "\nAttempts to submit new block to network.\n" "The 'jsonparametersobject' parameter is currently ignored.\n" @@ -777,7 +785,7 @@ UniValue submitblock(const JSONRPCRequest& request) UniValue estimatefee(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "estimatefee nblocks\n" "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" "confirmation within nblocks blocks. Uses virtual transaction size of transaction\n" @@ -811,7 +819,7 @@ UniValue estimatefee(const JSONRPCRequest& request) UniValue estimatesmartfee(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "estimatesmartfee nblocks\n" "\nWARNING: This interface is unstable and may disappear or change!\n" "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 5d86e94846..de1bbe62e5 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -20,13 +20,14 @@ #endif #include <stdint.h> +#ifdef HAVE_MALLOC_INFO +#include <malloc.h> +#endif #include <boost/assign/list_of.hpp> #include <univalue.h> -using namespace std; - /** * @note Do not add or change anything in the information returned by this * method. `getinfo` exists for backwards-compatibility only. It combines @@ -43,7 +44,7 @@ using namespace std; UniValue getinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getinfo\n" "\nDEPRECATED. Returns an object containing various state info.\n" "\nResult:\n" @@ -94,7 +95,7 @@ UniValue getinfo(const JSONRPCRequest& request) obj.push_back(Pair("timeoffset", GetTimeOffset())); if(g_connman) obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); - obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); + obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET)); #ifdef ENABLE_WALLET @@ -159,7 +160,7 @@ public: UniValue validateaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "validateaddress \"address\"\n" "\nReturn information about the given bitcoin address.\n" "\nArguments:\n" @@ -200,7 +201,7 @@ UniValue validateaddress(const JSONRPCRequest& request) if (isValid) { CTxDestination dest = address.Get(); - string currentAddress = address.ToString(); + std::string currentAddress = address.ToString(); ret.push_back(Pair("address", currentAddress)); CScript scriptPubKey = GetScriptForDestination(dest); @@ -248,13 +249,13 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa // Gather public keys if (nRequired < 1) - throw runtime_error("a multisignature address must require at least one key to redeem"); + throw std::runtime_error("a multisignature address must require at least one key to redeem"); if ((int)keys.size() < nRequired) - throw runtime_error( + throw std::runtime_error( strprintf("not enough keys supplied " "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); if (keys.size() > 16) - throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); + throw std::runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); std::vector<CPubKey> pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) @@ -266,15 +267,15 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa if (pwallet && address.IsValid()) { CKeyID keyID; if (!address.GetKeyID(keyID)) - throw runtime_error( + throw std::runtime_error( strprintf("%s does not refer to a key",ks)); CPubKey vchPubKey; if (!pwallet->GetPubKey(keyID, vchPubKey)) { - throw runtime_error( + throw std::runtime_error( strprintf("no full public key for address %s",ks)); } if (!vchPubKey.IsFullyValid()) - throw runtime_error(" Invalid public key: "+ks); + throw std::runtime_error(" Invalid public key: "+ks); pubkeys[i] = vchPubKey; } @@ -285,18 +286,18 @@ CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& pa { CPubKey vchPubKey(ParseHex(ks)); if (!vchPubKey.IsFullyValid()) - throw runtime_error(" Invalid public key: "+ks); + throw std::runtime_error(" Invalid public key: "+ks); pubkeys[i] = vchPubKey; } else { - throw runtime_error(" Invalid public key: "+ks); + throw std::runtime_error(" Invalid public key: "+ks); } } CScript result = GetScriptForMultisig(nRequired, pubkeys); if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) - throw runtime_error( + throw std::runtime_error( strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)); return result; @@ -312,7 +313,7 @@ UniValue createmultisig(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 2) { - string msg = "createmultisig nrequired [\"key\",...]\n" + std::string msg = "createmultisig nrequired [\"key\",...]\n" "\nCreates a multi-signature address with n signature of m keys required.\n" "It returns a json object with the address and redeemScript.\n" @@ -336,7 +337,7 @@ UniValue createmultisig(const JSONRPCRequest& request) "\nAs a json rpc call\n" + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") ; - throw runtime_error(msg); + throw std::runtime_error(msg); } // Construct using pay-to-script-hash: @@ -354,7 +355,7 @@ UniValue createmultisig(const JSONRPCRequest& request) UniValue verifymessage(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 3) - throw runtime_error( + throw std::runtime_error( "verifymessage \"address\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" @@ -376,9 +377,9 @@ UniValue verifymessage(const JSONRPCRequest& request) LOCK(cs_main); - string strAddress = request.params[0].get_str(); - string strSign = request.params[1].get_str(); - string strMessage = request.params[2].get_str(); + std::string strAddress = request.params[0].get_str(); + std::string strSign = request.params[1].get_str(); + std::string strMessage = request.params[2].get_str(); CBitcoinAddress addr(strAddress); if (!addr.IsValid()) @@ -389,7 +390,7 @@ UniValue verifymessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); bool fInvalid = false; - vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); + std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); if (fInvalid) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); @@ -408,7 +409,7 @@ UniValue verifymessage(const JSONRPCRequest& request) UniValue signmessagewithprivkey(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 2) - throw runtime_error( + throw std::runtime_error( "signmessagewithprivkey \"privkey\" \"message\"\n" "\nSign a message with the private key of an address\n" "\nArguments:\n" @@ -425,8 +426,8 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request) + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"") ); - string strPrivkey = request.params[0].get_str(); - string strMessage = request.params[1].get_str(); + std::string strPrivkey = request.params[0].get_str(); + std::string strMessage = request.params[1].get_str(); CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(strPrivkey); @@ -440,7 +441,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request) ss << strMessageMagic; ss << strMessage; - vector<unsigned char> vchSig; + std::vector<unsigned char> vchSig; if (!key.SignCompact(ss.GetHash(), vchSig)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); @@ -450,7 +451,7 @@ UniValue signmessagewithprivkey(const JSONRPCRequest& request) UniValue setmocktime(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "setmocktime timestamp\n" "\nSet the local time to given timestamp (-regtest only)\n" "\nArguments:\n" @@ -459,7 +460,7 @@ UniValue setmocktime(const JSONRPCRequest& request) ); if (!Params().MineBlocksOnDemand()) - throw runtime_error("setmocktime for regression testing (-regtest mode) only"); + throw std::runtime_error("setmocktime for regression testing (-regtest mode) only"); // For now, don't change mocktime if we're in the middle of validation, as // this could have an effect on mempool time-based eviction, as well as @@ -487,16 +488,39 @@ static UniValue RPCLockedMemoryInfo() return obj; } +#ifdef HAVE_MALLOC_INFO +static std::string RPCMallocInfo() +{ + char *ptr = nullptr; + size_t size = 0; + FILE *f = open_memstream(&ptr, &size); + if (f) { + malloc_info(0, f); + fclose(f); + if (ptr) { + std::string rv(ptr, size); + free(ptr); + return rv; + } + } + return ""; +} +#endif + UniValue getmemoryinfo(const JSONRPCRequest& request) { /* Please, avoid using the word "pool" here in the RPC interface or help, * as users will undoubtedly confuse it with the other "memory pool" */ - if (request.fHelp || request.params.size() != 0) - throw runtime_error( - "getmemoryinfo\n" + if (request.fHelp || request.params.size() > 1) + throw std::runtime_error( + "getmemoryinfo (\"mode\")\n" "Returns an object containing information about memory usage.\n" - "\nResult:\n" + "Arguments:\n" + "1. \"mode\" determines what kind of information is returned. This argument is optional, the default mode is \"stats\".\n" + " - \"stats\" returns general statistics about memory usage in the daemon.\n" + " - \"mallocinfo\" returns an XML string describing low-level heap state (only available if compiled with glibc 2.10+).\n" + "\nResult (mode \"stats\"):\n" "{\n" " \"locked\": { (json object) Information about locked memory manager\n" " \"used\": xxxxx, (numeric) Number of bytes used\n" @@ -507,19 +531,33 @@ UniValue getmemoryinfo(const JSONRPCRequest& request) " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n" " }\n" "}\n" + "\nResult (mode \"mallocinfo\"):\n" + "\"<malloc version=\"1\">...\"\n" "\nExamples:\n" + HelpExampleCli("getmemoryinfo", "") + HelpExampleRpc("getmemoryinfo", "") ); - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("locked", RPCLockedMemoryInfo())); - return obj; + + std::string mode = (request.params.size() < 1 || request.params[0].isNull()) ? "stats" : request.params[0].get_str(); + if (mode == "stats") { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("locked", RPCLockedMemoryInfo())); + return obj; + } else if (mode == "mallocinfo") { +#ifdef HAVE_MALLOC_INFO + return RPCMallocInfo(); +#else + throw JSONRPCError(RPC_INVALID_PARAMETER, "mallocinfo is only available when compiled with glibc 2.10+"); +#endif + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode); + } } UniValue echo(const JSONRPCRequest& request) { if (request.fHelp) - throw runtime_error( + throw std::runtime_error( "echo|echojson \"message\" ...\n" "\nSimply echo back the input arguments. This command is for testing.\n" "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in" @@ -533,7 +571,7 @@ static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */ - { "control", "getmemoryinfo", &getmemoryinfo, true, {} }, + { "control", "getmemoryinfo", &getmemoryinfo, true, {"mode"} }, { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */ { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} }, { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} }, diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index a7169749c3..44c6e6d308 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -23,12 +23,10 @@ #include <univalue.h> -using namespace std; - UniValue getconnectioncount(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getconnectioncount\n" "\nReturns the number of connections to other nodes.\n" "\nResult:\n" @@ -47,7 +45,7 @@ UniValue getconnectioncount(const JSONRPCRequest& request) UniValue ping(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "ping\n" "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" @@ -70,7 +68,7 @@ UniValue ping(const JSONRPCRequest& request) UniValue getpeerinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getpeerinfo\n" "\nReturns data about each connected network node as a json array of objects.\n" "\nResult:\n" @@ -102,7 +100,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) " n, (numeric) The heights of blocks we're currently asking from this peer\n" " ...\n" " ],\n" - " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n" + " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n" " \"bytessent_per_msg\": {\n" " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n" " ...\n" @@ -122,7 +120,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - vector<CNodeStats> vstats; + std::vector<CNodeStats> vstats; g_connman->GetNodeStats(vstats); UniValue ret(UniValue::VARR); @@ -191,12 +189,12 @@ UniValue getpeerinfo(const JSONRPCRequest& request) UniValue addnode(const JSONRPCRequest& request) { - string strCommand; + std::string strCommand; if (request.params.size() == 2) strCommand = request.params[1].get_str(); if (request.fHelp || request.params.size() != 2 || (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) - throw runtime_error( + throw std::runtime_error( "addnode \"node\" \"add|remove|onetry\"\n" "\nAttempts add or remove a node from the addnode list.\n" "Or try a connection to a node once.\n" @@ -211,7 +209,7 @@ UniValue addnode(const JSONRPCRequest& request) if(!g_connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); - string strNode = request.params[0].get_str(); + std::string strNode = request.params[0].get_str(); if (strCommand == "onetry") { @@ -237,7 +235,7 @@ UniValue addnode(const JSONRPCRequest& request) UniValue disconnectnode(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "disconnectnode \"node\" \n" "\nImmediately disconnects from the specified node.\n" "\nArguments:\n" @@ -260,7 +258,7 @@ UniValue disconnectnode(const JSONRPCRequest& request) UniValue getaddednodeinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getaddednodeinfo ( \"node\" )\n" "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n" @@ -328,7 +326,7 @@ UniValue getaddednodeinfo(const JSONRPCRequest& request) UniValue getnettotals(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 0) - throw runtime_error( + throw std::runtime_error( "getnettotals\n" "\nReturns information about network traffic, including bytes in, bytes out,\n" "and current time.\n" @@ -384,7 +382,7 @@ static UniValue GetNetworksInfo() obj.push_back(Pair("name", GetNetworkName(network))); obj.push_back(Pair("limited", IsLimited(network))); obj.push_back(Pair("reachable", IsReachable(network))); - obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())); + obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string())); obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials)); networks.push_back(obj); } @@ -394,7 +392,7 @@ static UniValue GetNetworksInfo() UniValue getnetworkinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getnetworkinfo\n" "Returns an object containing various state info regarding P2P networking.\n" "\nResult:\n" @@ -469,12 +467,12 @@ UniValue getnetworkinfo(const JSONRPCRequest& request) UniValue setban(const JSONRPCRequest& request) { - string strCommand; + std::string strCommand; if (request.params.size() >= 2) strCommand = request.params[1].get_str(); if (request.fHelp || request.params.size() < 2 || (strCommand != "add" && strCommand != "remove")) - throw runtime_error( + throw std::runtime_error( "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n" "\nAttempts add or remove a IP/Subnet from the banned list.\n" "\nArguments:\n" @@ -494,7 +492,7 @@ UniValue setban(const JSONRPCRequest& request) CNetAddr netAddr; bool isSubnet = false; - if (request.params[0].get_str().find("/") != string::npos) + if (request.params[0].get_str().find("/") != std::string::npos) isSubnet = true; if (!isSubnet) { @@ -506,7 +504,7 @@ UniValue setban(const JSONRPCRequest& request) LookupSubNet(request.params[0].get_str().c_str(), subNet); if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) - throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet"); + throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet"); if (strCommand == "add") { @@ -526,7 +524,7 @@ UniValue setban(const JSONRPCRequest& request) else if(strCommand == "remove") { if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) )) - throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed"); + throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned."); } return NullUniValue; } @@ -534,7 +532,7 @@ UniValue setban(const JSONRPCRequest& request) UniValue listbanned(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "listbanned\n" "\nList all banned IPs/Subnets.\n" "\nExamples:\n" @@ -567,7 +565,7 @@ UniValue listbanned(const JSONRPCRequest& request) UniValue clearbanned(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "clearbanned\n" "\nClear all banned IPs.\n" "\nExamples:\n" @@ -585,7 +583,7 @@ UniValue clearbanned(const JSONRPCRequest& request) UniValue setnetworkactive(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) { - throw runtime_error( + throw std::runtime_error( "setnetworkactive true|false\n" "\nDisable/enable all p2p network activity.\n" "\nArguments:\n" diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp index dc710d939f..2be1edb5a6 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -15,8 +15,6 @@ #include <stdint.h> #include <fstream> -using namespace std; - /** * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were @@ -26,7 +24,7 @@ using namespace std; * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html */ -UniValue JSONRPCRequestObj(const string& strMethod, const UniValue& params, const UniValue& id) +UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id) { UniValue request(UniValue::VOBJ); request.push_back(Pair("method", strMethod)); @@ -47,13 +45,13 @@ UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const Un return reply; } -string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) +std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) { UniValue reply = JSONRPCReplyObj(result, error, id); return reply.write() + "\n"; } -UniValue JSONRPCError(int code, const string& message) +UniValue JSONRPCError(int code, const std::string& message) { UniValue error(UniValue::VOBJ); error.push_back(Pair("code", code)); diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 47e56e712b..85bc4db101 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -31,9 +31,15 @@ enum HTTPStatusCode enum RPCErrorCode { //! Standard JSON-RPC 2.0 errors + // RPC_INVALID_REQUEST is internally mapped to HTTP_BAD_REQUEST (400). + // It should not be used for application-layer errors. RPC_INVALID_REQUEST = -32600, + // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404). + // It should not be used for application-layer errors. RPC_METHOD_NOT_FOUND = -32601, RPC_INVALID_PARAMS = -32602, + // RPC_INTERNAL_ERROR should only be used for genuine errors in bitcoind + // (for example datadir corruption). RPC_INTERNAL_ERROR = -32603, RPC_PARSE_ERROR = -32700, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index e6fe67de92..717e9d75f3 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -34,12 +34,10 @@ #include <univalue.h> -using namespace std; - void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex) { txnouttype type; - vector<CTxDestination> addresses; + std::vector<CTxDestination> addresses; int nRequired; out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey))); @@ -127,7 +125,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) UniValue getrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getrawtransaction \"txid\" ( verbose )\n" "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" @@ -140,7 +138,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" - "2. verbose (bool, optional, default=false) If true, return a string, other return a json object\n" + "2. verbose (bool, optional, default=false) If false, return a string, otherwise return a json object\n" "\nResult (if verbose is not set or set to false):\n" "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" @@ -215,7 +213,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) } else { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean."); - } + } } CTransactionRef tx; @@ -225,7 +223,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") + ". Use gettransaction for wallet transactions."); - string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); + std::string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); if (!fVerbose) return strHex; @@ -239,7 +237,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) UniValue gettxoutproof(const JSONRPCRequest& request) { if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2)) - throw runtime_error( + throw std::runtime_error( "gettxoutproof [\"txid\",...] ( blockhash )\n" "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" "\nNOTE: By default this function only works sometimes. This is when there is an\n" @@ -257,16 +255,16 @@ UniValue gettxoutproof(const JSONRPCRequest& request) "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" ); - set<uint256> setTxids; + std::set<uint256> setTxids; uint256 oneTxid; UniValue txids = request.params[0].get_array(); for (unsigned int idx = 0; idx < txids.size(); idx++) { const UniValue& txid = txids[idx]; if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str()); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid txid ")+txid.get_str()); uint256 hash(uint256S(txid.get_str())); if (setTxids.count(hash)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str()); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str()); setTxids.insert(hash); oneTxid = hash; } @@ -319,7 +317,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request) UniValue verifytxoutproof(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "verifytxoutproof \"proof\"\n" "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" "and throwing an RPC error if the block is not in our best chain\n" @@ -335,8 +333,8 @@ UniValue verifytxoutproof(const JSONRPCRequest& request) UniValue res(UniValue::VARR); - vector<uint256> vMatch; - vector<unsigned int> vIndex; + std::vector<uint256> vMatch; + std::vector<unsigned int> vIndex; if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) return res; @@ -353,7 +351,7 @@ UniValue verifytxoutproof(const JSONRPCRequest& request) UniValue createrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n" "\nCreate a transaction spending the given inputs and creating new outputs.\n" "Outputs can be addresses or data.\n" @@ -362,7 +360,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) "it is not stored in the wallet or transmitted to the network.\n" "\nArguments:\n" - "1. \"inputs\" (string, required) A json array of json objects\n" + "1. \"inputs\" (array, required) A json array of json objects\n" " [\n" " {\n" " \"txid\":\"id\", (string, required) The transaction id\n" @@ -371,7 +369,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) " } \n" " ,...\n" " ]\n" - "2. \"outputs\" (string, required) a json object with outputs\n" + "2. \"outputs\" (object, required) a json object with outputs\n" " {\n" " \"address\": x.xxx, (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" " \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n" @@ -434,9 +432,9 @@ UniValue createrawtransaction(const JSONRPCRequest& request) rawTx.vin.push_back(in); } - set<CBitcoinAddress> setAddress; - vector<string> addrList = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, addrList) { + std::set<CBitcoinAddress> setAddress; + std::vector<std::string> addrList = sendTo.getKeys(); + BOOST_FOREACH(const std::string& name_, addrList) { if (name_ == "data") { std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data"); @@ -446,10 +444,10 @@ UniValue createrawtransaction(const JSONRPCRequest& request) } else { CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); @@ -466,7 +464,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) UniValue decoderawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "decoderawtransaction \"hexstring\"\n" "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" @@ -535,7 +533,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) UniValue decodescript(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "decodescript \"hexstring\"\n" "\nDecode a hex-encoded script.\n" "\nArguments:\n" @@ -562,7 +560,7 @@ UniValue decodescript(const JSONRPCRequest& request) UniValue r(UniValue::VOBJ); CScript script; if (request.params[0].get_str().size() > 0){ - vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument")); + std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument")); script = CScript(scriptData.begin(), scriptData.end()); } else { // Empty scripts are valid @@ -600,7 +598,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) #endif if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" "\nSign inputs for raw transaction (serialized, hex-encoded).\n" "The second optional argument (may be null) is an array of previous transaction outputs that\n" @@ -665,9 +663,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request) #endif RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true); - vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1")); + std::vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1")); CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); - vector<CMutableTransaction> txVariants; + std::vector<CMutableTransaction> txVariants; while (!ssData.empty()) { try { CMutableTransaction tx; @@ -750,13 +748,13 @@ UniValue signrawtransaction(const JSONRPCRequest& request) if (nOut < 0) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); - vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); + std::vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); { CCoinsModifier coins = view.ModifyCoins(txid); if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { - string err("Previous output scriptPubKey mismatch:\n"); + std::string err("Previous output scriptPubKey mismatch:\n"); err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+ ScriptToAsmStr(scriptPubKey); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); @@ -782,7 +780,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) }); UniValue v = find_value(prevOut, "redeemScript"); if (!v.isNull()) { - vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); + std::vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); CScript redeemScript(rsData.begin(), rsData.end()); tempKeystore.AddCScript(redeemScript); } @@ -798,16 +796,16 @@ UniValue signrawtransaction(const JSONRPCRequest& request) int nHashType = SIGHASH_ALL; if (request.params.size() > 3 && !request.params[3].isNull()) { - static map<string, int> mapSigHashValues = + static std::map<std::string, int> mapSigHashValues = boost::assign::map_list_of - (string("ALL"), int(SIGHASH_ALL)) - (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) - (string("NONE"), int(SIGHASH_NONE)) - (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) - (string("SINGLE"), int(SIGHASH_SINGLE)) - (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) + (std::string("ALL"), int(SIGHASH_ALL)) + (std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) + (std::string("NONE"), int(SIGHASH_NONE)) + (std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) + (std::string("SINGLE"), int(SIGHASH_SINGLE)) + (std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) ; - string strHashType = request.params[3].get_str(); + std::string strHashType = request.params[3].get_str(); if (mapSigHashValues.count(strHashType)) nHashType = mapSigHashValues[strHashType]; else @@ -867,7 +865,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) UniValue sendrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "sendrawtransaction \"hexstring\" ( allowhighfees )\n" "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" "\nAlso see createrawtransaction and signrawtransaction calls.\n" @@ -938,7 +936,7 @@ static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"transactions","outputs","locktime"} }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime"} }, { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} }, { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} }, diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index f418d71e71..9b0699afcc 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -26,9 +26,6 @@ #include <memory> // for unique_ptr #include <unordered_map> -using namespace RPCServer; -using namespace std; - static bool fRPCRunning = false; static bool fRPCInWarmup = true; static std::string rpcWarmupStatus("RPC server started"); @@ -43,7 +40,6 @@ static struct CRPCSignals boost::signals2::signal<void ()> Started; boost::signals2::signal<void ()> Stopped; boost::signals2::signal<void (const CRPCCommand&)> PreCommand; - boost::signals2::signal<void (const CRPCCommand&)> PostCommand; } g_rpcSignals; void RPCServer::OnStarted(boost::function<void ()> slot) @@ -61,13 +57,8 @@ void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot) g_rpcSignals.PreCommand.connect(boost::bind(slot, _1)); } -void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot) -{ - g_rpcSignals.PostCommand.connect(boost::bind(slot, _1)); -} - void RPCTypeCheck(const UniValue& params, - const list<UniValue::VType>& typesExpected, + const std::list<UniValue::VType>& typesExpected, bool fAllowNull) { unsigned int i = 0; @@ -92,7 +83,7 @@ void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected) } void RPCTypeCheckObj(const UniValue& o, - const map<string, UniValueType>& typesExpected, + const std::map<std::string, UniValueType>& typesExpected, bool fAllowNull, bool fStrict) { @@ -102,7 +93,7 @@ void RPCTypeCheckObj(const UniValue& o, throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) { - string err = strprintf("Expected type %s for %s, got %s", + 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); } @@ -110,11 +101,11 @@ void RPCTypeCheckObj(const UniValue& o, if (fStrict) { - BOOST_FOREACH(const string& k, o.getKeys()) + BOOST_FOREACH(const std::string& k, o.getKeys()) { if (typesExpected.count(k) == 0) { - string err = strprintf("Unexpected key %s", k); + std::string err = strprintf("Unexpected key %s", k); throw JSONRPCError(RPC_TYPE_ERROR, err); } } @@ -143,9 +134,9 @@ UniValue ValueFromAmount(const CAmount& amount) strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder)); } -uint256 ParseHashV(const UniValue& v, string strName) +uint256 ParseHashV(const UniValue& v, std::string strName) { - string strHex; + std::string strHex; if (v.isStr()) strHex = v.get_str(); if (!IsHex(strHex)) // Note: IsHex("") is false @@ -156,20 +147,20 @@ uint256 ParseHashV(const UniValue& v, string strName) result.SetHex(strHex); return result; } -uint256 ParseHashO(const UniValue& o, string strKey) +uint256 ParseHashO(const UniValue& o, std::string strKey) { return ParseHashV(find_value(o, strKey), strKey); } -vector<unsigned char> ParseHexV(const UniValue& v, string strName) +std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName) { - string strHex; + 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); } -vector<unsigned char> ParseHexO(const UniValue& o, string strKey) +std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey) { return ParseHexV(find_value(o, strKey), strKey); } @@ -180,12 +171,12 @@ vector<unsigned char> ParseHexO(const UniValue& o, string strKey) std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const { - string strRet; - string category; - set<rpcfn_type> setDone; - vector<pair<string, const CRPCCommand*> > vCommands; + std::string strRet; + std::string category; + std::set<rpcfn_type> setDone; + std::vector<std::pair<std::string, const CRPCCommand*> > vCommands; - for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi) + for (std::map<std::string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi) vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second)); sort(vCommands.begin(), vCommands.end()); @@ -193,10 +184,10 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& jreq.fHelp = true; jreq.params = UniValue(); - BOOST_FOREACH(const PAIRTYPE(string, const CRPCCommand*)& command, vCommands) + BOOST_FOREACH(const PAIRTYPE(std::string, const CRPCCommand*)& command, vCommands) { const CRPCCommand *pcmd = command.second; - string strMethod = pcmd->name; + std::string strMethod = pcmd->name; if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand) continue; jreq.strMethod = strMethod; @@ -209,10 +200,10 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& catch (const std::exception& e) { // Help text is returned in an exception - string strHelp = string(e.what()); + std::string strHelp = std::string(e.what()); if (strCommand == "") { - if (strHelp.find('\n') != string::npos) + if (strHelp.find('\n') != std::string::npos) strHelp = strHelp.substr(0, strHelp.find('\n')); if (category != pcmd->category) @@ -220,7 +211,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& if (!category.empty()) strRet += "\n"; category = pcmd->category; - string firstLetter = category.substr(0,1); + std::string firstLetter = category.substr(0,1); boost::to_upper(firstLetter); strRet += "== " + firstLetter + category.substr(1) + " ==\n"; } @@ -237,7 +228,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& UniValue help(const JSONRPCRequest& jsonRequest) { if (jsonRequest.fHelp || jsonRequest.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "help ( \"command\" )\n" "\nList all commands, or get help for a specified command.\n" "\nArguments:\n" @@ -246,7 +237,7 @@ UniValue help(const JSONRPCRequest& jsonRequest) "\"text\" (string) The help text\n" ); - string strCommand; + std::string strCommand; if (jsonRequest.params.size() > 0) strCommand = jsonRequest.params[0].get_str(); @@ -258,7 +249,7 @@ UniValue stop(const JSONRPCRequest& jsonRequest) { // Accept the deprecated and ignored 'detach' boolean argument if (jsonRequest.fHelp || jsonRequest.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "stop\n" "\nStop Bitcoin server."); // Event loop will exit after current HTTP requests have been handled, so @@ -292,7 +283,7 @@ CRPCTable::CRPCTable() const CRPCCommand *CRPCTable::operator[](const std::string &name) const { - map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name); + std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name); if (it == mapCommands.end()) return NULL; return (*it).second; @@ -304,7 +295,7 @@ bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd) return false; // don't allow overwriting for now - map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name); + std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name); if (it != mapCommands.end()) return false; @@ -494,8 +485,6 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const { throw JSONRPCError(RPC_MISC_ERROR, e.what()); } - - g_rpcSignals.PostCommand(*pcmd); } std::vector<std::string> CRPCTable::listCommands() const diff --git a/src/rpc/server.h b/src/rpc/server.h index 68d8a6ec96..de14c7ed3e 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -28,7 +28,6 @@ namespace RPCServer void OnStarted(boost::function<void ()> slot); void OnStopped(boost::function<void ()> slot); void OnPreCommand(boost::function<void (const CRPCCommand&)> slot); - void OnPostCommand(boost::function<void (const CRPCCommand&)> slot); } class CBlockIndex; @@ -69,7 +68,7 @@ void SetRPCWarmupStatus(const std::string& newStatus); void SetRPCWarmupFinished(); /* returns the current warmup state. */ -bool RPCIsInWarmup(std::string *statusOut); +bool RPCIsInWarmup(std::string *outStatus); /** * Type-check arguments; throws JSONRPCError if wrong type given. Does not check that diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f9b7835882..8ecf0bbdac 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -13,9 +13,7 @@ #include "script/script.h" #include "uint256.h" -using namespace std; - -typedef vector<unsigned char> valtype; +typedef std::vector<unsigned char> valtype; namespace { @@ -56,10 +54,10 @@ bool CastToBool(const valtype& vch) */ #define stacktop(i) (stack.at(stack.size()+(i))) #define altstacktop(i) (altstack.at(altstack.size()+(i))) -static inline void popstack(vector<valtype>& stack) +static inline void popstack(std::vector<valtype>& stack) { if (stack.empty()) - throw runtime_error("popstack(): stack empty"); + throw std::runtime_error("popstack(): stack empty"); stack.pop_back(); } @@ -194,7 +192,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) { return true; } -bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) { +bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) { // Empty signature. Not strictly DER encoded, but allowed to provide a // compact way to provide an invalid signature for use with CHECK(MULTI)SIG if (vchSig.size() == 0) { @@ -245,7 +243,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { return true; } -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -260,8 +258,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; - vector<bool> vfExec; - vector<valtype> altstack; + std::vector<bool> vfExec; + std::vector<valtype> altstack; set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); if (script.size() > MAX_SCRIPT_SIZE) return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); @@ -1250,14 +1248,14 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha return pubkey.Verify(sighash, vchSig); } -bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool TransactionSignatureChecker::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; // Hash type is one byte tacked on to the end of the signature - vector<unsigned char> vchSig(vchSigIn); + std::vector<unsigned char> vchSig(vchSigIn); if (vchSig.empty()) return false; int nHashType = vchSig.back(); @@ -1355,7 +1353,7 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { - vector<vector<unsigned char> > stack; + std::vector<std::vector<unsigned char> > stack; CScript scriptPubKey; if (witversion == 0) { @@ -1420,7 +1418,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); } - vector<vector<unsigned char> > stack, stackCopy; + std::vector<std::vector<unsigned char> > stack, stackCopy; if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) // serror is set return false; @@ -1558,7 +1556,7 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, if (scriptPubKey.IsPayToScriptHash() && scriptSig.IsPushOnly()) { CScript::const_iterator pc = scriptSig.begin(); - vector<unsigned char> data; + std::vector<unsigned char> data; while (pc < scriptSig.end()) { opcodetype opcode; scriptSig.GetOp(pc, opcode, data); diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 608a8de8f5..a4743281b1 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -13,11 +13,9 @@ #include <boost/foreach.hpp> -using namespace std; +typedef std::vector<unsigned char> valtype; -typedef vector<unsigned char> valtype; - -unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore) +unsigned int HaveKeys(const std::vector<valtype>& pubkeys, const CKeyStore& keystore) { unsigned int nResult = 0; BOOST_FOREACH(const valtype& pubkey, pubkeys) @@ -49,7 +47,7 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion) { - vector<valtype> vSolutions; + std::vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { if (keystore.HaveWatchOnly(scriptPubKey)) @@ -132,7 +130,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& // partially owned (somebody else has a key that can spend // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations. - vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); + std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); if (sigversion != SIGVERSION_BASE) { for (size_t i = 0; i < keys.size(); i++) { if (keys[i].size() != 33) { diff --git a/src/script/script.cpp b/src/script/script.cpp index 01180a7d6d..70eb8a139b 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -8,8 +8,6 @@ #include "tinyformat.h" #include "utilstrencodings.h" -using namespace std; - const char* GetOpName(opcodetype opcode) { switch (opcode) @@ -186,7 +184,7 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const // get the last item that the scriptSig // pushes onto the stack: const_iterator pc = scriptSig.begin(); - vector<unsigned char> vData; + std::vector<unsigned char> vData; while (pc < scriptSig.end()) { opcodetype opcode; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index b008df2591..5682418546 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -14,8 +14,6 @@ #include <boost/foreach.hpp> -using namespace std; - typedef std::vector<unsigned char> valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} @@ -39,14 +37,14 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) { - vector<unsigned char> vchSig; + std::vector<unsigned char> vchSig; if (!creator.CreateSig(vchSig, address, scriptCode, sigversion)) return false; ret.push_back(vchSig); return true; } -static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) +static bool SignN(const std::vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -73,7 +71,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP uint160 h160; ret.clear(); - vector<valtype> vSolutions; + std::vector<valtype> vSolutions; if (!Solver(scriptPubKey, whichTypeRet, vSolutions)) return false; @@ -125,7 +123,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP } } -static CScript PushAll(const vector<valtype>& values) +static CScript PushAll(const std::vector<valtype>& values) { CScript result; BOOST_FOREACH(const valtype& v, values) { @@ -228,12 +226,12 @@ bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutab return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); } -static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const vector<valtype>& vSolutions, - const vector<valtype>& sigs1, const vector<valtype>& sigs2, SigVersion sigversion) +static std::vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, + const std::vector<valtype>& vSolutions, + const std::vector<valtype>& sigs1, const std::vector<valtype>& sigs2, SigVersion sigversion) { // Combine all the signatures we've got: - set<valtype> allsigs; + std::set<valtype> allsigs; BOOST_FOREACH(const valtype& v, sigs1) { if (!v.empty()) @@ -249,7 +247,7 @@ static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSi assert(vSolutions.size() > 1); unsigned int nSigsRequired = vSolutions.front()[0]; unsigned int nPubKeys = vSolutions.size()-2; - map<valtype, valtype> sigs; + std::map<valtype, valtype> sigs; BOOST_FOREACH(const valtype& sig, allsigs) { for (unsigned int i = 0; i < nPubKeys; i++) @@ -306,7 +304,7 @@ struct Stacks } static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const txnouttype txType, const vector<valtype>& vSolutions, + const txnouttype txType, const std::vector<valtype>& vSolutions, Stacks sigs1, Stacks sigs2, SigVersion sigversion) { switch (txType) @@ -340,7 +338,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature CScript pubKey2(spk.begin(), spk.end()); txnouttype txType2; - vector<vector<unsigned char> > vSolutions2; + std::vector<std::vector<unsigned char> > vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); @@ -360,7 +358,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature // Recur to combine: CScript pubKey2(sigs1.witness.back().begin(), sigs1.witness.back().end()); txnouttype txType2; - vector<valtype> vSolutions2; + std::vector<valtype> vSolutions2; Solver(pubKey2, txType2, vSolutions2); sigs1.witness.pop_back(); sigs1.script = sigs1.witness; @@ -383,7 +381,7 @@ SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignature const SignatureData& scriptSig1, const SignatureData& scriptSig2) { txnouttype txType; - vector<vector<unsigned char> > vSolutions; + std::vector<std::vector<unsigned char> > vSolutions; Solver(scriptPubKey, txType, vSolutions); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 4b9bec9aa1..63f20b0993 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -12,9 +12,7 @@ #include <boost/foreach.hpp> -using namespace std; - -typedef vector<unsigned char> valtype; +typedef std::vector<unsigned char> valtype; bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER; unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY; @@ -40,20 +38,20 @@ const char* GetTxnOutputType(txnouttype t) /** * Return public keys or hashes from scriptPubKey, for 'standard' transaction types. */ -bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet) +bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) { // Templates - static multimap<txnouttype, CScript> mTemplates; + static std::multimap<txnouttype, CScript> mTemplates; if (mTemplates.empty()) { // Standard tx, sender provides pubkey, receiver adds signature - mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); + mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey - mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); + mTemplates.insert(std::make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); // Sender provides N pubkeys, receivers provides M signatures - mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); + mTemplates.insert(std::make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); } vSolutionsRet.clear(); @@ -63,7 +61,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi if (scriptPubKey.IsPayToScriptHash()) { typeRet = TX_SCRIPTHASH; - vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); + std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22); vSolutionsRet.push_back(hashBytes); return true; } @@ -102,7 +100,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi vSolutionsRet.clear(); opcodetype opcode1, opcode2; - vector<unsigned char> vch1, vch2; + std::vector<unsigned char> vch1, vch2; // Compare CScript::const_iterator pc1 = script1.begin(); @@ -181,7 +179,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { - vector<valtype> vSolutions; + std::vector<valtype> vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) return false; @@ -209,11 +207,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) return false; } -bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet) +bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet) { addressRet.clear(); typeRet = TX_NONSTANDARD; - vector<valtype> vSolutions; + std::vector<valtype> vSolutions; if (!Solver(scriptPubKey, typeRet, vSolutions)) return false; if (typeRet == TX_NULL_DATA){ diff --git a/src/streams.h b/src/streams.h index 3c24c2c373..1387b9cf54 100644 --- a/src/streams.h +++ b/src/streams.h @@ -404,8 +404,8 @@ public: return (*this); } - void GetAndClear(CSerializeData &data) { - data.insert(data.end(), begin(), end()); + void GetAndClear(CSerializeData &d) { + d.insert(d.end(), begin(), end()); clear(); } diff --git a/src/sync.cpp b/src/sync.cpp index fce57f1df9..552682ab67 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -46,8 +46,6 @@ struct CLockLocation { return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : ""); } - std::string MutexName() const { return mutexName; } - bool fTry; private: std::string mutexName; diff --git a/src/sync.h b/src/sync.h index 3b29050e0e..9274f50d8b 100644 --- a/src/sync.h +++ b/src/sync.h @@ -97,7 +97,6 @@ public: } }; -typedef CCriticalSection CDynamicCriticalSection; /** Wrapped boost mutex: supports waiting but not recursive locking */ typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection; diff --git a/src/test/README.md b/src/test/README.md index 8f99804e10..eeb04c6ffa 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -50,12 +50,3 @@ examine `uint256_tests.cpp`. For further reading, I found the following website to be helpful in explaining how the boost unit test framework works: [http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/). - -### bitcoin-util-test.py - -The test directory also contains the bitcoin-util-test.py tool, which tests bitcoin utils (currently just bitcoin-tx). This test gets run automatically during the `make check` build process. It is also possible to run the test manually from the src directory: - -``` -test/bitcoin-util-test.py --srcdir=[current directory] - -``` diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 322addc9f6..5d1c5b78d1 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -413,7 +413,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) size_t percent23 = (addrman.size() * 23) / 100; BOOST_CHECK(vAddr.size() == percent23); BOOST_CHECK(vAddr.size() == 461); - // (Addrman.size() < number of addresses added) due to address collisons. + // (Addrman.size() < number of addresses added) due to address collisions. BOOST_CHECK(addrman.size() == 2007); } diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py deleted file mode 100755 index e2087187aa..0000000000 --- a/src/test/bitcoin-util-test.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Copyright 2014 BitPay Inc. -# Copyright 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. -from __future__ import division,print_function,unicode_literals -import os -import bctest -import buildenv -import argparse -import logging - -help_text="""Test framework for bitcoin utils. - -Runs automatically during `make check`. - -Can also be run manually from the src directory by specifying the source directory: - -test/bitcoin-util-test.py --srcdir='srcdir' [--verbose] -""" - -if __name__ == '__main__': - # Try to get the source directory from the environment variables. This will - # be set for `make check` automated runs. If environment variable is not set, - # then get the source directory from command line args. - try: - srcdir = os.environ["srcdir"] - verbose = False - except: - parser = argparse.ArgumentParser(description=help_text) - parser.add_argument('-s', '--srcdir') - parser.add_argument('-v', '--verbose', action='store_true') - args = parser.parse_args() - srcdir = args.srcdir - verbose = args.verbose - - if verbose: - level = logging.DEBUG - else: - level = logging.ERROR - formatter = '%(asctime)s - %(levelname)s - %(message)s' - # Add the format/level to the logger - logging.basicConfig(format = formatter, level=level) - - bctest.bctester(srcdir + "/test/data", "bitcoin-util-test.json", buildenv) diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in deleted file mode 100644 index 153f34a3db..0000000000 --- a/src/test/buildenv.py.in +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env python -exeext="@EXEEXT@" diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp new file mode 100644 index 0000000000..287395c6c6 --- /dev/null +++ b/src/test/checkqueue_tests.cpp @@ -0,0 +1,442 @@ +// Copyright (c) 2012-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. + +#include "util.h" +#include "utiltime.h" +#include "validation.h" + +#include "test/test_bitcoin.h" +#include "checkqueue.h" +#include <boost/test/unit_test.hpp> +#include <boost/thread.hpp> +#include <atomic> +#include <thread> +#include <vector> +#include <mutex> +#include <condition_variable> + +#include <unordered_set> +#include <memory> +#include "random.h" + +// BasicTestingSetup not sufficient because nScriptCheckThreads is not set +// otherwise. +BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, TestingSetup) + +static const int QUEUE_BATCH_SIZE = 128; + +struct FakeCheck { + bool operator()() + { + return true; + } + void swap(FakeCheck& x){}; +}; + +struct FakeCheckCheckCompletion { + static std::atomic<size_t> n_calls; + bool operator()() + { + ++n_calls; + return true; + } + void swap(FakeCheckCheckCompletion& x){}; +}; + +struct FailingCheck { + bool fails; + FailingCheck(bool _fails) : fails(_fails){}; + FailingCheck() : fails(true){}; + bool operator()() + { + return !fails; + } + void swap(FailingCheck& x) + { + std::swap(fails, x.fails); + }; +}; + +struct UniqueCheck { + static std::mutex m; + static std::unordered_multiset<size_t> results; + size_t check_id; + UniqueCheck(size_t check_id_in) : check_id(check_id_in){}; + UniqueCheck() : check_id(0){}; + bool operator()() + { + std::lock_guard<std::mutex> l(m); + results.insert(check_id); + return true; + } + void swap(UniqueCheck& x) { std::swap(x.check_id, check_id); }; +}; + + +struct MemoryCheck { + static std::atomic<size_t> fake_allocated_memory; + bool b {false}; + bool operator()() + { + return true; + } + MemoryCheck(){}; + MemoryCheck(const MemoryCheck& x) + { + // We have to do this to make sure that destructor calls are paired + // + // Really, copy constructor should be deletable, but CCheckQueue breaks + // if it is deleted because of internal push_back. + fake_allocated_memory += b; + }; + MemoryCheck(bool b_) : b(b_) + { + fake_allocated_memory += b; + }; + ~MemoryCheck(){ + fake_allocated_memory -= b; + + }; + void swap(MemoryCheck& x) { std::swap(b, x.b); }; +}; + +struct FrozenCleanupCheck { + static std::atomic<uint64_t> nFrozen; + static std::condition_variable cv; + static std::mutex m; + // Freezing can't be the default initialized behavior given how the queue + // swaps in default initialized Checks. + bool should_freeze {false}; + bool operator()() + { + return true; + } + FrozenCleanupCheck() {} + ~FrozenCleanupCheck() + { + if (should_freeze) { + std::unique_lock<std::mutex> l(m); + nFrozen = 1; + cv.notify_one(); + cv.wait(l, []{ return nFrozen == 0;}); + } + } + void swap(FrozenCleanupCheck& x){std::swap(should_freeze, x.should_freeze);}; +}; + +// Static Allocations +std::mutex FrozenCleanupCheck::m{}; +std::atomic<uint64_t> FrozenCleanupCheck::nFrozen{0}; +std::condition_variable FrozenCleanupCheck::cv{}; +std::mutex UniqueCheck::m; +std::unordered_multiset<size_t> UniqueCheck::results; +std::atomic<size_t> FakeCheckCheckCompletion::n_calls{0}; +std::atomic<size_t> MemoryCheck::fake_allocated_memory{0}; + +// Queue Typedefs +typedef CCheckQueue<FakeCheckCheckCompletion> Correct_Queue; +typedef CCheckQueue<FakeCheck> Standard_Queue; +typedef CCheckQueue<FailingCheck> Failing_Queue; +typedef CCheckQueue<UniqueCheck> Unique_Queue; +typedef CCheckQueue<MemoryCheck> Memory_Queue; +typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue; + + +/** This test case checks that the CCheckQueue works properly + * with each specified size_t Checks pushed. + */ +void Correct_Queue_range(std::vector<size_t> range) +{ + auto small_queue = std::unique_ptr<Correct_Queue>(new Correct_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{small_queue->Thread();}); + } + // Make vChecks here to save on malloc (this test can be slow...) + std::vector<FakeCheckCheckCompletion> vChecks; + for (auto i : range) { + size_t total = i; + FakeCheckCheckCompletion::n_calls = 0; + CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get()); + while (total) { + vChecks.resize(std::min(total, (size_t) GetRand(10))); + total -= vChecks.size(); + control.Add(vChecks); + } + 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(); + tg.join_all(); +} + +/** Test that 0 checks is correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) +{ + std::vector<size_t> range; + range.push_back((size_t)0); + Correct_Queue_range(range); +} +/** Test that 1 check is correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One) +{ + std::vector<size_t> range; + range.push_back((size_t)1); + Correct_Queue_range(range); +} +/** Test that MAX check is correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max) +{ + std::vector<size_t> range; + range.push_back(100000); + Correct_Queue_range(range); +} +/** Test that random numbers of checks are correct + */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) +{ + std::vector<size_t> range; + range.reserve(100000/1000); + for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)GetRand(std::min((size_t)1000, ((size_t)100000) - i)))) + range.push_back(i); + Correct_Queue_range(range); +} + + +/** Test that failing checks are caught */ +BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) +{ + auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE}); + + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{fail_queue->Thread();}); + } + + for (size_t i = 0; i < 1001; ++i) { + CCheckQueueControl<FailingCheck> control(fail_queue.get()); + size_t remaining = i; + while (remaining) { + size_t r = GetRand(10); + + std::vector<FailingCheck> vChecks; + vChecks.reserve(r); + for (size_t k = 0; k < r && remaining; k++, remaining--) + vChecks.emplace_back(remaining == 1); + control.Add(vChecks); + } + bool success = control.Wait(); + if (i > 0) { + BOOST_REQUIRE(!success); + } else if (i == 0) { + BOOST_REQUIRE(success); + } + } + tg.interrupt_all(); + tg.join_all(); +} +// Test that a block validation which fails does not interfere with +// future blocks, ie, the bad state is cleared. +BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure) +{ + auto fail_queue = std::unique_ptr<Failing_Queue>(new Failing_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{fail_queue->Thread();}); + } + + for (auto times = 0; times < 10; ++times) { + for (bool end_fails : {true, false}) { + CCheckQueueControl<FailingCheck> control(fail_queue.get()); + { + std::vector<FailingCheck> vChecks; + vChecks.resize(100, false); + vChecks[99] = end_fails; + control.Add(vChecks); + } + bool r =control.Wait(); + BOOST_REQUIRE(r || end_fails); + } + } + tg.interrupt_all(); + tg.join_all(); +} + +// Test that unique checks are actually all called individually, rather than +// just one check being called repeatedly. Test that checks are not called +// more than once as well +BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) +{ + auto queue = std::unique_ptr<Unique_Queue>(new Unique_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{queue->Thread();}); + + } + + size_t COUNT = 100000; + size_t total = COUNT; + { + CCheckQueueControl<UniqueCheck> control(queue.get()); + while (total) { + size_t r = GetRand(10); + std::vector<UniqueCheck> vChecks; + for (size_t k = 0; k < r && total; k++) + vChecks.emplace_back(--total); + control.Add(vChecks); + } + } + bool r = true; + BOOST_REQUIRE_EQUAL(UniqueCheck::results.size(), COUNT); + for (size_t i = 0; i < COUNT; ++i) + r = r && UniqueCheck::results.count(i) == 1; + BOOST_REQUIRE(r); + tg.interrupt_all(); + tg.join_all(); +} + + +// Test that blocks which might allocate lots of memory free their memory aggressively. +// +// This test attempts to catch a pathological case where by lazily freeing +// checks might mean leaving a check un-swapped out, and decreasing by 1 each +// time could leave the data hanging across a sequence of blocks. +BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) +{ + auto queue = std::unique_ptr<Memory_Queue>(new Memory_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{queue->Thread();}); + } + for (size_t i = 0; i < 1000; ++i) { + size_t total = i; + { + CCheckQueueControl<MemoryCheck> control(queue.get()); + while (total) { + size_t r = GetRand(10); + std::vector<MemoryCheck> vChecks; + for (size_t k = 0; k < r && total; k++) { + total--; + // Each iteration leaves data at the front, back, and middle + // to catch any sort of deallocation failure + vChecks.emplace_back(total == 0 || total == i || total == i/2); + } + control.Add(vChecks); + } + } + BOOST_REQUIRE_EQUAL(MemoryCheck::fake_allocated_memory, 0); + } + tg.interrupt_all(); + tg.join_all(); +} + +// Test that a new verification cannot occur until all checks +// have been destructed +BOOST_AUTO_TEST_CASE(test_CheckQueue_FrozenCleanup) +{ + auto queue = std::unique_ptr<FrozenCleanup_Queue>(new FrozenCleanup_Queue {QUEUE_BATCH_SIZE}); + boost::thread_group tg; + bool fails = false; + for (auto x = 0; x < nScriptCheckThreads; ++x) { + tg.create_thread([&]{queue->Thread();}); + } + std::thread t0([&]() { + CCheckQueueControl<FrozenCleanupCheck> control(queue.get()); + std::vector<FrozenCleanupCheck> vChecks(1); + // Freezing can't be the default initialized behavior given how the queue + // swaps in default initialized Checks (otherwise freezing destructor + // would get called twice). + vChecks[0].should_freeze = true; + control.Add(vChecks); + control.Wait(); // Hangs here + }); + { + std::unique_lock<std::mutex> l(FrozenCleanupCheck::m); + // Wait until the queue has finished all jobs and frozen + FrozenCleanupCheck::cv.wait(l, [](){return FrozenCleanupCheck::nFrozen == 1;}); + // Try to get control of the queue a bunch of times + for (auto x = 0; x < 100 && !fails; ++x) { + fails = queue->ControlMutex.try_lock(); + } + // Unfreeze + FrozenCleanupCheck::nFrozen = 0; + } + // Awaken frozen destructor + FrozenCleanupCheck::cv.notify_one(); + // Wait for control to finish + t0.join(); + tg.interrupt_all(); + tg.join_all(); + BOOST_REQUIRE(!fails); +} + + +/** Test that CCheckQueueControl is threadsafe */ +BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks) +{ + auto queue = std::unique_ptr<Standard_Queue>(new Standard_Queue{QUEUE_BATCH_SIZE}); + { + boost::thread_group tg; + std::atomic<int> nThreads {0}; + std::atomic<int> fails {0}; + for (size_t i = 0; i < 3; ++i) { + tg.create_thread( + [&]{ + CCheckQueueControl<FakeCheck> control(queue.get()); + // While sleeping, no other thread should execute to this point + auto observed = ++nThreads; + MilliSleep(10); + fails += observed != nThreads; + }); + } + tg.join_all(); + BOOST_REQUIRE_EQUAL(fails, 0); + } + { + boost::thread_group tg; + std::mutex m; + bool has_lock {false}; + bool has_tried {false}; + bool done {false}; + bool done_ack {false}; + std::condition_variable cv; + { + std::unique_lock<std::mutex> l(m); + tg.create_thread([&]{ + CCheckQueueControl<FakeCheck> control(queue.get()); + std::unique_lock<std::mutex> ll(m); + has_lock = true; + cv.notify_one(); + cv.wait(ll, [&]{return has_tried;}); + done = true; + cv.notify_one(); + // Wait until the done is acknowledged + // + cv.wait(ll, [&]{return done_ack;}); + }); + // Wait for thread to get the lock + cv.wait(l, [&](){return has_lock;}); + bool fails = false; + for (auto x = 0; x < 100 && !fails; ++x) { + fails = queue->ControlMutex.try_lock(); + } + has_tried = true; + cv.notify_one(); + cv.wait(l, [&](){return done;}); + // Acknowledge the done + done_ack = true; + cv.notify_one(); + BOOST_REQUIRE(!fails); + } + tg.join_all(); + } +} +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index 00446aa11e..4d6d6d6210 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -379,7 +379,7 @@ void test_cache_generations() // Loose Check that hit rate is above min_hit_rate BOOST_CHECK(hit > min_hit_rate); // Tighter check, count number of times we are less than tight_hit_rate - // (and implicityly, greater than min_hit_rate) + // (and implicitly, greater than min_hit_rate) out_of_tight_tolerance += hit < tight_hit_rate; } // Check that being out of tolerance happens less than diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 22c90bd95b..9d55beb8ea 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -141,6 +141,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) // Call the destructor to free leveldb LOCK delete dbw; + dbw = nullptr; // Now, set up another wrapper that wants to obfuscate the same directory CDBWrapper odbw(ph, (1 << 10), false, false, true); @@ -182,6 +183,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) // Call the destructor to free leveldb LOCK delete dbw; + dbw = nullptr; // Simulate a -reindex by wiping the existing data store CDBWrapper odbw(ph, (1 << 10), false, true, true); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 40a7fdf11d..559b3caf1c 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -29,34 +29,6 @@ static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs"); static const std::string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF"); -#ifdef KEY_TESTS_DUMPINFO -void dumpKeyInfo(uint256 privkey) -{ - CKey key; - key.resize(32); - memcpy(&secret[0], &privkey, 32); - std::vector<unsigned char> sec; - sec.resize(32); - memcpy(&sec[0], &secret[0], 32); - printf(" * secret (hex): %s\n", HexStr(sec).c_str()); - - for (int nCompressed=0; nCompressed<2; nCompressed++) - { - bool fCompressed = nCompressed == 1; - printf(" * %s:\n", fCompressed ? "compressed" : "uncompressed"); - CBitcoinSecret bsecret; - bsecret.SetSecret(secret, fCompressed); - printf(" * secret (base58): %s\n", bsecret.ToString().c_str()); - CKey key; - key.SetSecret(secret, fCompressed); - std::vector<unsigned char> vchPubKey = key.GetPubKey(); - printf(" * pubkey (hex): %s\n", HexStr(vchPubKey).c_str()); - printf(" * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str()); - } -} -#endif - - BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(key_test1) diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index af02d67f74..f2f06fa8e2 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) // If no mutation was done (once for every ntx value), try up to 16 branches. if (mutate == 0) { for (int loop = 0; loop < std::min(ntx, 16); loop++) { - // If ntx <= 16, try all branches. Otherise, try 16 random ones. + // If ntx <= 16, try all branches. Otherwise, try 16 random ones. int mtx = loop; if (ntx > 16) { mtx = insecure_rand() % ntx; diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 399bdbc811..7cf2a744ea 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_CHECK(banned_until.get_int64() > now); BOOST_CHECK(banned_until.get_int64()-now <= 200); - // must throw an exception because 127.0.0.1 is in already banned suubnet range + // must throw an exception because 127.0.0.1 is in already banned subnet range BOOST_CHECK_THROW(r = CallRPC(std::string("setban 127.0.0.1 add")), std::runtime_error); BOOST_CHECK_NO_THROW(CallRPC(std::string("setban 127.0.0.0/24 remove"))); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 32184165f7..343c645cb1 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -32,7 +32,7 @@ // Uncomment if you want to output updated JSON tests. // #define UPDATE_JSON_TESTS -static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; +static const unsigned int gFlags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int ParseScriptFlags(std::string strFlags); std::string FormatScriptFlags(unsigned int flags); @@ -455,11 +455,6 @@ public: { return comment; } - - const CScript& GetScriptPubKey() - { - return creditTx->vout[0].scriptPubKey; - } }; std::string JSONPrettyPrint(const UniValue& univalue) @@ -1070,18 +1065,18 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), CScriptWitness(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, NULL, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, NULL, gFlags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } @@ -1103,54 +1098,54 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) std::vector<CKey> keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, NULL, gFlags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 2297644c0b..abaec45cd7 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -2,8 +2,6 @@ // 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 "test_bitcoin.h" #include "chainparams.h" @@ -27,10 +25,8 @@ #include <memory> #include <boost/filesystem.hpp> -#include <boost/test/unit_test.hpp> #include <boost/thread.hpp> -std::unique_ptr<CConnman> g_connman; FastRandomContext insecure_rand_ctx(true); extern bool fPrintToConsole; @@ -69,11 +65,14 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); - BOOST_REQUIRE(InitBlockIndex(chainparams)); + if (!InitBlockIndex(chainparams)) { + throw std::runtime_error("InitBlockIndex failed."); + } { CValidationState state; - bool ok = ActivateBestChain(state, chainparams); - BOOST_REQUIRE(ok); + if (!ActivateBestChain(state, chainparams)) { + throw std::runtime_error("ActivateBestChain failed."); + } } nScriptCheckThreads = 3; for (int i=0; i < nScriptCheckThreads-1; i++) @@ -150,18 +149,3 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) { return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight, spendsCoinbase, sigOpCost, lp); } - -void Shutdown(void* parg) -{ - exit(EXIT_SUCCESS); -} - -void StartShutdown() -{ - exit(EXIT_SUCCESS); -} - -bool ShutdownRequested() -{ - return false; -} diff --git a/src/test/test_bitcoin_main.cpp b/src/test/test_bitcoin_main.cpp new file mode 100644 index 0000000000..34beef5539 --- /dev/null +++ b/src/test/test_bitcoin_main.cpp @@ -0,0 +1,26 @@ +// Copyright (c) 2011-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#define BOOST_TEST_MODULE Bitcoin Test Suite + +#include "net.h" + +#include <boost/test/unit_test.hpp> + +std::unique_ptr<CConnman> g_connman; + +void Shutdown(void* parg) +{ + exit(EXIT_SUCCESS); +} + +void StartShutdown() +{ + exit(EXIT_SUCCESS); +} + +bool ShutdownRequested() +{ + return false; +} diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 641655621c..5da4907f06 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -247,7 +247,7 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) for (int mod=2;mod<11;mod++) { int mask = 1; - // Really rough binomal confidence approximation. + // Really rough binomial confidence approximation. int err = 30*10000./mod*sqrt((1./mod*(1-1./mod))/10000.); //mask is 2^ceil(log2(mod))-1 while(mask<mod-1)mask=(mask<<1)+1; @@ -321,7 +321,7 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32) BOOST_CHECK(ParseInt32("1234", &n) && n == 1234); BOOST_CHECK(ParseInt32("01234", &n) && n == 1234); // no octal BOOST_CHECK(ParseInt32("2147483647", &n) && n == 2147483647); - BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648); + BOOST_CHECK(ParseInt32("-2147483648", &n) && n == (-2147483647 - 1)); // (-2147483647 - 1) equals INT_MIN BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234); // Invalid values BOOST_CHECK(!ParseInt32("", &n)); diff --git a/src/tinyformat.h b/src/tinyformat.h index 17f0360c42..5022d46809 100644 --- a/src/tinyformat.h +++ b/src/tinyformat.h @@ -123,7 +123,7 @@ namespace tinyformat {} namespace tfm = tinyformat; // Error handling; calls assert() by default. -#define TINYFORMAT_ERROR(reasonString) throw std::runtime_error(reasonString) +#define TINYFORMAT_ERROR(reasonString) throw tinyformat::format_error(reasonString) // Define for C++11 variadic templates which make the code shorter & more // general. If you don't define this, C++11 support is autodetected below. @@ -164,6 +164,13 @@ namespace tfm = tinyformat; namespace tinyformat { +class format_error: public std::runtime_error +{ +public: + format_error(const std::string &what): std::runtime_error(what) { + } +}; + //------------------------------------------------------------------------------ namespace detail { diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index c49c5d9eb2..d24020e51f 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -662,26 +662,26 @@ void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg) } /****** Thread ********/ -struct event_base *base; -boost::thread torControlThread; +static struct event_base *gBase; +static boost::thread torControlThread; static void TorControlThread() { - TorController ctrl(base, GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); + TorController ctrl(gBase, GetArg("-torcontrol", DEFAULT_TOR_CONTROL)); - event_base_dispatch(base); + event_base_dispatch(gBase); } void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler) { - assert(!base); + assert(!gBase); #ifdef WIN32 evthread_use_windows_threads(); #else evthread_use_pthreads(); #endif - base = event_base_new(); - if (!base) { + gBase = event_base_new(); + if (!gBase) { LogPrintf("tor: Unable to create event_base\n"); return; } @@ -691,18 +691,18 @@ void StartTorControl(boost::thread_group& threadGroup, CScheduler& scheduler) void InterruptTorControl() { - if (base) { + if (gBase) { LogPrintf("tor: Thread interrupt\n"); - event_base_loopbreak(base); + event_base_loopbreak(gBase); } } void StopTorControl() { - if (base) { + if (gBase) { torControlThread.join(); - event_base_free(base); - base = 0; + event_base_free(gBase); + gBase = 0; } } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fb58208774..6e1d7a42b5 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -108,7 +108,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan // vHashesToUpdate is the set of transaction hashes from a disconnected block // which has been re-added to the mempool. -// for each entry, look for descendants that are outside hashesToUpdate, and +// for each entry, look for descendants that are outside vHashesToUpdate, and // add fee/size information for such descendants to the parent. // for each such descendant, also update the ancestor state to include the parent. void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate) diff --git a/src/txmempool.h b/src/txmempool.h index f9a9d088d0..4222789510 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -552,12 +552,12 @@ public: * new mempool entries may have children in the mempool (which is generally * not the case when otherwise adding transactions). * UpdateTransactionsFromBlock() will find child transactions and update the - * descendant state for each transaction in hashesToUpdate (excluding any - * child transactions present in hashesToUpdate, which are already accounted - * for). Note: hashesToUpdate should be the set of transactions from the + * descendant state for each transaction in vHashesToUpdate (excluding any + * child transactions present in vHashesToUpdate, which are already accounted + * for). Note: vHashesToUpdate should be the set of transactions from the * disconnected block that have been accepted back into the mempool. */ - void UpdateTransactionsFromBlock(const std::vector<uint256> &hashesToUpdate); + void UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate); /** Try to calculate all in-mempool ancestors of entry. * (these are all calculated including the tx itself) diff --git a/src/util.cpp b/src/util.cpp index 78c353dfe5..486df772fb 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -97,15 +97,15 @@ namespace boost { } // namespace boost -using namespace std; + const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf"; const char * const BITCOIN_PID_FILENAME = "bitcoind.pid"; CCriticalSection cs_args; -map<string, string> mapArgs; -static map<string, vector<string> > _mapMultiArgs; -const map<string, vector<string> >& mapMultiArgs = _mapMultiArgs; +std::map<std::string, std::string> mapArgs; +static std::map<std::string, std::vector<std::string> > _mapMultiArgs; +const std::map<std::string, std::vector<std::string> >& mapMultiArgs = _mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugLog = true; @@ -191,7 +191,7 @@ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; */ static FILE* fileout = NULL; static boost::mutex* mutexDebugLog = NULL; -static list<string> *vMsgsBeforeOpenLog; +static std::list<std::string>* vMsgsBeforeOpenLog; static int FileWriteStr(const std::string &str, FILE *fp) { @@ -202,7 +202,7 @@ static void DebugPrintInit() { assert(mutexDebugLog == NULL); mutexDebugLog = new boost::mutex(); - vMsgsBeforeOpenLog = new list<string>; + vMsgsBeforeOpenLog = new std::list<std::string>; } void OpenDebugLog() @@ -238,22 +238,22 @@ bool LogAcceptCategory(const char* category) // This helps prevent issues debugging global destructors, // where mapMultiArgs might be deleted before another // global destructor calls LogPrint() - static boost::thread_specific_ptr<set<string> > ptrCategory; + static boost::thread_specific_ptr<std::set<std::string> > ptrCategory; if (ptrCategory.get() == NULL) { if (mapMultiArgs.count("-debug")) { - const vector<string>& categories = mapMultiArgs.at("-debug"); - ptrCategory.reset(new set<string>(categories.begin(), categories.end())); + const std::vector<std::string>& categories = mapMultiArgs.at("-debug"); + ptrCategory.reset(new std::set<std::string>(categories.begin(), categories.end())); // thread_specific_ptr automatically deletes the set when the thread ends. } else - ptrCategory.reset(new set<string>()); + ptrCategory.reset(new std::set<std::string>()); } - const set<string>& setCategories = *ptrCategory.get(); + const std::set<std::string>& setCategories = *ptrCategory; // if not debugging everything and not debugging specific category, LogPrint does nothing. - if (setCategories.count(string("")) == 0 && - setCategories.count(string("1")) == 0 && - setCategories.count(string(category)) == 0) + if (setCategories.count(std::string("")) == 0 && + setCategories.count(std::string("1")) == 0 && + setCategories.count(std::string(category)) == 0) return false; } return true; @@ -266,7 +266,7 @@ bool LogAcceptCategory(const char* category) */ static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine) { - string strStamped; + std::string strStamped; if (!fLogTimestamps) return str; @@ -293,7 +293,7 @@ int LogPrintStr(const std::string &str) int ret = 0; // Returns total number of characters written static std::atomic_bool fStartedNewLine(true); - string strTimestamped = LogTimestampStr(str, &fStartedNewLine); + std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine); if (fPrintToConsole) { @@ -561,14 +561,14 @@ void ReadConfigFile(const std::string& confPath) { LOCK(cs_args); - set<string> setOptions; + std::set<std::string> setOptions; setOptions.insert("*"); for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { // Don't overwrite existing settings so command line settings override bitcoin.conf - string strKey = string("-") + it->string_key; - string strValue = it->value[0]; + std::string strKey = std::string("-") + it->string_key; + std::string strValue = it->value[0]; InterpretNegativeSetting(strKey, strValue); if (mapArgs.count(strKey) == 0) mapArgs[strKey] = strValue; @@ -839,4 +839,4 @@ std::string CopyrightHolders(const std::string& strPrefix) strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers"; } return strCopyrightHolders; -}
\ No newline at end of file +} diff --git a/src/util.h b/src/util.h index e27ce121c8..61dc0d366c 100644 --- a/src/util.h +++ b/src/util.h @@ -73,14 +73,24 @@ bool LogAcceptCategory(const char* category); /** Send a string to the log output */ int LogPrintStr(const std::string &str); -#define LogPrint(category, ...) do { \ - if (LogAcceptCategory((category))) { \ - LogPrintStr(tfm::format(__VA_ARGS__)); \ +/** Get format string from VA_ARGS for error reporting */ +template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } + +#define LogPrintf(...) do { \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(__VA_ARGS__); \ + } catch (tinyformat::format_error &fmterr) { \ + /* Original format string will have newline so don't add one here */ \ + _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \ } \ + LogPrintStr(_log_msg_); \ } while(0) -#define LogPrintf(...) do { \ - LogPrintStr(tfm::format(__VA_ARGS__)); \ +#define LogPrint(category, ...) do { \ + if (LogAcceptCategory((category))) { \ + LogPrintf(__VA_ARGS__); \ + } \ } while(0) template<typename... Args> diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index bebe56130d..6e6e33184e 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -9,8 +9,6 @@ #include "tinyformat.h" #include "utilstrencodings.h" -using namespace std; - std::string FormatMoney(const CAmount& n) { // Note: not using straight sprintf here because we do NOT want @@ -18,7 +16,7 @@ std::string FormatMoney(const CAmount& n) int64_t n_abs = (n > 0 ? n : -n); int64_t quotient = n_abs/COIN; int64_t remainder = n_abs%COIN; - string str = strprintf("%d.%08d", quotient, remainder); + std::string str = strprintf("%d.%08d", quotient, remainder); // Right-trim excess zeros before the decimal point: int nTrim = 0; @@ -33,14 +31,14 @@ std::string FormatMoney(const CAmount& n) } -bool ParseMoney(const string& str, CAmount& nRet) +bool ParseMoney(const std::string& str, CAmount& nRet) { return ParseMoney(str.c_str(), nRet); } bool ParseMoney(const char* pszIn, CAmount& nRet) { - string strWhole; + std::string strWhole; int64_t nUnits = 0; const char* p = pszIn; while (isspace(*p)) diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 29ae57940f..74bf66fbf6 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -12,20 +12,18 @@ #include <errno.h> #include <limits> -using namespace std; +static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; -static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - -static const string SAFE_CHARS[] = +static const std::string SAFE_CHARS[] = { CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME }; -string SanitizeString(const string& str, int rule) +std::string SanitizeString(const std::string& str, int rule) { - string strResult; + std::string strResult; for (std::string::size_type i = 0; i < str.size(); i++) { if (SAFE_CHARS[rule].find(str[i]) != std::string::npos) @@ -57,7 +55,7 @@ signed char HexDigit(char c) return p_util_hexdigit[(unsigned char)c]; } -bool IsHex(const string& str) +bool IsHex(const std::string& str) { for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) { @@ -67,10 +65,10 @@ bool IsHex(const string& str) return (str.size() > 0) && (str.size()%2 == 0); } -vector<unsigned char> ParseHex(const char* psz) +std::vector<unsigned char> ParseHex(const char* psz) { // convert hex dump to vector - vector<unsigned char> vch; + std::vector<unsigned char> vch; while (true) { while (isspace(*psz)) @@ -88,16 +86,16 @@ vector<unsigned char> ParseHex(const char* psz) return vch; } -vector<unsigned char> ParseHex(const string& str) +std::vector<unsigned char> ParseHex(const std::string& str) { return ParseHex(str.c_str()); } -string EncodeBase64(const unsigned char* pch, size_t len) +std::string EncodeBase64(const unsigned char* pch, size_t len) { static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - string strRet=""; + std::string strRet = ""; strRet.reserve((len+2)/3*4); int mode=0, left=0; @@ -139,12 +137,12 @@ string EncodeBase64(const unsigned char* pch, size_t len) return strRet; } -string EncodeBase64(const string& str) +std::string EncodeBase64(const std::string& str) { return EncodeBase64((const unsigned char*)str.c_str(), str.size()); } -vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) +std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) { static const int decode64_table[256] = { @@ -166,7 +164,7 @@ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) if (pfInvalid) *pfInvalid = false; - vector<unsigned char> vchRet; + std::vector<unsigned char> vchRet; vchRet.reserve(strlen(p)*3/4); int mode = 0; @@ -227,17 +225,17 @@ vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid) return vchRet; } -string DecodeBase64(const string& str) +std::string DecodeBase64(const std::string& str) { - vector<unsigned char> vchRet = DecodeBase64(str.c_str()); - return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); + std::vector<unsigned char> vchRet = DecodeBase64(str.c_str()); + return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size()); } -string EncodeBase32(const unsigned char* pch, size_t len) +std::string EncodeBase32(const unsigned char* pch, size_t len) { static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; - string strRet=""; + std::string strRet=""; strRet.reserve((len+4)/5*8); int mode=0, left=0; @@ -292,12 +290,12 @@ string EncodeBase32(const unsigned char* pch, size_t len) return strRet; } -string EncodeBase32(const string& str) +std::string EncodeBase32(const std::string& str) { return EncodeBase32((const unsigned char*)str.c_str(), str.size()); } -vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) +std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) { static const int decode32_table[256] = { @@ -319,7 +317,7 @@ vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) if (pfInvalid) *pfInvalid = false; - vector<unsigned char> vchRet; + std::vector<unsigned char> vchRet; vchRet.reserve((strlen(p))*5/8); int mode = 0; @@ -414,10 +412,10 @@ vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) return vchRet; } -string DecodeBase32(const string& str) +std::string DecodeBase32(const std::string& str) { - vector<unsigned char> vchRet = DecodeBase32(str.c_str()); - return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size()); + std::vector<unsigned char> vchRet = DecodeBase32(str.c_str()); + return (vchRet.size() == 0) ? std::string() : std::string((const char*)&vchRet[0], vchRet.size()); } static bool ParsePrechecks(const std::string& str) diff --git a/src/utiltime.cpp b/src/utiltime.cpp index c7b3e4f168..a9936a645a 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -12,8 +12,6 @@ #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/thread.hpp> -using namespace std; - static int64_t nMockTime = 0; //!< For unit testing int64_t GetTime() diff --git a/src/validation.cpp b/src/validation.cpp index 63918a3f30..037b9c0abc 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1714,7 +1714,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck) { AssertLockHeld(cs_main); - + assert(pindex); + // pindex->phashBlock can be null if called by CreateNewBlock/TestBlockValidity + assert((pindex->phashBlock == NULL) || + (*pindex->phashBlock == block.GetHash())); int64_t nTimeStart = GetTimeMicros(); // Check it again in case a previous version let a bad block in @@ -2948,7 +2951,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) { - const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; + assert(pindexPrev != NULL); + const int nHeight = pindexPrev->nHeight + 1; // Check proof of work if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work"); @@ -3148,7 +3152,7 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); // TODO: Decouple this function from the block download logic by removing fRequested - // This requires some new chain datastructure to efficiently look up if a + // This requires some new chain data structure to efficiently look up if a // block is in a chain leading to a candidate for best tip, despite not // being such a candidate itself. diff --git a/src/validation.h b/src/validation.h index 43f0dbae34..5f8e9a689c 100644 --- a/src/validation.h +++ b/src/validation.h @@ -314,7 +314,7 @@ void FlushStateToDisk(); /** Prune block files and flush state to disk. */ void PruneAndFlush(); /** Prune block files up to a given height */ -void PruneBlockFilesManual(int nPruneUpToHeight); +void PruneBlockFilesManual(int nManualPruneHeight); /** (try to) add transaction to memory pool * plTxnReplaced will be appended to with all transactions replaced from mempool **/ diff --git a/src/validationinterface.h b/src/validationinterface.h index a494eb6990..7f13a29d23 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -69,7 +69,12 @@ struct CMainSignals { boost::signals2::signal<void (const uint256 &)> Inventory; /** Tells listeners to broadcast their data. */ boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast; - /** Notifies listeners of a block validation result */ + /** + * Notifies listeners of a block validation result. + * If the provided CValidationState IsValid, the provided block + * is guaranteed to be the current best block at the time the + * callback was generated (not necessarily now) + */ boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; /** Notifies listeners that a key for mining is required (coinbase) */ boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining; diff --git a/src/versionbits.cpp b/src/versionbits.cpp index d73f340510..8a7cce7485 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -17,7 +17,7 @@ const struct BIP9DeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION }, { /*.name =*/ "segwit", - /*.gbt_force =*/ false, + /*.gbt_force =*/ true, } }; diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index eaf4ff8062..4e93e929be 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -6,6 +6,7 @@ #define BITCOIN_WALLET_COINCONTROL_H #include "primitives/transaction.h" +#include "wallet/wallet.h" /** Coin Control Features. */ class CCoinControl @@ -24,6 +25,8 @@ public: CFeeRate nFeeRate; //! Override the default confirmation target, 0 = use default int nConfirmTarget; + //! Signal BIP-125 replace by fee. + bool signalRbf; CCoinControl() { @@ -40,6 +43,7 @@ public: nFeeRate = CFeeRate(0); fOverrideFeeRate = false; nConfirmTarget = 0; + signalRbf = fWalletRbf; } bool HasSelected() const diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 74d87f9d15..0801bd7300 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -22,9 +22,6 @@ #include <boost/thread.hpp> #include <boost/version.hpp> -using namespace std; - - // // CDB // @@ -117,7 +114,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) void CDBEnv::MakeMock() { if (fDbEnvInit) - throw runtime_error("CDBEnv::MakeMock: Already initialized"); + throw std::runtime_error("CDBEnv::MakeMock: Already initialized"); boost::this_thread::interruption_point(); @@ -140,7 +137,7 @@ void CDBEnv::MakeMock() DB_PRIVATE, S_IRUSR | S_IWUSR); if (ret > 0) - throw runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret)); + throw std::runtime_error(strprintf("CDBEnv::MakeMock: Error %d opening database environment.", ret)); fDbEnvInit = true; fMockDb = true; @@ -214,7 +211,7 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco { CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION); CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION); - string strType, strErr; + std::string strType, strErr; if (!(*recoverKVcallback)(callbackDataIn, ssKey, ssValue)) continue; } @@ -301,7 +298,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C if (fAggressive) flags |= DB_AGGRESSIVE; - stringstream strDump; + std::stringstream strDump; Db db(dbenv, 0); int result = db.verify(strFile.c_str(), NULL, &strDump, flags); @@ -325,7 +322,7 @@ bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<C // ... repeated // DATA=END - string strLine; + std::string strLine; while (!strDump.eof() && strLine != HEADER_END) getline(strDump, strLine); // Skip past header @@ -378,7 +375,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose { LOCK(bitdb.cs_db); if (!bitdb.Open(GetDataDir())) - throw runtime_error("CDB: Failed to open database environment."); + throw std::runtime_error("CDB: Failed to open database environment."); strFile = strFilename; ++bitdb.mapFileUseCount[strFile]; @@ -391,7 +388,7 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose DbMpoolFile* mpf = pdb->get_mpf(); ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); if (ret != 0) - throw runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile)); + throw std::runtime_error(strprintf("CDB: Failed to configure for no temp file backing for database %s", strFile)); } ret = pdb->open(NULL, // Txn pointer @@ -406,10 +403,10 @@ CDB::CDB(const std::string& strFilename, const char* pszMode, bool fFlushOnClose pdb = NULL; --bitdb.mapFileUseCount[strFile]; strFile = ""; - throw runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); + throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); } - if (fCreate && !Exists(string("version"))) { + if (fCreate && !Exists(std::string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; WriteVersion(CLIENT_VERSION); @@ -452,7 +449,7 @@ void CDB::Close() } } -void CDBEnv::CloseDb(const string& strFile) +void CDBEnv::CloseDb(const std::string& strFile) { { LOCK(cs_db); @@ -466,7 +463,7 @@ void CDBEnv::CloseDb(const string& strFile) } } -bool CDBEnv::RemoveDb(const string& strFile) +bool CDBEnv::RemoveDb(const std::string& strFile) { this->CloseDb(strFile); @@ -475,7 +472,7 @@ bool CDBEnv::RemoveDb(const string& strFile) return (rc == 0); } -bool CDB::Rewrite(const string& strFile, const char* pszSkip) +bool CDB::Rewrite(const std::string& strFile, const char* pszSkip) { while (true) { { @@ -488,7 +485,7 @@ bool CDB::Rewrite(const string& strFile, const char* pszSkip) bool fSuccess = true; LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); - string strFileRes = strFile + ".rewrite"; + std::string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); Db* pdbCopy = new Db(bitdb.dbenv, 0); @@ -568,9 +565,9 @@ void CDBEnv::Flush(bool fShutdown) return; { LOCK(cs_db); - map<string, int>::iterator mi = mapFileUseCount.begin(); + std::map<std::string, int>::iterator mi = mapFileUseCount.begin(); while (mi != mapFileUseCount.end()) { - string strFile = (*mi).first; + std::string strFile = (*mi).first; int nRefCount = (*mi).second; LogPrint("db", "CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); if (nRefCount == 0) { @@ -607,17 +604,17 @@ bool CDB::PeriodicFlush(std::string strFile) { // Don't do this if any databases are in use int nRefCount = 0; - map<string, int>::iterator mi = bitdb.mapFileUseCount.begin(); - while (mi != bitdb.mapFileUseCount.end()) + std::map<std::string, int>::iterator mit = bitdb.mapFileUseCount.begin(); + while (mit != bitdb.mapFileUseCount.end()) { - nRefCount += (*mi).second; - mi++; + nRefCount += (*mit).second; + mit++; } if (nRefCount == 0) { boost::this_thread::interruption_point(); - map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile); + std::map<std::string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile); if (mi != bitdb.mapFileUseCount.end()) { LogPrint("db", "Flushing %s\n", strFile); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index e02c6513e4..7ff9e7ae58 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -29,8 +29,6 @@ #include <boost/assign/list_of.hpp> #include <boost/foreach.hpp> -using namespace std; - std::string static EncodeDumpTime(int64_t nTime) { return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); } @@ -82,7 +80,7 @@ UniValue importprivkey(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n" "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" "\nArguments:\n" @@ -106,8 +104,8 @@ UniValue importprivkey(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - string strSecret = request.params[0].get_str(); - string strLabel = ""; + std::string strSecret = request.params[0].get_str(); + std::string strLabel = ""; if (request.params.size() > 1) strLabel = request.params[1].get_str(); @@ -156,8 +154,8 @@ UniValue importprivkey(const JSONRPCRequest& request) return NullUniValue; } -void ImportAddress(CWallet*, const CBitcoinAddress& address, const string& strLabel); -void ImportScript(CWallet * const pwallet, const CScript& script, const string& strLabel, bool isRedeemScript) +void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel); +void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) { if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); @@ -182,7 +180,7 @@ void ImportScript(CWallet * const pwallet, const CScript& script, const string& } } -void ImportAddress(CWallet * const pwallet, const CBitcoinAddress& address, const string& strLabel) +void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel) { CScript script = GetScriptForDestination(address.Get()); ImportScript(pwallet, script, strLabel, false); @@ -199,7 +197,7 @@ UniValue importaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "importaddress \"address\" ( \"label\" rescan p2sh )\n" "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" @@ -221,7 +219,7 @@ UniValue importaddress(const JSONRPCRequest& request) ); - string strLabel = ""; + std::string strLabel = ""; if (request.params.size() > 1) strLabel = request.params[1].get_str(); @@ -269,7 +267,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 2) - throw runtime_error( + throw std::runtime_error( "importprunedfunds\n" "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n" "\nArguments:\n" @@ -288,8 +286,8 @@ UniValue importprunedfunds(const JSONRPCRequest& request) ssMB >> merkleBlock; //Search partial merkle tree in proof for our transaction and index in valid block - vector<uint256> vMatch; - vector<unsigned int> vIndex; + std::vector<uint256> vMatch; + std::vector<unsigned int> vIndex; unsigned int txnIndex = 0; if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) { @@ -298,7 +296,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request) if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); - vector<uint256>::const_iterator it; + std::vector<uint256>::const_iterator it; if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof"); } @@ -330,7 +328,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "removeprunedfunds \"txid\"\n" "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n" "\nArguments:\n" @@ -345,16 +343,16 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) uint256 hash; hash.SetHex(request.params[0].get_str()); - vector<uint256> vHash; + std::vector<uint256> vHash; vHash.push_back(hash); - vector<uint256> vHashOut; + std::vector<uint256> vHashOut; if (pwallet->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction."); + throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction."); } if(vHashOut.empty()) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet."); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet."); } return NullUniValue; @@ -368,7 +366,7 @@ UniValue importpubkey(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "importpubkey \"pubkey\" ( \"label\" rescan )\n" "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" @@ -386,7 +384,7 @@ UniValue importpubkey(const JSONRPCRequest& request) ); - string strLabel = ""; + std::string strLabel = ""; if (request.params.size() > 1) strLabel = request.params[1].get_str(); @@ -428,7 +426,7 @@ UniValue importwallet(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "importwallet \"filename\"\n" "\nImports keys from a wallet dump file (see dumpwallet).\n" "\nArguments:\n" @@ -449,7 +447,7 @@ UniValue importwallet(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - ifstream file; + std::ifstream file; file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -536,7 +534,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpprivkey \"address\"\n" "\nReveals the private key corresponding to 'address'.\n" "Then the importprivkey can be used with this output\n" @@ -554,7 +552,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - string strAddress = request.params[0].get_str(); + std::string strAddress = request.params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); @@ -577,7 +575,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpwallet \"filename\"\n" "\nDumps all wallet keys in a human-readable format.\n" "\nArguments:\n" @@ -591,7 +589,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - ofstream file; + std::ofstream file; file.open(request.params[0].get_str().c_str()); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -675,16 +673,16 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 } // Optional fields. - const string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : ""; + const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : ""; const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue(); const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false; const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false; - const string& label = data.exists("label") && !internal ? data["label"].get_str() : ""; + const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : ""; bool isScript = scriptPubKey.getType() == UniValue::VSTR; bool isP2SH = strRedeemScript.length() > 0; - const string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str(); + const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str(); // Parse the output. CScript script; @@ -745,7 +743,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 pwallet->MarkDirty(); - if (!pwallet->HaveWatchOnly(redeemScript) && !pwallet->AddWatchOnly(redeemScript, timestamp)) { + if (!pwallet->AddWatchOnly(redeemScript, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } @@ -762,7 +760,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 pwallet->MarkDirty(); - if (!pwallet->HaveWatchOnly(redeemDestination) && !pwallet->AddWatchOnly(redeemDestination, timestamp)) { + if (!pwallet->AddWatchOnly(redeemDestination, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } @@ -774,7 +772,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 // Import private keys. if (keys.size()) { for (size_t i = 0; i < keys.size(); i++) { - const string& privkey = keys[i].get_str(); + const std::string& privkey = keys[i].get_str(); CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(privkey); @@ -814,7 +812,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 } else { // Import public keys. if (pubKeys.size() && keys.size() == 0) { - const string& strPubKey = pubKeys[0].get_str(); + const std::string& strPubKey = pubKeys[0].get_str(); if (!IsHex(strPubKey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string"); @@ -855,7 +853,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 pwallet->MarkDirty(); - if (!pwallet->HaveWatchOnly(pubKeyScript) && !pwallet->AddWatchOnly(pubKeyScript, timestamp)) { + if (!pwallet->AddWatchOnly(pubKeyScript, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } @@ -873,7 +871,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 pwallet->MarkDirty(); - if (!pwallet->HaveWatchOnly(scriptRawPubKey) && !pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) { + if (!pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } @@ -882,7 +880,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 // Import private keys. if (keys.size()) { - const string& strPrivkey = keys[0].get_str(); + const std::string& strPrivkey = keys[0].get_str(); // Checks. CBitcoinSecret vchSecret; @@ -947,7 +945,7 @@ UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int6 pwallet->MarkDirty(); - if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, timestamp)) { + if (!pwallet->AddWatchOnly(script, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } @@ -1001,7 +999,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) // clang-format off if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "importmulti \"requests\" \"options\"\n\n" "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n" "Arguments:\n" diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5ef93ac532..22b1e3522c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -27,8 +27,6 @@ #include <univalue.h> -using namespace std; - CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request) { return pwalletMain; @@ -94,13 +92,13 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) } entry.push_back(Pair("bip125-replaceable", rbfStatus)); - BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) + BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } -string AccountFromValue(const UniValue& value) +std::string AccountFromValue(const UniValue& value) { - string strAccount = value.get_str(); + std::string strAccount = value.get_str(); if (strAccount == "*") throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name"); return strAccount; @@ -114,7 +112,7 @@ UniValue getnewaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getnewaddress ( \"account\" )\n" "\nReturns a new Bitcoin address for receiving payments.\n" "If 'account' is specified (DEPRECATED), it is added to the address book \n" @@ -131,7 +129,7 @@ UniValue getnewaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); // Parse the account first so we don't generate a key if there's an error - string strAccount; + std::string strAccount; if (request.params.size() > 0) strAccount = AccountFromValue(request.params[0]); @@ -152,7 +150,7 @@ UniValue getnewaddress(const JSONRPCRequest& request) } -CBitcoinAddress GetAccountAddress(CWallet * const pwallet, string strAccount, bool bForceNew=false) +CBitcoinAddress GetAccountAddress(CWallet* const pwallet, std::string strAccount, bool bForceNew=false) { CPubKey pubKey; if (!pwallet->GetAccountPubkey(pubKey, strAccount, bForceNew)) { @@ -170,7 +168,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getaccountaddress \"account\"\n" "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n" "\nArguments:\n" @@ -187,7 +185,7 @@ UniValue getaccountaddress(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); // Parse the account first so we don't generate a key if there's an error - string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = AccountFromValue(request.params[0]); UniValue ret(UniValue::VSTR); @@ -204,7 +202,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "getrawchangeaddress\n" "\nReturns a new Bitcoin address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n" @@ -223,7 +221,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) CReserveKey reservekey(pwallet); CPubKey vchPubKey; - if (!reservekey.GetReservedKey(vchPubKey)) + if (!reservekey.GetReservedKey(vchPubKey, true)) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); reservekey.KeepKey(); @@ -242,7 +240,7 @@ UniValue setaccount(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "setaccount \"address\" \"account\"\n" "\nDEPRECATED. Sets the account associated with the given address.\n" "\nArguments:\n" @@ -259,7 +257,7 @@ UniValue setaccount(const JSONRPCRequest& request) if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - string strAccount; + std::string strAccount; if (request.params.size() > 1) strAccount = AccountFromValue(request.params[1]); @@ -267,7 +265,7 @@ UniValue setaccount(const JSONRPCRequest& request) if (IsMine(*pwallet, address.Get())) { // Detect when changing the account of an address that is the 'unused current key' of another account: if (pwallet->mapAddressBook.count(address.Get())) { - string strOldAccount = pwallet->mapAddressBook[address.Get()].name; + std::string strOldAccount = pwallet->mapAddressBook[address.Get()].name; if (address == GetAccountAddress(pwallet, strOldAccount)) { GetAccountAddress(pwallet, strOldAccount, true); } @@ -289,7 +287,7 @@ UniValue getaccount(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getaccount \"address\"\n" "\nDEPRECATED. Returns the account associated with the given address.\n" "\nArguments:\n" @@ -307,8 +305,8 @@ UniValue getaccount(const JSONRPCRequest& request) if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - string strAccount; - map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get()); + std::string strAccount; + std::map<CTxDestination, CAddressBookData>::iterator mi = pwallet->mapAddressBook.find(address.Get()); if (mi != pwallet->mapAddressBook.end() && !(*mi).second.name.empty()) { strAccount = (*mi).second.name; } @@ -324,7 +322,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "getaddressesbyaccount \"account\"\n" "\nDEPRECATED. Returns the list of addresses for the given account.\n" "\nArguments:\n" @@ -341,13 +339,13 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = AccountFromValue(request.params[0]); // Find all addresses that have the given account UniValue ret(UniValue::VARR); for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) { const CBitcoinAddress& address = item.first; - const string& strName = item.second.name; + const std::string& strName = item.second.name; if (strName == strAccount) ret.push_back(address.ToString()); } @@ -376,7 +374,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA CReserveKey reservekey(pwallet); CAmount nFeeRequired; std::string strError; - vector<CRecipient> vecSend; + std::vector<CRecipient> vecSend; int nChangePosRet = -1; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); @@ -400,7 +398,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) - throw runtime_error( + throw std::runtime_error( "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n" "\nSend an amount to a given address.\n" + HelpRequiringPassphrase(pwallet) + @@ -460,7 +458,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) } if (request.fHelp) - throw runtime_error( + throw std::runtime_error( "listaddressgroupings\n" "\nLists groups of addresses which have had their common ownership\n" "made public by common use as inputs or as the resulting change\n" @@ -485,8 +483,8 @@ UniValue listaddressgroupings(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); UniValue jsonGroupings(UniValue::VARR); - map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(); - for (set<CTxDestination> grouping : pwallet->GetAddressGroupings()) { + std::map<CTxDestination, CAmount> balances = pwallet->GetAddressBalances(); + for (std::set<CTxDestination> grouping : pwallet->GetAddressGroupings()) { UniValue jsonGrouping(UniValue::VARR); BOOST_FOREACH(CTxDestination address, grouping) { @@ -513,7 +511,7 @@ UniValue signmessage(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 2) - throw runtime_error( + throw std::runtime_error( "signmessage \"address\" \"message\"\n" "\nSign a message with the private key of an address" + HelpRequiringPassphrase(pwallet) + "\n" @@ -537,8 +535,8 @@ UniValue signmessage(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - string strAddress = request.params[0].get_str(); - string strMessage = request.params[1].get_str(); + std::string strAddress = request.params[0].get_str(); + std::string strMessage = request.params[1].get_str(); CBitcoinAddress addr(strAddress); if (!addr.IsValid()) @@ -557,7 +555,7 @@ UniValue signmessage(const JSONRPCRequest& request) ss << strMessageMagic; ss << strMessage; - vector<unsigned char> vchSig; + std::vector<unsigned char> vchSig; if (!key.SignCompact(ss.GetHash(), vchSig)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); @@ -572,7 +570,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getreceivedbyaddress \"address\" ( minconf )\n" "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n" "\nArguments:\n" @@ -632,7 +630,7 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "getreceivedbyaccount \"account\" ( minconf )\n" "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n" "\nArguments:\n" @@ -659,8 +657,8 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request) nMinDepth = request.params[1].get_int(); // Get the set of pub keys assigned to account - string strAccount = AccountFromValue(request.params[0]); - set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount); + std::string strAccount = AccountFromValue(request.params[0]); + std::set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount); // Tally CAmount nAmount = 0; @@ -691,7 +689,7 @@ UniValue getbalance(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "getbalance ( \"account\" minconf include_watchonly )\n" "\nIf account is not specified, returns the server's total available balance.\n" "If account is specified (DEPRECATED), returns the balance in the account.\n" @@ -750,9 +748,9 @@ UniValue getbalance(const JSONRPCRequest& request) continue; CAmount allFee; - string strSentAccount; - list<COutputEntry> listReceived; - list<COutputEntry> listSent; + std::string strSentAccount; + std::list<COutputEntry> listReceived; + std::list<COutputEntry> listSent; wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (wtx.GetDepthInMainChain() >= nMinDepth) { @@ -766,7 +764,7 @@ UniValue getbalance(const JSONRPCRequest& request) return ValueFromAmount(nBalance); } - string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = AccountFromValue(request.params[0]); CAmount nBalance = pwallet->GetAccountBalance(strAccount, nMinDepth, filter); @@ -781,7 +779,7 @@ UniValue getunconfirmedbalance(const JSONRPCRequest &request) } if (request.fHelp || request.params.size() > 0) - throw runtime_error( + throw std::runtime_error( "getunconfirmedbalance\n" "Returns the server's total unconfirmed balance\n"); @@ -799,7 +797,7 @@ UniValue movecmd(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 3 || request.params.size() > 5) - throw runtime_error( + throw std::runtime_error( "move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n" "\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n" "\nArguments:\n" @@ -821,15 +819,15 @@ UniValue movecmd(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - string strFrom = AccountFromValue(request.params[0]); - string strTo = AccountFromValue(request.params[1]); + std::string strFrom = AccountFromValue(request.params[0]); + std::string strTo = AccountFromValue(request.params[1]); CAmount nAmount = AmountFromValue(request.params[2]); if (nAmount <= 0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send"); if (request.params.size() > 3) // unused parameter, used to be nMinDepth, keep type-checking it though (void)request.params[3].get_int(); - string strComment; + std::string strComment; if (request.params.size() > 4) strComment = request.params[4].get_str(); @@ -849,7 +847,7 @@ UniValue sendfrom(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 3 || request.params.size() > 6) - throw runtime_error( + throw std::runtime_error( "sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n" "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address." + HelpRequiringPassphrase(pwallet) + "\n" @@ -879,7 +877,7 @@ UniValue sendfrom(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = AccountFromValue(request.params[0]); CBitcoinAddress address(request.params[1].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); @@ -918,7 +916,7 @@ UniValue sendmany(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) - throw runtime_error( + throw std::runtime_error( "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n" "\nSend multiple times. Amounts are double-precision floating point numbers." + HelpRequiringPassphrase(pwallet) + "\n" @@ -959,7 +957,7 @@ UniValue sendmany(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - string strAccount = AccountFromValue(request.params[0]); + std::string strAccount = AccountFromValue(request.params[0]); UniValue sendTo = request.params[1].get_obj(); int nMinDepth = 1; if (request.params.size() > 2) @@ -974,19 +972,19 @@ UniValue sendmany(const JSONRPCRequest& request) if (request.params.size() > 4) subtractFeeFromAmount = request.params[4].get_array(); - set<CBitcoinAddress> setAddress; - vector<CRecipient> vecSend; + std::set<CBitcoinAddress> setAddress; + std::vector<CRecipient> vecSend; CAmount totalAmount = 0; - vector<string> keys = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, keys) + std::vector<std::string> keys = sendTo.getKeys(); + BOOST_FOREACH(const std::string& name_, keys) { CBitcoinAddress address(name_); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+name_); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+name_); setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); @@ -1017,7 +1015,7 @@ UniValue sendmany(const JSONRPCRequest& request) CReserveKey keyChange(pwallet); CAmount nFeeRequired = 0; int nChangePosRet = -1; - string strFailReason; + std::string strFailReason; bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); @@ -1042,7 +1040,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) { - string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" + std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n" "\nAdd a nrequired-to-sign multisignature address to the wallet.\n" "Each key is a Bitcoin address or hex-encoded public key.\n" "If 'account' is specified (DEPRECATED), assign address to that account.\n" @@ -1065,12 +1063,12 @@ UniValue addmultisigaddress(const JSONRPCRequest& request) "\nAs json rpc call\n" + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") ; - throw runtime_error(msg); + throw std::runtime_error(msg); } LOCK2(cs_main, pwallet->cs_wallet); - string strAccount; + std::string strAccount; if (request.params.size() > 2) strAccount = AccountFromValue(request.params[2]); @@ -1140,7 +1138,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) { - string msg = "addwitnessaddress \"address\"\n" + std::string msg = "addwitnessaddress \"address\"\n" "\nAdd a witness address for a script (with pubkey or redeemscript known).\n" "It returns the witness script.\n" @@ -1151,7 +1149,7 @@ UniValue addwitnessaddress(const JSONRPCRequest& request) "\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n" "}\n" ; - throw runtime_error(msg); + throw std::runtime_error(msg); } { @@ -1181,7 +1179,7 @@ struct tallyitem { CAmount nAmount; int nConf; - vector<uint256> txids; + std::vector<uint256> txids; bool fIsWatchonly; tallyitem() { @@ -1209,7 +1207,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA filter = filter | ISMINE_WATCH_ONLY; // Tally - map<CBitcoinAddress, tallyitem> mapTally; + std::map<CBitcoinAddress, tallyitem> mapTally; for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { const CWalletTx& wtx = pairWtx.second; @@ -1232,7 +1230,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA tallyitem& item = mapTally[address]; item.nAmount += txout.nValue; - item.nConf = min(item.nConf, nDepth); + item.nConf = std::min(item.nConf, nDepth); item.txids.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) item.fIsWatchonly = true; @@ -1241,11 +1239,11 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA // Reply UniValue ret(UniValue::VARR); - map<string, tallyitem> mapAccountTally; + std::map<std::string, tallyitem> mapAccountTally; for (const std::pair<CBitcoinAddress, CAddressBookData>& item : pwallet->mapAddressBook) { const CBitcoinAddress& address = item.first; - const string& strAccount = item.second.name; - map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address); + const std::string& strAccount = item.second.name; + std::map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address); if (it == mapTally.end() && !fIncludeEmpty) continue; @@ -1263,7 +1261,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA { tallyitem& _item = mapAccountTally[strAccount]; _item.nAmount += nAmount; - _item.nConf = min(_item.nConf, nConf); + _item.nConf = std::min(_item.nConf, nConf); _item.fIsWatchonly = fIsWatchonly; } else @@ -1292,7 +1290,7 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA if (fByAccounts) { - for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) + for (std::map<std::string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { CAmount nAmount = (*it).second.nAmount; int nConf = (*it).second.nConf; @@ -1317,7 +1315,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "listreceivedbyaddress ( minconf include_empty include_watchonly)\n" "\nList balances by receiving address.\n" "\nArguments:\n" @@ -1361,7 +1359,7 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "listreceivedbyaccount ( minconf include_empty include_watchonly)\n" "\nDEPRECATED. List balances by account.\n" "\nArguments:\n" @@ -1399,16 +1397,16 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest) entry.push_back(Pair("address", addr.ToString())); } -void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) +void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) { CAmount nFee; - string strSentAccount; - list<COutputEntry> listReceived; - list<COutputEntry> listSent; + std::string strSentAccount; + std::list<COutputEntry> listReceived; + std::list<COutputEntry> listSent; wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount, filter); - bool fAllAccounts = (strAccount == string("*")); + bool fAllAccounts = (strAccount == std::string("*")); bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY); // Sent @@ -1441,7 +1439,7 @@ void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const strin { BOOST_FOREACH(const COutputEntry& r, listReceived) { - string account; + std::string account; if (pwallet->mapAddressBook.count(r.destination)) { account = pwallet->mapAddressBook[r.destination].name; } @@ -1479,9 +1477,9 @@ void ListTransactions(CWallet * const pwallet, const CWalletTx& wtx, const strin } } -void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret) +void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccount, UniValue& ret) { - bool fAllAccounts = (strAccount == string("*")); + bool fAllAccounts = (strAccount == std::string("*")); if (fAllAccounts || acentry.strAccount == strAccount) { @@ -1504,7 +1502,7 @@ UniValue listtransactions(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "listtransactions ( \"account\" count skip include_watchonly)\n" "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n" "\nArguments:\n" @@ -1565,7 +1563,7 @@ UniValue listtransactions(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - string strAccount = "*"; + std::string strAccount = "*"; if (request.params.size() > 0) strAccount = request.params[0].get_str(); int nCount = 10; @@ -1607,11 +1605,11 @@ UniValue listtransactions(const JSONRPCRequest& request) if ((nFrom + nCount) > (int)ret.size()) nCount = ret.size() - nFrom; - vector<UniValue> arrTmp = ret.getValues(); + std::vector<UniValue> arrTmp = ret.getValues(); - vector<UniValue>::iterator first = arrTmp.begin(); + std::vector<UniValue>::iterator first = arrTmp.begin(); std::advance(first, nFrom); - vector<UniValue>::iterator last = arrTmp.begin(); + std::vector<UniValue>::iterator last = arrTmp.begin(); std::advance(last, nFrom+nCount); if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); @@ -1634,7 +1632,7 @@ UniValue listaccounts(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "listaccounts ( minconf include_watchonly)\n" "\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n" "\nArguments:\n" @@ -1666,7 +1664,7 @@ UniValue listaccounts(const JSONRPCRequest& request) if(request.params[1].get_bool()) includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; - map<string, CAmount> mapAccountBalances; + std::map<std::string, CAmount> mapAccountBalances; for (const std::pair<CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) { if (IsMine(*pwallet, entry.first) & includeWatchonly) { // This address belongs to me mapAccountBalances[entry.second.name] = 0; @@ -1676,9 +1674,9 @@ UniValue listaccounts(const JSONRPCRequest& request) for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) { const CWalletTx& wtx = pairWtx.second; CAmount nFee; - string strSentAccount; - list<COutputEntry> listReceived; - list<COutputEntry> listSent; + std::string strSentAccount; + std::list<COutputEntry> listReceived; + std::list<COutputEntry> listSent; int nDepth = wtx.GetDepthInMainChain(); if (wtx.GetBlocksToMaturity() > 0 || nDepth < 0) continue; @@ -1697,12 +1695,12 @@ UniValue listaccounts(const JSONRPCRequest& request) } } - const list<CAccountingEntry> & acentries = pwallet->laccentries; + const std::list<CAccountingEntry>& acentries = pwallet->laccentries; BOOST_FOREACH(const CAccountingEntry& entry, acentries) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; UniValue ret(UniValue::VOBJ); - BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) { + BOOST_FOREACH(const PAIRTYPE(std::string, CAmount)& accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; @@ -1716,7 +1714,7 @@ UniValue listsinceblock(const JSONRPCRequest& request) } if (request.fHelp) - throw runtime_error( + throw std::runtime_error( "listsinceblock ( \"blockhash\" target_confirmations include_watchonly)\n" "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n" "\nArguments:\n" @@ -1823,7 +1821,7 @@ UniValue gettransaction(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "gettransaction \"txid\" ( include_watchonly )\n" "\nGet detailed information about in-wallet transaction <txid>\n" "\nArguments:\n" @@ -1854,7 +1852,7 @@ UniValue gettransaction(const JSONRPCRequest& request) " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n" " 'send' category of transactions.\n" " \"abandoned\": xxx (bool) 'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n" - " 'send' category of transactions.\n" + " 'send' category of transactions.\n" " }\n" " ,...\n" " ],\n" @@ -1898,7 +1896,7 @@ UniValue gettransaction(const JSONRPCRequest& request) ListTransactions(pwallet, wtx, "*", 0, false, details, filter); entry.push_back(Pair("details", details)); - string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags()); + std::string strHex = EncodeHexTx(static_cast<CTransaction>(wtx), RPCSerializationFlags()); entry.push_back(Pair("hex", strHex)); return entry; @@ -1912,7 +1910,7 @@ UniValue abandontransaction(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "abandontransaction \"txid\"\n" "\nMark in-wallet transaction <txid> as abandoned\n" "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n" @@ -1951,7 +1949,7 @@ UniValue backupwallet(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "backupwallet \"destination\"\n" "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n" "\nArguments:\n" @@ -1963,7 +1961,7 @@ UniValue backupwallet(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - string strDest = request.params[0].get_str(); + std::string strDest = request.params[0].get_str(); if (!pwallet->BackupWallet(strDest)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!"); } @@ -1980,7 +1978,7 @@ UniValue keypoolrefill(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "keypoolrefill ( newsize )\n" "\nFills the keypool." + HelpRequiringPassphrase(pwallet) + "\n" @@ -2027,7 +2025,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request) } if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) { - throw runtime_error( + throw std::runtime_error( "walletpassphrase \"passphrase\" timeout\n" "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" "This is needed prior to performing transactions related to private keys such as sending bitcoins\n" @@ -2069,7 +2067,7 @@ UniValue walletpassphrase(const JSONRPCRequest& request) } } else - throw runtime_error( + throw std::runtime_error( "walletpassphrase <passphrase> <timeout>\n" "Stores the wallet decryption key in memory for <timeout> seconds."); @@ -2091,7 +2089,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request) } if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 2)) { - throw runtime_error( + throw std::runtime_error( "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n" "\nArguments:\n" @@ -2122,7 +2120,7 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request) strNewWalletPass = request.params[1].get_str().c_str(); if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) - throw runtime_error( + throw std::runtime_error( "walletpassphrasechange <oldpassphrase> <newpassphrase>\n" "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>."); @@ -2142,7 +2140,7 @@ UniValue walletlock(const JSONRPCRequest& request) } if (pwallet->IsCrypted() && (request.fHelp || request.params.size() != 0)) { - throw runtime_error( + throw std::runtime_error( "walletlock\n" "\nRemoves the wallet encryption key from memory, locking the wallet.\n" "After calling this method, you will need to call walletpassphrase again\n" @@ -2182,7 +2180,7 @@ UniValue encryptwallet(const JSONRPCRequest& request) } if (!pwallet->IsCrypted() && (request.fHelp || request.params.size() != 1)) { - throw runtime_error( + throw std::runtime_error( "encryptwallet \"passphrase\"\n" "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" "After this, any calls that interact with private keys such as sending or signing \n" @@ -2221,7 +2219,7 @@ UniValue encryptwallet(const JSONRPCRequest& request) strWalletPass = request.params[0].get_str().c_str(); if (strWalletPass.length() < 1) - throw runtime_error( + throw std::runtime_error( "encryptwallet <passphrase>\n" "Encrypts the wallet with <passphrase>."); @@ -2244,7 +2242,7 @@ UniValue lockunspent(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n" "\nUpdates list of temporarily unspendable outputs.\n" "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" @@ -2308,7 +2306,7 @@ UniValue lockunspent(const JSONRPCRequest& request) {"vout", UniValueType(UniValue::VNUM)}, }); - string txid = find_value(o, "txid").get_str(); + std::string txid = find_value(o, "txid").get_str(); if (!IsHex(txid)) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); @@ -2335,7 +2333,7 @@ UniValue listlockunspent(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 0) - throw runtime_error( + throw std::runtime_error( "listlockunspent\n" "\nReturns list of temporarily unspendable outputs.\n" "See the lockunspent call to lock and unlock transactions for spending.\n" @@ -2362,7 +2360,7 @@ UniValue listlockunspent(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); - vector<COutPoint> vOutpts; + std::vector<COutPoint> vOutpts; pwallet->ListLockedCoins(vOutpts); UniValue ret(UniValue::VARR); @@ -2386,7 +2384,7 @@ UniValue settxfee(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) - throw runtime_error( + throw std::runtime_error( "settxfee amount\n" "\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n" "\nArguments:\n" @@ -2415,21 +2413,22 @@ UniValue getwalletinfo(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "getwalletinfo\n" "Returns an object containing various wallet state info.\n" "\nResult:\n" "{\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" - " \"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\n" - " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" - " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" - " \"hdmasterkeyid\": \"<hash160>\" (string) the Hash160 of the HD master pubkey\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" + " \"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" + " \"keypoolsize_hd_internal\": xxxx, (numeric) how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)\n" + " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" + " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n" + " \"hdmasterkeyid\": \"<hash160>\" (string) the Hash160 of the HD master pubkey\n" "}\n" "\nExamples:\n" + HelpExampleCli("getwalletinfo", "") @@ -2439,18 +2438,23 @@ UniValue getwalletinfo(const JSONRPCRequest& request) LOCK2(cs_main, pwallet->cs_wallet); UniValue obj(UniValue::VOBJ); + + size_t kpExternalSize = pwallet->KeypoolCountExternalKeys(); obj.push_back(Pair("walletversion", pwallet->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance()))); obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance()))); obj.push_back(Pair("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance()))); obj.push_back(Pair("txcount", (int)pwallet->mapWallet.size())); obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize())); + obj.push_back(Pair("keypoolsize", (int64_t)kpExternalSize)); + CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID; + if (!masterKeyID.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) { + obj.push_back(Pair("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize))); + } if (pwallet->IsCrypted()) { obj.push_back(Pair("unlocked_until", pwallet->nRelockTime)); } obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); - CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID; if (!masterKeyID.IsNull()) obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex())); return obj; @@ -2464,7 +2468,7 @@ UniValue resendwallettransactions(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() != 0) - throw runtime_error( + throw std::runtime_error( "resendwallettransactions\n" "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n" "Intended only for testing; the wallet code periodically re-broadcasts\n" @@ -2494,7 +2498,7 @@ UniValue listunspent(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "listunspent ( minconf maxconf [\"addresses\",...] [include_unsafe] )\n" "\nReturns array of unspent transaction outputs\n" "with between minconf and maxconf (inclusive) confirmations.\n" @@ -2508,9 +2512,7 @@ UniValue listunspent(const JSONRPCRequest& request) " ,...\n" " ]\n" "4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n" - " because they come from unconfirmed untrusted transactions or unconfirmed\n" - " replacement transactions (cases where we are less sure that a conflicting\n" - " transaction won't be mined).\n" + " See description of \"safe\" attribute below.\n" "\nResult\n" "[ (array of json object)\n" " {\n" @@ -2523,7 +2525,10 @@ UniValue listunspent(const JSONRPCRequest& request) " \"confirmations\" : n, (numeric) The number of confirmations\n" " \"redeemScript\" : n (string) The redeemScript if scriptPubKey is P2SH\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" + " \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\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" + " and are not eligible for spending by fundrawtransaction and sendtoaddress.\n" " }\n" " ,...\n" "]\n" @@ -2546,7 +2551,7 @@ UniValue listunspent(const JSONRPCRequest& request) nMaxDepth = request.params[1].get_int(); } - set<CBitcoinAddress> setAddress; + std::set<CBitcoinAddress> setAddress; if (request.params.size() > 2 && !request.params[2].isNull()) { RPCTypeCheckArgument(request.params[2], UniValue::VARR); UniValue inputs = request.params[2].get_array(); @@ -2554,9 +2559,9 @@ UniValue listunspent(const JSONRPCRequest& request) const UniValue& input = inputs[idx]; CBitcoinAddress address(input.get_str()); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str()); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ")+input.get_str()); if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); + throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ")+input.get_str()); setAddress.insert(address); } } @@ -2568,7 +2573,7 @@ UniValue listunspent(const JSONRPCRequest& request) } UniValue results(UniValue::VARR); - vector<COutput> vecOutputs; + std::vector<COutput> vecOutputs; assert(pwallet != NULL); LOCK2(cs_main, pwallet->cs_wallet); pwallet->AvailableCoins(vecOutputs, !include_unsafe, NULL, true); @@ -2608,6 +2613,7 @@ UniValue listunspent(const JSONRPCRequest& request) entry.push_back(Pair("confirmations", out.nDepth)); entry.push_back(Pair("spendable", out.fSpendable)); entry.push_back(Pair("solvable", out.fSolvable)); + entry.push_back(Pair("safe", out.fSafe)); results.push_back(entry); } @@ -2622,7 +2628,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) } if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "fundrawtransaction \"hexstring\" ( options )\n" "\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" @@ -2679,7 +2685,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) CFeeRate feeRate = CFeeRate(0); bool overrideEstimatedFeerate = false; UniValue subtractFeeFromOutputs; - set<int> setSubtractFeeFromOutputs; + std::set<int> setSubtractFeeFromOutputs; if (request.params.size() > 1) { if (request.params[1].type() == UniValue::VBOOL) { @@ -2707,7 +2713,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) CBitcoinAddress address(options["changeAddress"].get_str()); if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "changeAddress must be a valid bitcoin address"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "changeAddress must be a valid bitcoin address"); changeAddress = address.Get(); } @@ -2758,10 +2764,10 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) } CAmount nFeeOut; - string strFailReason; + std::string strFailReason; if (!pwallet->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress)) { - throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); + throw JSONRPCError(RPC_WALLET_ERROR, strFailReason); } UniValue result(UniValue::VOBJ); @@ -2782,14 +2788,14 @@ UniValue fundrawtransaction(const JSONRPCRequest& request) int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, CWallet &wallet) { CMutableTransaction txNew(tx); - std::vector<pair<CWalletTx *, unsigned int>> vCoins; + std::vector<std::pair<CWalletTx*, unsigned int>> vCoins; // Look up the inputs. We should have already checked that this transaction // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our // wallet, with a valid index into the vout array. for (auto& input : tx.vin) { const auto mi = wallet.mapWallet.find(input.prevout.hash); assert(mi != wallet.mapWallet.end() && input.prevout.n < mi->second.tx->vout.size()); - vCoins.emplace_back(make_pair(&(mi->second), input.prevout.n)); + vCoins.emplace_back(std::make_pair(&(mi->second), input.prevout.n)); } if (!wallet.DummySignTx(txNew, vCoins)) { // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE) @@ -2807,7 +2813,7 @@ UniValue bumpfee(const JSONRPCRequest& request) return NullUniValue; if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { - throw runtime_error( + throw std::runtime_error( "bumpfee \"txid\" ( options ) \n" "\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" @@ -2862,33 +2868,33 @@ UniValue bumpfee(const JSONRPCRequest& request) CWalletTx& wtx = pwallet->mapWallet[hash]; if (pwallet->HasWalletSpend(hash)) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the wallet"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the wallet"); } { LOCK(mempool.cs); auto it = mempool.mapTx.find(hash); if (it != mempool.mapTx.end() && it->GetCountWithDescendants() > 1) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the mempool"); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction has descendants in the mempool"); } } if (wtx.GetDepthInMainChain() != 0) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction has been mined, or is conflicted with a mined transaction"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has been mined, or is conflicted with a mined transaction"); } if (!SignalsOptInRBF(wtx)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction is not BIP 125 replaceable"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction is not BIP 125 replaceable"); } if (wtx.mapValue.count("replaced_by_txid")) { - throw JSONRPCError(RPC_INVALID_REQUEST, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid"))); + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid"))); } // check that original tx consists entirely of our inputs // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee) if (!pwallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that don't belong to this wallet"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction contains inputs that don't belong to this wallet"); } // figure out which output was change @@ -2897,13 +2903,13 @@ UniValue bumpfee(const JSONRPCRequest& request) for (size_t i = 0; i < wtx.tx->vout.size(); ++i) { if (pwallet->IsChange(wtx.tx->vout[i])) { if (nOutput != -1) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has multiple change outputs"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction has multiple change outputs"); } nOutput = i; } } if (nOutput == -1) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not have a change output"); + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction does not have a change output"); } // Calculate the expected size of the new transaction. @@ -2994,7 +3000,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // Check that in all cases the new fee doesn't violate maxTxFee if (nNewFee > maxTxFee) { - throw JSONRPCError(RPC_MISC_ERROR, + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)", FormatMoney(nNewFee), FormatMoney(maxTxFee))); } @@ -3006,7 +3012,7 @@ UniValue bumpfee(const JSONRPCRequest& request) // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment. CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) { - throw JSONRPCError(RPC_MISC_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK()))); + throw JSONRPCError(RPC_WALLET_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK()))); } // Now modify the output to increase the fee. @@ -3016,7 +3022,7 @@ UniValue bumpfee(const JSONRPCRequest& request) CMutableTransaction tx(*(wtx.tx)); CTxOut* poutput = &(tx.vout[nOutput]); if (poutput->nValue < nDelta) { - throw JSONRPCError(RPC_MISC_ERROR, "Change output is too small to bump the fee"); + throw JSONRPCError(RPC_WALLET_ERROR, "Change output is too small to bump the fee"); } // If the output would become dust, discard it (converting the dust to fee) diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 42b67fac39..67e5e90224 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -27,16 +27,14 @@ extern UniValue importmulti(const JSONRPCRequest& request); // we repeat those tests this many times and only complain if all iterations of the test fail #define RANDOM_REPEATS 5 -using namespace std; - std::vector<std::unique_ptr<CWalletTx>> wtxn; -typedef set<pair<const CWalletTx*,unsigned int> > CoinSet; +typedef std::set<std::pair<const CWalletTx*,unsigned int> > CoinSet; BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup) static const CWallet testWallet; -static vector<COutput> vCoins; +static std::vector<COutput> vCoins; static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { @@ -56,7 +54,7 @@ static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = fa wtx->fDebitCached = true; wtx->nDebitCached = 1; } - COutput output(wtx.get(), nInput, nAge, true, true); + COutput output(wtx.get(), nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */); vCoins.push_back(output); wtxn.emplace_back(std::move(wtx)); } @@ -69,7 +67,7 @@ static void empty_wallet(void) static bool equal_sets(CoinSet a, CoinSet b) { - pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin()); + std::pair<CoinSet::iterator, CoinSet::iterator> ret = mismatch(a.begin(), a.end(), b.begin()); return ret.first == a.end() && ret.second == b.end(); } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index dc3e0e28d1..e631c86bb2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -33,8 +33,6 @@ #include <boost/filesystem.hpp> #include <boost/thread.hpp> -using namespace std; - CWallet* pwalletMain = NULL; /** Transaction fee set by the user */ CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); @@ -66,8 +64,8 @@ const uint256 CMerkleTx::ABANDON_HASH(uint256S("00000000000000000000000000000000 struct CompareValueOnly { - bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1, - const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const + bool operator()(const std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> >& t1, + const std::pair<CAmount, std::pair<const CWalletTx*, unsigned int> >& t2) const { return t1.first < t2.first; } @@ -87,7 +85,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const return &(it->second); } -CPubKey CWallet::GenerateNewKey() +CPubKey CWallet::GenerateNewKey(bool internal) { AssertLockHeld(cs_wallet); // mapKeyMetadata bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets @@ -100,7 +98,7 @@ CPubKey CWallet::GenerateNewKey() // use HD key derivation if HD was enabled during wallet creation if (IsHDEnabled()) { - DeriveNewChildKey(metadata, secret); + DeriveNewChildKey(metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); } else { secret.MakeNewKey(fCompressed); } @@ -120,13 +118,13 @@ CPubKey CWallet::GenerateNewKey() return pubkey; } -void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret) +void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal) { // for now we use a fixed keypath scheme of m/0'/0'/k CKey key; //master key seed (256bit) CExtKey masterKey; //hd master key CExtKey accountKey; //key at m/0' - CExtKey externalChainChildKey; //key at m/0'/0' + CExtKey chainChildKey; //key at m/0'/0' (external) or m/0'/1' (internal) CExtKey childKey; //key at m/0'/0'/<n>' // try to get the master key @@ -139,22 +137,28 @@ void CWallet::DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret) // use hardened derivation (child keys >= 0x80000000 are hardened after bip32) masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); - // derive m/0'/0' - accountKey.Derive(externalChainChildKey, BIP32_HARDENED_KEY_LIMIT); + // derive m/0'/0' (external chain) OR m/0'/1' (internal chain) + assert(internal ? CanSupportFeature(FEATURE_HD_SPLIT) : true); + accountKey.Derive(chainChildKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0)); // derive child key at next index, skip keys already known to the wallet do { // always derive hardened keys // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649 - externalChainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); - metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'"; - metadata.hdMasterKeyID = hdChain.masterKeyID; - // increment childkey index - hdChain.nExternalChainCounter++; + if (internal) { + chainChildKey.Derive(childKey, hdChain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT); + metadata.hdKeypath = "m/0'/1'/" + std::to_string(hdChain.nInternalChainCounter) + "'"; + hdChain.nInternalChainCounter++; + } + else { + chainChildKey.Derive(childKey, hdChain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT); + metadata.hdKeypath = "m/0'/0'/" + std::to_string(hdChain.nExternalChainCounter) + "'"; + hdChain.nExternalChainCounter++; + } } while (HaveKey(childKey.key.GetPubKey().GetID())); secret = childKey.key; - + metadata.hdMasterKeyID = hdChain.masterKeyID; // update the chain model in the database if (!CWalletDB(strWalletFile).WriteHDChain(hdChain)) throw std::runtime_error(std::string(__func__) + ": Writing HD chain model failed"); @@ -186,7 +190,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) } bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, - const vector<unsigned char> &vchCryptedSecret) + const std::vector<unsigned char> &vchCryptedSecret) { if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) return false; @@ -404,9 +408,9 @@ bool CWallet::SetMaxVersion(int nVersion) return true; } -set<uint256> CWallet::GetConflicts(const uint256& txid) const +std::set<uint256> CWallet::GetConflicts(const uint256& txid) const { - set<uint256> result; + std::set<uint256> result; AssertLockHeld(cs_wallet); std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid); @@ -471,7 +475,7 @@ bool CWallet::Verify() return true; } -void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range) +void CWallet::SyncMetaData(std::pair<TxSpends::iterator, TxSpends::iterator> range) { // We want all the wallet transactions in range to have the same metadata as // the oldest (smallest nOrderPos). @@ -515,7 +519,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range) bool CWallet::IsSpent(const uint256& hash, unsigned int n) const { const COutPoint outpoint(hash, n); - pair<TxSpends::const_iterator, TxSpends::const_iterator> range; + std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range; range = mapTxSpends.equal_range(outpoint); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) @@ -533,9 +537,9 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const void CWallet::AddToSpends(const COutPoint& outpoint, const uint256& wtxid) { - mapTxSpends.insert(make_pair(outpoint, wtxid)); + mapTxSpends.insert(std::make_pair(outpoint, wtxid)); - pair<TxSpends::iterator, TxSpends::iterator> range; + std::pair<TxSpends::iterator, TxSpends::iterator> range; range = mapTxSpends.equal_range(outpoint); SyncMetaData(range); } @@ -635,7 +639,9 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) if (IsHDEnabled()) { CKey key; CPubKey masterPubKey = GenerateNewHDMasterKey(); - if (!SetHDMasterKey(masterPubKey)) + // preserve the old chains version to not break backward compatibility + CHDChain oldChain = GetHDChain(); + if (!SetHDMasterKey(masterPubKey, &oldChain)) return false; } @@ -661,20 +667,20 @@ DBErrors CWallet::ReorderTransactions() // Probably a bad idea to change the output of this // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap. - typedef pair<CWalletTx*, CAccountingEntry*> TxPair; - typedef multimap<int64_t, TxPair > TxItems; + typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; + typedef std::multimap<int64_t, TxPair > TxItems; TxItems txByTime; - for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { CWalletTx* wtx = &((*it).second); - txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0))); + txByTime.insert(std::make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0))); } - list<CAccountingEntry> acentries; + std::list<CAccountingEntry> acentries; walletdb.ListAccountCreditDebit("", acentries); BOOST_FOREACH(CAccountingEntry& entry, acentries) { - txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); + txByTime.insert(std::make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); } nOrderPosNext = 0; @@ -788,7 +794,7 @@ bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bFo else { // Check if the current key has been used CScript scriptPubKey = GetScriptForDestination(account.vchPubKey.GetID()); - for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); + for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end() && account.vchPubKey.IsValid(); ++it) BOOST_FOREACH(const CTxOut& txout, (*it).second.tx->vout) @@ -801,7 +807,7 @@ bool CWallet::GetAccountPubkey(CPubKey &pubKey, std::string strAccount, bool bFo // Generate a new key if (bForceNew) { - if (!GetKeyFromPool(account.vchPubKey)) + if (!GetKeyFromPool(account.vchPubKey, false)) return false; SetAddressBook(account.vchPubKey.GetID(), strAccount, "receive"); @@ -860,7 +866,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) uint256 hash = wtxIn.GetHash(); // Inserts only if not already there, returns tx inserted or tx found - pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn)); + std::pair<std::map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(std::make_pair(hash, wtxIn)); CWalletTx& wtx = (*ret.first).second; wtx.BindWallet(this); bool fInsertedNew = ret.second; @@ -868,7 +874,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(&walletdb); - wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); wtx.nTimeSmart = ComputeTimeSmart(wtx); AddToSpends(hash); } @@ -933,7 +939,7 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn) mapWallet[hash] = wtxIn; CWalletTx& wtx = mapWallet[hash]; wtx.BindWallet(this); - wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); + wtxOrdered.insert(std::make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(hash); BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if (mapWallet.count(txin.prevout.hash)) { @@ -1132,7 +1138,7 @@ isminetype CWallet::IsMine(const CTxIn &txin) const { { LOCK(cs_wallet); - map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); + std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; @@ -1149,7 +1155,7 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const { { LOCK(cs_wallet); - map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); + std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); if (mi != mapWallet.end()) { const CWalletTx& prev = (*mi).second; @@ -1302,17 +1308,17 @@ CPubKey CWallet::GenerateNewHDMasterKey() return pubkey; } -bool CWallet::SetHDMasterKey(const CPubKey& pubkey) +bool CWallet::SetHDMasterKey(const CPubKey& pubkey, CHDChain *possibleOldChain) { LOCK(cs_wallet); - - // ensure this wallet.dat can only be opened by clients supporting HD - SetMinVersion(FEATURE_HD); - // store the keyid (hash160) together with // the child index counter in the database // as a hdchain object CHDChain newHdChain; + if (possibleOldChain) { + // preserve the old chains version + newHdChain.nVersion = possibleOldChain->nVersion; + } newHdChain.masterKeyID = pubkey.GetID(); SetHDChain(newHdChain, false); @@ -1323,13 +1329,13 @@ bool CWallet::SetHDChain(const CHDChain& chain, bool memonly) { LOCK(cs_wallet); if (!memonly && !CWalletDB(strWalletFile).WriteHDChain(chain)) - throw runtime_error(std::string(__func__) + ": writing chain failed"); + throw std::runtime_error(std::string(__func__) + ": writing chain failed"); hdChain = chain; return true; } -bool CWallet::IsHDEnabled() +bool CWallet::IsHDEnabled() const { return !hdChain.masterKeyID.IsNull(); } @@ -1351,7 +1357,7 @@ int CWalletTx::GetRequestCount() const // Generated block if (!hashUnset()) { - map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); + std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock); if (mi != pwallet->mapRequestCount.end()) nRequests = (*mi).second; } @@ -1359,7 +1365,7 @@ int CWalletTx::GetRequestCount() const else { // Did anyone request this transaction? - map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); + std::map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash()); if (mi != pwallet->mapRequestCount.end()) { nRequests = (*mi).second; @@ -1367,7 +1373,7 @@ int CWalletTx::GetRequestCount() const // How about the block it's in? if (nRequests == 0 && !hashUnset()) { - map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock); + std::map<uint256, int>::const_iterator _mi = pwallet->mapRequestCount.find(hashBlock); if (_mi != pwallet->mapRequestCount.end()) nRequests = (*_mi).second; else @@ -1379,8 +1385,8 @@ int CWalletTx::GetRequestCount() const return nRequests; } -void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, - list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const +void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived, + std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const { nFee = 0; listReceived.clear(); @@ -1435,15 +1441,15 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, } -void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, +void CWalletTx::GetAccountAmounts(const std::string& strAccount, CAmount& nReceived, CAmount& nSent, CAmount& nFee, const isminefilter& filter) const { nReceived = nSent = nFee = 0; CAmount allFee; - string strSentAccount; - list<COutputEntry> listReceived; - list<COutputEntry> listSent; + std::string strSentAccount; + std::list<COutputEntry> listReceived; + std::list<COutputEntry> listSent; GetAmounts(listReceived, listSent, allFee, strSentAccount, filter); if (strAccount == strSentAccount) @@ -1458,7 +1464,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, { if (pwallet->mapAddressBook.count(r.destination)) { - map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination); + std::map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.destination); if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount) nReceived += r.amount; } @@ -1579,9 +1585,9 @@ bool CWalletTx::RelayWalletTransaction(CConnman* connman) return false; } -set<uint256> CWalletTx::GetConflicts() const +std::set<uint256> CWalletTx::GetConflicts() const { - set<uint256> result; + std::set<uint256> result; if (pwallet != NULL) { uint256 myHash = GetHash(); @@ -1806,14 +1812,14 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime, CCon LOCK(cs_wallet); // Sort them in chronological order - multimap<unsigned int, CWalletTx*> mapSorted; + std::multimap<unsigned int, CWalletTx*> mapSorted; BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { CWalletTx& wtx = item.second; // Don't rebroadcast if newer than nTime: if (wtx.nTimeReceived > nTime) continue; - mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); + mapSorted.insert(std::make_pair(wtx.nTimeReceived, &wtx)); } BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { @@ -1863,7 +1869,7 @@ CAmount CWallet::GetBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) @@ -1879,7 +1885,7 @@ CAmount CWallet::GetUnconfirmedBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) @@ -1894,7 +1900,7 @@ CAmount CWallet::GetImmatureBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureCredit(); @@ -1908,7 +1914,7 @@ CAmount CWallet::GetWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (pcoin->IsTrusted()) @@ -1924,7 +1930,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; if (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0 && pcoin->InMempool()) @@ -1939,7 +1945,7 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; nTotal += pcoin->GetImmatureWatchOnlyCredit(); @@ -1948,13 +1954,13 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const return nTotal; } -void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const +void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const CCoinControl *coinControl, bool fIncludeZeroValue) const { vCoins.clear(); { LOCK2(cs_main, cs_wallet); - for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const uint256& wtxid = it->first; const CWalletTx* pcoin = &(*it).second; @@ -1962,9 +1968,6 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const if (!CheckFinalTx(*pcoin)) continue; - if (fOnlyConfirmed && !pcoin->IsTrusted()) - continue; - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; @@ -1977,6 +1980,8 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const if (nDepth == 0 && !pcoin->InMempool()) continue; + bool safeTx = pcoin->IsTrusted(); + // We should not consider coins from transactions that are replacing // other transactions. // @@ -1992,8 +1997,8 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const // 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 && fOnlyConfirmed && pcoin->mapValue.count("replaces_txid")) { - continue; + if (nDepth == 0 && pcoin->mapValue.count("replaces_txid")) { + safeTx = false; } // Similarly, we should not consider coins from transactions that @@ -2004,7 +2009,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const // 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 && fOnlyConfirmed && pcoin->mapValue.count("replaced_by_txid")) { + if (nDepth == 0 && pcoin->mapValue.count("replaced_by_txid")) { + safeTx = false; + } + + if (fOnlySafe && !safeTx) { continue; } @@ -2016,16 +2025,16 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const vCoins.push_back(COutput(pcoin, i, nDepth, ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO), - (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO)); + (mine & (ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE)) != ISMINE_NO, safeTx)); } } } } -static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, - vector<char>& vfBest, CAmount& nBest, int iterations = 1000) +static void ApproximateBestSubset(const std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > >& vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, + std::vector<char>& vfBest, CAmount& nBest, int iterations = 1000) { - vector<char> vfIncluded; + std::vector<char> vfIncluded; vfBest.assign(vValue.size(), true); nBest = nTotalLower; @@ -2068,17 +2077,17 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns } } -bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, vector<COutput> vCoins, - set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const +bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMine, const int nConfTheirs, const uint64_t nMaxAncestors, std::vector<COutput> vCoins, + std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target - pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger; + std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > coinLowestLarger; coinLowestLarger.first = std::numeric_limits<CAmount>::max(); coinLowestLarger.second.first = NULL; - vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue; + std::vector<std::pair<CAmount, std::pair<const CWalletTx*,unsigned int> > > vValue; CAmount nTotalLower = 0; random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); @@ -2099,7 +2108,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin int i = output.i; CAmount n = pcoin->tx->vout[i].nValue; - pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i)); + std::pair<CAmount,std::pair<const CWalletTx*,unsigned int> > coin = std::make_pair(n,std::make_pair(pcoin, i)); if (n == nTargetValue) { @@ -2140,7 +2149,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin // Solve subset sum by stochastic approximation std::sort(vValue.begin(), vValue.end(), CompareValueOnly()); std::reverse(vValue.begin(), vValue.end()); - vector<char> vfBest; + std::vector<char> vfBest; CAmount nBest; ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest); @@ -2173,9 +2182,9 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const int nConfMin return true; } -bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const { - vector<COutput> vCoins(vAvailableCoins); + std::vector<COutput> vCoins(vAvailableCoins); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) @@ -2185,13 +2194,13 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& if (!out.fSpendable) continue; nValueRet += out.tx->tx->vout[out.i].nValue; - setCoinsRet.insert(make_pair(out.tx, out.i)); + setCoinsRet.insert(std::make_pair(out.tx, out.i)); } return (nValueRet >= nTargetValue); } // calculate value from preset inputs and store them - set<pair<const CWalletTx*, uint32_t> > setPresetCoins; + std::set<std::pair<const CWalletTx*, uint32_t> > setPresetCoins; CAmount nValueFromPresetInputs = 0; std::vector<COutPoint> vPresetInputs; @@ -2199,7 +2208,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& coinControl->ListSelected(vPresetInputs); BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs) { - map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); + std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); if (it != mapWallet.end()) { const CWalletTx* pcoin = &it->second; @@ -2207,15 +2216,15 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& if (pcoin->tx->vout.size() <= outpoint.n) return false; nValueFromPresetInputs += pcoin->tx->vout[outpoint.n].nValue; - setPresetCoins.insert(make_pair(pcoin, outpoint.n)); + setPresetCoins.insert(std::make_pair(pcoin, outpoint.n)); } else return false; // TODO: Allow non-wallet inputs } // remove preset inputs from vCoins - for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();) + for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();) { - if (setPresetCoins.count(make_pair(it->tx, it->i))) + if (setPresetCoins.count(std::make_pair(it->tx, it->i))) it = vCoins.erase(it); else ++it; @@ -2244,7 +2253,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount& bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange) { - vector<CRecipient> vecSend; + std::vector<CRecipient> vecSend; // Turn the txout set into a CRecipient vector for (size_t idx = 0; idx < tx.vout.size(); idx++) @@ -2298,7 +2307,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov return true; } -bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, +bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, const CCoinControl* coinControl, bool sign) { CAmount nValue = 0; @@ -2359,7 +2368,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt assert(txNew.nLockTime < LOCKTIME_THRESHOLD); { - set<pair<const CWalletTx*,unsigned int> > setCoins; + std::set<std::pair<const CWalletTx*,unsigned int> > setCoins; LOCK2(cs_main, cs_wallet); { std::vector<COutput> vAvailableCoins; @@ -2444,7 +2453,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // Reserve a new key pair from key pool CPubKey vchPubKey; bool ret; - ret = reservekey.GetReservedKey(vchPubKey); + ret = reservekey.GetReservedKey(vchPubKey, true); if (!ret) { strFailReason = _("Keypool ran out, please call keypoolrefill first"); @@ -2499,7 +2508,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt return false; } - vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut; + std::vector<CTxOut>::iterator position = txNew.vout.begin()+nChangePosInOut; txNew.vout.insert(position, newTxOut); } } @@ -2516,9 +2525,10 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // to avoid conflicting with other possible uses of nSequence, // and in the spirit of "smallest possible change from prior // behavior." + bool rbf = coinControl ? coinControl->signalRbf : fWalletRbf; for (const auto& coin : setCoins) txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second,CScript(), - std::numeric_limits<unsigned int>::max() - (fWalletRbf ? 2 : 1))); + std::numeric_limits<unsigned int>::max() - (rbf ? 2 : 1))); // Fill in dummy signatures for fee calculation. if (!DummySignTx(txNew, setCoins)) { @@ -2569,7 +2579,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // to be addressed so we avoid creating too small an output. if (nFeeRet > nFeeNeeded && nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) { CAmount extraFeePaid = nFeeRet - nFeeNeeded; - vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut; + std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut; change_position->nValue += extraFeePaid; nFeeRet -= extraFeePaid; } @@ -2579,7 +2589,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt // Try to reduce change to include necessary fee if (nChangePosInOut != -1 && nSubtractFeeFromAmount == 0) { CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet; - vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut; + std::vector<CTxOut>::iterator change_position = txNew.vout.begin()+nChangePosInOut; // Only reduce change if remaining amount is still a large enough output. if (change_position->nValue >= MIN_FINAL_CHANGE + additionalFeeNeeded) { change_position->nValue -= additionalFeeNeeded; @@ -2705,7 +2715,7 @@ bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB *pwa laccentries.push_back(acentry); CAccountingEntry & entry = laccentries.back(); - wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + wtxOrdered.insert(std::make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); return true; } @@ -2770,7 +2780,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) return DB_LOAD_OK; } -DBErrors CWallet::ZapSelectTx(vector<uint256>& vHashIn, vector<uint256>& vHashOut) +DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) { if (!fFileBacked) return DB_LOAD_OK; @@ -2825,7 +2835,7 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx) } -bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) +bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose) { bool fUpdated = false; { @@ -2854,7 +2864,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address) { // Delete destdata tuples associated with address std::string strAddress = CBitcoinAddress(address).ToString(); - BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata) + BOOST_FOREACH(const PAIRTYPE(std::string, std::string) &item, mapAddressBook[address].destdata) { CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); } @@ -2883,7 +2893,7 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) /** * Mark old keypool keys as used, - * and generate all new keys + * and generate all new keys */ bool CWallet::NewKeyPool() { @@ -2894,21 +2904,37 @@ bool CWallet::NewKeyPool() walletdb.ErasePool(nIndex); setKeyPool.clear(); - if (IsLocked()) + if (!TopUpKeyPool()) { return false; - - int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0); - for (int i = 0; i < nKeys; i++) - { - int64_t nIndex = i+1; - walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); - setKeyPool.insert(nIndex); } - LogPrintf("CWallet::NewKeyPool wrote %d new keys\n", nKeys); + LogPrintf("CWallet::NewKeyPool rewrote keypool\n"); } return true; } +size_t CWallet::KeypoolCountExternalKeys() +{ + AssertLockHeld(cs_wallet); // setKeyPool + + // immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported + if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT)) + return setKeyPool.size(); + + CWalletDB walletdb(strWalletFile); + + // count amount of external keys + size_t amountE = 0; + for(const int64_t& id : setKeyPool) + { + CKeyPool tmpKeypool; + if (!walletdb.ReadPool(id, tmpKeypool)) + throw std::runtime_error(std::string(__func__) + ": read failed"); + amountE += !tmpKeypool.fInternal; + } + + return amountE; +} + bool CWallet::TopUpKeyPool(unsigned int kpSize) { { @@ -2917,30 +2943,44 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) if (IsLocked()) return false; - CWalletDB walletdb(strWalletFile); - // Top up key pool unsigned int nTargetSize; if (kpSize > 0) nTargetSize = kpSize; else - nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0); + nTargetSize = std::max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0); + + // count amount of available keys (internal, external) + // make sure the keypool of external and internal keys fits the user selected target (-keypool) + int64_t amountExternal = KeypoolCountExternalKeys(); + int64_t amountInternal = setKeyPool.size() - amountExternal; + int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountExternal, (int64_t) 0); + int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountInternal, (int64_t) 0); - while (setKeyPool.size() < (nTargetSize + 1)) + if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT)) + { + // don't create extra internal keys + missingInternal = 0; + } + bool internal = false; + CWalletDB walletdb(strWalletFile); + for (int64_t i = missingInternal + missingExternal; i--;) { int64_t nEnd = 1; + if (i < missingInternal) + internal = true; if (!setKeyPool.empty()) nEnd = *(--setKeyPool.end()) + 1; - if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) - throw runtime_error(std::string(__func__) + ": writing generated key failed"); + if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(internal), internal))) + throw std::runtime_error(std::string(__func__) + ": writing generated key failed"); setKeyPool.insert(nEnd); - LogPrintf("keypool added key %d, size=%u\n", nEnd, setKeyPool.size()); + LogPrintf("keypool added key %d, size=%u, internal=%d\n", nEnd, setKeyPool.size(), internal); } } return true; } -void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool) +void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal) { nIndex = -1; keypool.vchPubKey = CPubKey(); @@ -2956,14 +2996,24 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool) CWalletDB walletdb(strWalletFile); - nIndex = *(setKeyPool.begin()); - setKeyPool.erase(setKeyPool.begin()); - if (!walletdb.ReadPool(nIndex, keypool)) - throw runtime_error(std::string(__func__) + ": read failed"); - if (!HaveKey(keypool.vchPubKey.GetID())) - throw runtime_error(std::string(__func__) + ": unknown key in key pool"); - assert(keypool.vchPubKey.IsValid()); - LogPrintf("keypool reserve %d\n", nIndex); + // try to find a key that matches the internal/external filter + for(const int64_t& id : setKeyPool) + { + CKeyPool tmpKeypool; + if (!walletdb.ReadPool(id, tmpKeypool)) + throw std::runtime_error(std::string(__func__) + ": read failed"); + if (!HaveKey(tmpKeypool.vchPubKey.GetID())) + throw std::runtime_error(std::string(__func__) + ": unknown key in key pool"); + if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT) || tmpKeypool.fInternal == internal) + { + nIndex = id; + keypool = tmpKeypool; + setKeyPool.erase(id); + assert(keypool.vchPubKey.IsValid()); + LogPrintf("keypool reserve %d\n", nIndex); + return; + } + } } } @@ -2988,17 +3038,17 @@ void CWallet::ReturnKey(int64_t nIndex) LogPrintf("keypool return %d\n", nIndex); } -bool CWallet::GetKeyFromPool(CPubKey& result) +bool CWallet::GetKeyFromPool(CPubKey& result, bool internal) { int64_t nIndex = 0; CKeyPool keypool; { LOCK(cs_wallet); - ReserveKeyFromKeyPool(nIndex, keypool); + ReserveKeyFromKeyPool(nIndex, keypool, internal); if (nIndex == -1) { if (IsLocked()) return false; - result = GenerateNewKey(); + result = GenerateNewKey(internal); return true; } KeepKey(nIndex); @@ -3015,19 +3065,43 @@ int64_t CWallet::GetOldestKeyPoolTime() if (setKeyPool.empty()) return GetTime(); - // load oldest key from keypool, get time and return CKeyPool keypool; CWalletDB walletdb(strWalletFile); + + if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) + { + // if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key) + int64_t now = GetTime(); + int64_t oldest_external = now, oldest_internal = now; + + for(const int64_t& id : setKeyPool) + { + if (!walletdb.ReadPool(id, keypool)) { + throw std::runtime_error(std::string(__func__) + ": read failed"); + } + if (keypool.fInternal && keypool.nTime < oldest_internal) { + oldest_internal = keypool.nTime; + } + else if (!keypool.fInternal && keypool.nTime < oldest_external) { + oldest_external = keypool.nTime; + } + if (oldest_internal != now && oldest_external != now) { + break; + } + } + return std::max(oldest_internal, oldest_external); + } + // load oldest key from keypool, get time and return int64_t nIndex = *(setKeyPool.begin()); if (!walletdb.ReadPool(nIndex, keypool)) - throw runtime_error(std::string(__func__) + ": read oldest key in keypool failed"); + throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed"); assert(keypool.vchPubKey.IsValid()); return keypool.nTime; } std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() { - map<CTxDestination, CAmount> balances; + std::map<CTxDestination, CAmount> balances; { LOCK(cs_wallet); @@ -3065,11 +3139,11 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() return balances; } -set< set<CTxDestination> > CWallet::GetAddressGroupings() +std::set< std::set<CTxDestination> > CWallet::GetAddressGroupings() { AssertLockHeld(cs_wallet); // mapWallet - set< set<CTxDestination> > groupings; - set<CTxDestination> grouping; + std::set< std::set<CTxDestination> > groupings; + std::set<CTxDestination> grouping; BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { @@ -3122,20 +3196,20 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings() } } - set< set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses - map< CTxDestination, set<CTxDestination>* > setmap; // map addresses to the unique group containing it - BOOST_FOREACH(set<CTxDestination> _grouping, groupings) + std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses + std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it + BOOST_FOREACH(std::set<CTxDestination> _grouping, groupings) { // make a set of all the groups hit by this new group - set< set<CTxDestination>* > hits; - map< CTxDestination, set<CTxDestination>* >::iterator it; + std::set< std::set<CTxDestination>* > hits; + std::map< CTxDestination, std::set<CTxDestination>* >::iterator it; BOOST_FOREACH(CTxDestination address, _grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); // merge all hit groups into a new single group and delete old groups - set<CTxDestination>* merged = new set<CTxDestination>(_grouping); - BOOST_FOREACH(set<CTxDestination>* hit, hits) + std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping); + BOOST_FOREACH(std::set<CTxDestination>* hit, hits) { merged->insert(hit->begin(), hit->end()); uniqueGroupings.erase(hit); @@ -3148,8 +3222,8 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings() setmap[element] = merged; } - set< set<CTxDestination> > ret; - BOOST_FOREACH(set<CTxDestination>* uniqueGrouping, uniqueGroupings) + std::set< std::set<CTxDestination> > ret; + BOOST_FOREACH(std::set<CTxDestination>* uniqueGrouping, uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; @@ -3169,7 +3243,7 @@ CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAc CAmount nBalance = 0; // Tally wallet transactions - for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + for (std::map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) @@ -3192,23 +3266,23 @@ CAmount CWallet::GetAccountBalance(CWalletDB& walletdb, const std::string& strAc std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const { LOCK(cs_wallet); - set<CTxDestination> result; + std::set<CTxDestination> result; BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook) { const CTxDestination& address = item.first; - const string& strName = item.second.name; + const std::string& strName = item.second.name; if (strName == strAccount) result.insert(address); } return result; } -bool CReserveKey::GetReservedKey(CPubKey& pubkey) +bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal) { if (nIndex == -1) { CKeyPool keypool; - pwallet->ReserveKeyFromKeyPool(nIndex, keypool); + pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal); if (nIndex != -1) vchPubKey = keypool.vchPubKey; else { @@ -3236,7 +3310,7 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const +void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const { setAddress.clear(); @@ -3247,11 +3321,11 @@ void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const { CKeyPool keypool; if (!walletdb.ReadPool(id, keypool)) - throw runtime_error(std::string(__func__) + ": read failed"); + throw std::runtime_error(std::string(__func__) + ": read failed"); assert(keypool.vchPubKey.IsValid()); CKeyID keyID = keypool.vchPubKey.GetID(); if (!HaveKey(keyID)) - throw runtime_error(std::string(__func__) + ": unknown key in key pool"); + throw std::runtime_error(std::string(__func__) + ": unknown key in key pool"); setAddress.insert(keyID); } } @@ -3261,7 +3335,7 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) { LOCK(cs_wallet); // Only notify UI if this transaction is in this wallet - map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx); + std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(hashTx); if (mi != mapWallet.end()) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } @@ -3621,13 +3695,17 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile) { // Create new keyUser and set as default key if (GetBoolArg("-usehd", DEFAULT_USE_HD_WALLET) && !walletInstance->IsHDEnabled()) { + + // ensure this wallet.dat can only be opened by clients supporting HD with chain split + walletInstance->SetMinVersion(FEATURE_HD_SPLIT); + // generate a new master key CPubKey masterPubKey = walletInstance->GenerateNewHDMasterKey(); if (!walletInstance->SetHDMasterKey(masterPubKey)) throw std::runtime_error(std::string(__func__) + ": Storing master key failed"); } CPubKey newDefaultKey; - if (walletInstance->GetKeyFromPool(newDefaultKey)) { + if (walletInstance->GetKeyFromPool(newDefaultKey, false)) { walletInstance->SetDefaultKey(newDefaultKey); if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) { InitError(_("Cannot write default address") += "\n"); @@ -3886,12 +3964,14 @@ bool CWallet::BackupWallet(const std::string& strDest) CKeyPool::CKeyPool() { nTime = GetTime(); + fInternal = false; } -CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn) +CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn) { nTime = GetTime(); vchPubKey = vchPubKeyIn; + fInternal = internalIn; } CWalletKey::CWalletKey(int64_t nExpires) @@ -3932,7 +4012,7 @@ int CMerkleTx::GetBlocksToMaturity() const { if (!IsCoinBase()) return 0; - return max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain()); + return std::max(0, (COINBASE_MATURITY+1) - GetDepthInMainChain()); } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 9f89c89bc2..ccede60097 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -86,6 +86,9 @@ enum WalletFeature FEATURE_COMPRPUBKEY = 60000, // compressed public keys FEATURE_HD = 130000, // Hierarchical key derivation after BIP32 (HD Wallet) + + FEATURE_HD_SPLIT = 139900, // Wallet with HD chain split (change outputs will use m/0'/1'/k) + FEATURE_LATEST = FEATURE_COMPRPUBKEY // HD is optional, use FEATURE_COMPRPUBKEY as latest version }; @@ -96,9 +99,10 @@ class CKeyPool public: int64_t nTime; CPubKey vchPubKey; + bool fInternal; // for change outputs CKeyPool(); - CKeyPool(const CPubKey& vchPubKeyIn); + CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn); ADD_SERIALIZE_METHODS; @@ -109,6 +113,19 @@ public: READWRITE(nVersion); READWRITE(nTime); READWRITE(vchPubKey); + if (ser_action.ForRead()) { + try { + READWRITE(fInternal); + } + catch (std::ios_base::failure&) { + /* flag as external address if we can't read the internal boolean + (this will be the case for any wallet before the HD chain split version) */ + fInternal = false; + } + } + else { + READWRITE(fInternal); + } } }; @@ -466,12 +483,23 @@ public: const CWalletTx *tx; int i; int nDepth; + + /** Whether we have the private keys to spend this output */ bool fSpendable; + + /** Whether we know how to spend this output, ignoring the lack of keys */ bool fSolvable; - COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn) + /** + * Whether this output is considered safe to spend. Unconfirmed transactions + * from outside keys and unconfirmed replacement transactions are considered + * unsafe and will not be used to fund new spending transactions. + */ + bool fSafe; + + COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, bool fSafeIn) { - tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; + tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn; fSolvable = fSolvableIn; fSafe = fSafeIn; } std::string ToString() const; @@ -636,6 +664,9 @@ private: /* the HD chain data model (external chain counters) */ CHDChain hdChain; + /* HD derive new child key (on internal or external chain) */ + void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false); + bool fFileBacked; std::set<int64_t> setKeyPool; @@ -714,6 +745,7 @@ public: nLastResend = 0; nTimeFirstKey = 0; fBroadcastTransactions = false; + nRelockTime = 0; } std::map<uint256, CWalletTx> mapWallet; @@ -740,7 +772,7 @@ public: /** * populate vCoins with vector of available COutputs. */ - void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const; + void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false) const; /** * Shuffle and select coins until nTargetValue is reached while avoiding @@ -762,8 +794,7 @@ public: * keystore implementation * Generate a new key */ - CPubKey GenerateNewKey(); - void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret); + CPubKey GenerateNewKey(bool internal = false); //! Adds a key to the store, and saves it to disk. bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; //! Adds a key to the store, without saving it to disk (used by LoadWallet) @@ -871,11 +902,12 @@ public: static CAmount GetRequiredFee(unsigned int nTxBytes); bool NewKeyPool(); + size_t KeypoolCountExternalKeys(); bool TopUpKeyPool(unsigned int kpSize = 0); - void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool); + void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal); void KeepKey(int64_t nIndex); void ReturnKey(int64_t nIndex); - bool GetKeyFromPool(CPubKey &key); + bool GetKeyFromPool(CPubKey &key, bool internal = false); int64_t GetOldestKeyPoolTime(); void GetAllReserveKeys(std::set<CKeyID>& setAddress) const; @@ -1015,16 +1047,18 @@ public: /* Set the HD chain model (chain child index counters) */ bool SetHDChain(const CHDChain& chain, bool memonly); - const CHDChain& GetHDChain() { return hdChain; } + const CHDChain& GetHDChain() const { return hdChain; } /* Returns true if HD is enabled */ - bool IsHDEnabled(); + bool IsHDEnabled() const; /* Generates a new HD master key (will not be activated) */ CPubKey GenerateNewHDMasterKey(); - /* Set the current HD master key (will reset the chain child index counters) */ - bool SetHDMasterKey(const CPubKey& key); + /* Set the current HD master key (will reset the chain child index counters) + If possibleOldChain is provided, the parameters from the old chain (version) + will be preserved. */ + bool SetHDMasterKey(const CPubKey& key, CHDChain *possibleOldChain = nullptr); }; /** A key allocated from the key pool. */ @@ -1051,7 +1085,7 @@ public: } void ReturnKey(); - bool GetReservedKey(CPubKey &pubkey); + bool GetReservedKey(CPubKey &pubkey, bool internal = false); void KeepKey(); void KeepScript() { KeepKey(); } }; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 5ba9f150a8..d017965385 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -22,8 +22,6 @@ #include <boost/foreach.hpp> #include <boost/thread.hpp> -using namespace std; - static uint64_t nAccountingEntryNumber = 0; static std::atomic<unsigned int> nWalletDBUpdateCounter; @@ -32,30 +30,30 @@ static std::atomic<unsigned int> nWalletDBUpdateCounter; // CWalletDB // -bool CWalletDB::WriteName(const string& strAddress, const string& strName) +bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName) { nWalletDBUpdateCounter++; - return Write(make_pair(string("name"), strAddress), strName); + return Write(make_pair(std::string("name"), strAddress), strName); } -bool CWalletDB::EraseName(const string& strAddress) +bool CWalletDB::EraseName(const std::string& strAddress) { // This should only be used for sending addresses, never for receiving addresses, // receiving addresses must always have an address book entry if they're not change return. nWalletDBUpdateCounter++; - return Erase(make_pair(string("name"), strAddress)); + return Erase(make_pair(std::string("name"), strAddress)); } -bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose) +bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose) { nWalletDBUpdateCounter++; - return Write(make_pair(string("purpose"), strAddress), strPurpose); + return Write(make_pair(std::string("purpose"), strAddress), strPurpose); } -bool CWalletDB::ErasePurpose(const string& strPurpose) +bool CWalletDB::ErasePurpose(const std::string& strPurpose) { nWalletDBUpdateCounter++; - return Erase(make_pair(string("purpose"), strPurpose)); + return Erase(make_pair(std::string("purpose"), strPurpose)); } bool CWalletDB::WriteTx(const CWalletTx& wtx) @@ -183,15 +181,15 @@ bool CWalletDB::WriteMinVersion(int nVersion) return Write(std::string("minversion"), nVersion); } -bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account) +bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account) { account.SetNull(); - return Read(make_pair(string("acc"), strAccount), account); + return Read(make_pair(std::string("acc"), strAccount), account); } -bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) +bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account) { - return Write(make_pair(string("acc"), strAccount), account); + return Write(make_pair(std::string("acc"), strAccount), account); } bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry) @@ -204,9 +202,9 @@ bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry) return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } -CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount) +CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount) { - list<CAccountingEntry> entries; + std::list<CAccountingEntry> entries; ListAccountCreditDebit(strAccount, entries); CAmount nCreditDebit = 0; @@ -216,20 +214,20 @@ CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount) return nCreditDebit; } -void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries) +void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries) { bool fAllAccounts = (strAccount == "*"); Dbc* pcursor = GetCursor(); if (!pcursor) - throw runtime_error(std::string(__func__) + ": cannot create DB cursor"); + throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor"); bool setRange = true; while (true) { // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (setRange) - ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0))); + ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0))); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, setRange); setRange = false; @@ -238,11 +236,11 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin else if (ret != 0) { pcursor->close(); - throw runtime_error(std::string(__func__) + ": error scanning DB"); + throw std::runtime_error(std::string(__func__) + ": error scanning DB"); } // Unserialize - string strType; + std::string strType; ssKey >> strType; if (strType != "acentry") break; @@ -268,7 +266,7 @@ public: bool fIsEncrypted; bool fAnyUnordered; int nFileVersion; - vector<uint256> vWalletUpgrade; + std::vector<uint256> vWalletUpgrade; CWalletScanState() { nKeys = nCKeys = nWatchKeys = nKeyMeta = 0; @@ -280,7 +278,7 @@ public: bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, - CWalletScanState &wss, string& strType, string& strErr) + CWalletScanState &wss, std::string& strType, std::string& strErr) { try { // Unserialize @@ -289,13 +287,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssKey >> strType; if (strType == "name") { - string strAddress; + std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name; } else if (strType == "purpose") { - string strAddress; + std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose; } @@ -336,7 +334,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "acentry") { - string strAccount; + std::string strAccount; ssKey >> strAccount; uint64_t nNumber; ssKey >> nNumber; @@ -449,7 +447,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: CPubKey corrupt"; return false; } - vector<unsigned char> vchPrivKey; + std::vector<unsigned char> vchPrivKey; ssValue >> vchPrivKey; wss.nCKeys++; @@ -562,7 +560,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) LOCK(pwallet->cs_wallet); try { int nMinVersion = 0; - if (Read((string)"minversion", nMinVersion)) + if (Read((std::string)"minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; @@ -592,7 +590,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) } // Try to be tolerant of single corrupt records: - string strType, strErr; + std::string strType, strErr; if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) { // losing keys is considered a catastrophic error, anything else @@ -659,14 +657,14 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) return result; } -DBErrors CWalletDB::FindWalletTx(vector<uint256>& vTxHash, vector<CWalletTx>& vWtx) +DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx) { bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; try { int nMinVersion = 0; - if (Read((string)"minversion", nMinVersion)) + if (Read((std::string)"minversion", nMinVersion)) { if (nMinVersion > CLIENT_VERSION) return DB_TOO_NEW; @@ -694,7 +692,7 @@ DBErrors CWalletDB::FindWalletTx(vector<uint256>& vTxHash, vector<CWalletTx>& vW return DB_CORRUPT; } - string strType; + std::string strType; ssKey >> strType; if (strType == "tx") { uint256 hash; @@ -722,11 +720,11 @@ DBErrors CWalletDB::FindWalletTx(vector<uint256>& vTxHash, vector<CWalletTx>& vW return result; } -DBErrors CWalletDB::ZapSelectTx(vector<uint256>& vTxHashIn, vector<uint256>& vTxHashOut) +DBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut) { // build list of wallet TXs and hashes - vector<uint256> vTxHash; - vector<CWalletTx> vWtx; + std::vector<uint256> vTxHash; + std::vector<CWalletTx> vWtx; DBErrors err = FindWalletTx(vTxHash, vWtx); if (err != DB_LOAD_OK) { return err; @@ -737,7 +735,7 @@ DBErrors CWalletDB::ZapSelectTx(vector<uint256>& vTxHashIn, vector<uint256>& vTx // erase each matching wallet TX bool delerror = false; - vector<uint256>::iterator it = vTxHashIn.begin(); + std::vector<uint256>::iterator it = vTxHashIn.begin(); BOOST_FOREACH (uint256 hash, vTxHash) { while (it < vTxHashIn.end() && (*it) < hash) { it++; @@ -760,10 +758,10 @@ DBErrors CWalletDB::ZapSelectTx(vector<uint256>& vTxHashIn, vector<uint256>& vTx return DB_LOAD_OK; } -DBErrors CWalletDB::ZapWalletTx(vector<CWalletTx>& vWtx) +DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx) { // build list of wallet TXs - vector<uint256> vTxHash; + std::vector<uint256> vTxHash; DBErrors err = FindWalletTx(vTxHash, vWtx); if (err != DB_LOAD_OK) return err; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 4d7dfb727e..271c1d66c9 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -46,9 +46,12 @@ class CHDChain { public: uint32_t nExternalChainCounter; + uint32_t nInternalChainCounter; CKeyID masterKeyID; //!< master key hash160 - static const int CURRENT_VERSION = 1; + static const int VERSION_HD_BASE = 1; + static const int VERSION_HD_CHAIN_SPLIT = 2; + static const int CURRENT_VERSION = VERSION_HD_CHAIN_SPLIT; int nVersion; CHDChain() { SetNull(); } @@ -59,12 +62,15 @@ public: READWRITE(this->nVersion); READWRITE(nExternalChainCounter); READWRITE(masterKeyID); + if (this->nVersion >= VERSION_HD_CHAIN_SPLIT) + READWRITE(nInternalChainCounter); } void SetNull() { nVersion = CHDChain::CURRENT_VERSION; nExternalChainCounter = 0; + nInternalChainCounter = 0; masterKeyID.SetNull(); } }; diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index caca1248a1..4e13cbcaf4 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -30,6 +30,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...) if (rc != 0) { zmqError("Unable to initialize ZMQ msg"); + va_end(args); return -1; } @@ -43,6 +44,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...) { zmqError("Unable to send ZMQ msg"); zmq_msg_close(&msg); + va_end(args); return -1; } @@ -53,6 +55,7 @@ static int zmq_send_multipart(void *sock, const void* data, size_t size, ...) size = va_arg(args, size_t); } + va_end(args); return 0; } diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..dec8db960d --- /dev/null +++ b/test/README.md @@ -0,0 +1,97 @@ +This directory contains integration tests that test bitcoind and its +utilities in their entirety. It does not contain unit tests, which +can be found in [/src/test](/src/test), [/src/wallet/test](/src/wallet/test), +etc. + +There are currently two sets of tests in this directory: + +- [functional](/test/functional) which test the functionality of +bitcoind and bitcoin-qt by interacting with them through the RPC and P2P +interfaces. +- [util](test/util) which tests the bitcoin utilities, currently only +bitcoin-tx. + +The util tests are run as part of `make check` target. The functional +tests are run by the travis continuous build process whenever a pull +request is opened. Both sets of tests can also be run locally. + +Functional Test dependencies +============================ +The ZMQ functional test requires a python ZMQ library. To install it: + +- on Unix, run `sudo apt-get install python3-zmq` +- on mac OS, run `pip3 install pyzmq` + +Running tests locally +===================== + +Functional tests +---------------- + +You can run any single test by calling + + test/functional/test_runner.py <testname> + +Or you can run any combination of tests by calling + + test/functional/test_runner.py <testname1> <testname2> <testname3> ... + +Run the regression test suite with + + test/functional/test_runner.py + +Run all possible tests with + + test/functional/test_runner.py --extended + +By default, tests will be run in parallel. To specify how many jobs to run, +append `--jobs=n` (default n=4). + +If you want to create a basic coverage report for the RPC test suite, append `--coverage`. + +Possible options, which apply to each individual test run: + +``` + -h, --help show this help message and exit + --nocleanup Leave bitcoinds and test.* datadir on exit or error + --noshutdown Don't stop bitcoinds after the test execution + --srcdir=SRCDIR Source directory containing bitcoind/bitcoin-cli + (default: ../../src) + --tmpdir=TMPDIR Root directory for datadirs + --tracerpc Print out all RPC calls as they are made + --coveragedir=COVERAGEDIR + Write tested RPC commands into this directory +``` + +If you set the environment variable `PYTHON_DEBUG=1` you will get some debug +output (example: `PYTHON_DEBUG=1 test/functional/test_runner.py wallet`). + +A 200-block -regtest blockchain and wallets for four nodes +is created the first time a regression test is run and +is stored in the cache/ directory. Each node has 25 mature +blocks (25*50=1250 BTC) in its wallet. + +After the first run, the cache/ blockchain and wallets are +copied into a temporary directory and used as the initial +test state. + +If you get into a bad state, you should be able +to recover with: + +```bash +rm -rf cache +killall bitcoind +``` + +Util tests +---------- + +Util tests can be run locally by running `test/util/bitcoin-util-test.py`. +Use the `-v` option for verbose output. + +Writing functional tests +======================== + +You are encouraged to write functional tests for new or existing features. +Further information about the functional test framework and individual +tests is found in [test/functional](/test/functional). diff --git a/qa/rpc-tests/.gitignore b/test/functional/.gitignore index cb41d94423..cb41d94423 100644 --- a/qa/rpc-tests/.gitignore +++ b/test/functional/.gitignore diff --git a/qa/rpc-tests/README.md b/test/functional/README.md index 651b01f18a..651b01f18a 100644 --- a/qa/rpc-tests/README.md +++ b/test/functional/README.md diff --git a/qa/rpc-tests/abandonconflict.py b/test/functional/abandonconflict.py index 5a860e4392..887dbebd4f 100755 --- a/qa/rpc-tests/abandonconflict.py +++ b/test/functional/abandonconflict.py @@ -23,8 +23,8 @@ class AbandonConflictTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-logtimemicros"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"])) + self.nodes.append(start_node(1, self.options.tmpdir)) connect_nodes(self.nodes[0], 1) def run_test(self): @@ -81,7 +81,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Restart the node with a higher min relay fee so the parent tx is no longer in mempool # TODO: redo with eviction stop_node(self.nodes[0],0) - self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"]) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) # Verify txs no longer in mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) @@ -107,7 +107,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned stop_node(self.nodes[0],0) - self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.00001"]) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) @@ -127,7 +127,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Remove using high relay fee again stop_node(self.nodes[0],0) - self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"]) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("24.9996")) @@ -158,9 +158,9 @@ class AbandonConflictTest(BitcoinTestFramework): self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) newbalance = self.nodes[0].getbalance() #assert_equal(newbalance, balance - Decimal("10")) - print("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer") - print("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") - print(str(balance) + " -> " + str(newbalance) + " ?") + self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer") + self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") + self.log.info(str(balance) + " -> " + str(newbalance) + " ?") if __name__ == '__main__': AbandonConflictTest().main() diff --git a/qa/rpc-tests/assumevalid.py b/test/functional/assumevalid.py index b8dafff161..a9c2b17b4a 100755 --- a/qa/rpc-tests/assumevalid.py +++ b/test/functional/assumevalid.py @@ -15,7 +15,7 @@ transactions: 2-101: bury that block with 100 blocks so the coinbase transaction output can be spent 102: a block containing a transaction spending the coinbase - transaction output. The transaction has an invalid signature. + transaction output. The transaction has an invalid signature. 103-2202: bury the bad block with just over two weeks' worth of blocks (2100 blocks) @@ -29,40 +29,31 @@ Start three nodes: block 200. node2 will reject block 102 since it's assumed valid, but it isn't buried by at least two weeks' work. """ +import time -from test_framework.mininode import * -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * -from test_framework.blocktools import create_block, create_coinbase +from test_framework.blocktools import (create_block, create_coinbase) from test_framework.key import CECKey -from test_framework.script import * - -class BaseNode(SingleNodeConnCB): - def __init__(self): - SingleNodeConnCB.__init__(self) - self.last_inv = None - self.last_headers = None - self.last_block = None - self.last_getdata = None - self.block_announced = False - self.last_getheaders = None - self.disconnected = False - self.last_blockhash_announced = None - - def on_close(self, conn): - self.disconnected = True - - def wait_for_disconnect(self, timeout=60): - test_function = lambda: self.disconnected - assert(wait_until(test_function, timeout=timeout)) - return +from test_framework.mininode import (CBlockHeader, + COutPoint, + CTransaction, + CTxIn, + CTxOut, + NetworkThread, + NodeConn, + NodeConnCB, + msg_block, + msg_headers) +from test_framework.script import (CScript, OP_TRUE) +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import (start_node, p2p_port, assert_equal) +class BaseNode(NodeConnCB): def send_header_for_blocks(self, new_blocks): headers_message = msg_headers() - headers_message.headers = [ CBlockHeader(b) for b in new_blocks ] + headers_message.headers = [CBlockHeader(b) for b in new_blocks] self.send_message(headers_message) -class SendHeadersTest(BitcoinTestFramework): +class AssumeValidTest(BitcoinTestFramework): def __init__(self): super().__init__() self.setup_clean_chain = True @@ -72,8 +63,34 @@ class SendHeadersTest(BitcoinTestFramework): # Start node0. We don't start the other nodes yet since # we need to pre-mine a block with an invalid transaction # signature so we can pass in the block hash as assumevalid. - self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) + self.nodes = [start_node(0, self.options.tmpdir)] + + def send_blocks_until_disconnected(self, node): + """Keep sending blocks to the node until we're disconnected.""" + for i in range(len(self.blocks)): + try: + node.send_message(msg_block(self.blocks[i])) + except IOError as e: + assert str(e) == 'Not connected, no pushbuf' + break + + def assert_blockchain_height(self, node, height): + """Wait until the blockchain is no longer advancing and verify it's reached the expected height.""" + last_height = node.getblock(node.getbestblockhash())['height'] + timeout = 10 + while True: + time.sleep(0.25) + current_height = node.getblock(node.getbestblockhash())['height'] + if current_height != last_height: + last_height = current_height + if timeout < 0: + assert False, "blockchain too short after timeout: %d" % current_height + timeout - 0.25 + continue + elif current_height > height: + assert False, "blockchain too long: %d" % current_height + elif current_height == height: + break def run_test(self): @@ -83,7 +100,7 @@ class SendHeadersTest(BitcoinTestFramework): connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], node0)) node0.add_connection(connections[0]) - NetworkThread().start() # Start up network handling in another thread + NetworkThread().start() # Start up network handling in another thread node0.wait_for_verack() # Build the blockchain @@ -120,7 +137,7 @@ class SendHeadersTest(BitcoinTestFramework): # Create a transaction spending the coinbase output with an invalid (null) signature tx = CTransaction() tx.vin.append(CTxIn(COutPoint(self.block1.vtx[0].sha256, 0), scriptSig=b"")) - tx.vout.append(CTxOut(49*100000000, CScript([OP_TRUE]))) + tx.vout.append(CTxOut(49 * 100000000, CScript([OP_TRUE]))) tx.calc_sha256() block102 = create_block(self.tip, create_coinbase(height), self.block_time) @@ -146,14 +163,14 @@ class SendHeadersTest(BitcoinTestFramework): # Start node1 and node2 with assumevalid so they accept a block with a bad signature. self.nodes.append(start_node(1, self.options.tmpdir, - ["-debug", "-assumevalid=" + hex(block102.sha256)])) + ["-assumevalid=" + hex(block102.sha256)])) node1 = BaseNode() # connects to node1 connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1)) node1.add_connection(connections[1]) node1.wait_for_verack() self.nodes.append(start_node(2, self.options.tmpdir, - ["-debug", "-assumevalid=" + hex(block102.sha256)])) + ["-assumevalid=" + hex(block102.sha256)])) node2 = BaseNode() # connects to node2 connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2)) node2.add_connection(connections[2]) @@ -166,25 +183,19 @@ class SendHeadersTest(BitcoinTestFramework): node1.send_header_for_blocks(self.blocks[2000:]) node2.send_header_for_blocks(self.blocks[0:200]) - # Send 102 blocks to node0. Block 102 will be rejected. - for i in range(101): - node0.send_message(msg_block(self.blocks[i])) - node0.sync_with_ping() # make sure the most recent block is synced - node0.send_message(msg_block(self.blocks[101])) - assert_equal(self.nodes[0].getblock(self.nodes[0].getbestblockhash())['height'], 101) + # Send blocks to node0. Block 102 will be rejected. + self.send_blocks_until_disconnected(node0) + self.assert_blockchain_height(self.nodes[0], 101) - # Send 3102 blocks to node1. All blocks will be accepted. + # Send all blocks to node1. All blocks will be accepted. for i in range(2202): node1.send_message(msg_block(self.blocks[i])) - node1.sync_with_ping() # make sure the most recent block is synced + node1.sync_with_ping() # make sure the most recent block is synced assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202) - # Send 102 blocks to node2. Block 102 will be rejected. - for i in range(101): - node2.send_message(msg_block(self.blocks[i])) - node2.sync_with_ping() # make sure the most recent block is synced - node2.send_message(msg_block(self.blocks[101])) - assert_equal(self.nodes[2].getblock(self.nodes[2].getbestblockhash())['height'], 101) + # Send blocks to node2. Block 102 will be rejected. + self.send_blocks_until_disconnected(node2) + self.assert_blockchain_height(self.nodes[2], 101) if __name__ == '__main__': - SendHeadersTest().main() + AssumeValidTest().main() diff --git a/qa/rpc-tests/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index ea9c3d73ab..63d05e8fc9 100755 --- a/qa/rpc-tests/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -43,7 +43,7 @@ class BIP65Test(ComparisonTestFramework): def setup_network(self): # Must set the blockversion for this test self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=3']], + extra_args=[['-whitelist=127.0.0.1', '-blockversion=3']], binary=[self.options.testbinary]) def run_test(self): diff --git a/qa/rpc-tests/bip65-cltv.py b/test/functional/bip65-cltv.py index c9d02a98f3..7f13bb9952 100755 --- a/qa/rpc-tests/bip65-cltv.py +++ b/test/functional/bip65-cltv.py @@ -69,12 +69,8 @@ class BIP65Test(BitcoinTestFramework): if (self.nodes[0].getblockcount() != cnt + 1051): raise AssertionError("Failed to mine a version=4 block") - # Mine 1 old-version blocks - try: - self.nodes[1].generate(1) - raise AssertionError("Succeeded to mine a version=3 block after 950 version=4 blocks") - except JSONRPCException: - pass + # Mine 1 old-version blocks. This should fail + assert_raises_jsonrpc(-1,"CreateNewBlock: TestBlockValidity failed: bad-version(0x00000003)", self.nodes[1].generate, 1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 1051): raise AssertionError("Accepted a version=3 block after 950 version=4 blocks") diff --git a/qa/rpc-tests/bip68-112-113-p2p.py b/test/functional/bip68-112-113-p2p.py index 836267ea7f..0867f42585 100755 --- a/qa/rpc-tests/bip68-112-113-p2p.py +++ b/test/functional/bip68-112-113-p2p.py @@ -99,7 +99,7 @@ class BIP68_112_113Test(ComparisonTestFramework): def setup_network(self): # Must set the blockversion for this test self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=4']], + extra_args=[['-whitelist=127.0.0.1', '-blockversion=4']], binary=[self.options.testbinary]) def run_test(self): diff --git a/qa/rpc-tests/bip68-sequence.py b/test/functional/bip68-sequence.py index 3fe3b471f9..89d42a710c 100755 --- a/qa/rpc-tests/bip68-sequence.py +++ b/test/functional/bip68-sequence.py @@ -24,8 +24,8 @@ class BIP68Test(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-acceptnonstdtxn=0"])) + self.nodes.append(start_node(0, self.options.tmpdir)) + self.nodes.append(start_node(1, self.options.tmpdir, ["-acceptnonstdtxn=0"])) self.is_network_split = False self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] connect_nodes(self.nodes[0], 1) @@ -34,26 +34,26 @@ class BIP68Test(BitcoinTestFramework): # Generate some coins self.nodes[0].generate(110) - print("Running test disable flag") + self.log.info("Running test disable flag") self.test_disable_flag() - print("Running test sequence-lock-confirmed-inputs") + self.log.info("Running test sequence-lock-confirmed-inputs") self.test_sequence_lock_confirmed_inputs() - print("Running test sequence-lock-unconfirmed-inputs") + self.log.info("Running test sequence-lock-unconfirmed-inputs") self.test_sequence_lock_unconfirmed_inputs() - print("Running test BIP68 not consensus before versionbits activation") + self.log.info("Running test BIP68 not consensus before versionbits activation") self.test_bip68_not_consensus() - print("Activating BIP68 (and 112/113)") + self.log.info("Activating BIP68 (and 112/113)") self.activateCSV() - print("Verifying nVersion=2 transactions are standard.") - print("Note that with current versions of bitcoin software, nVersion=2 transactions are always standard (independent of BIP68 activation status).") + self.log.info("Verifying nVersion=2 transactions are standard.") + self.log.info("Note that nVersion=2 transactions are always standard (independent of BIP68 activation status).") self.test_version2_relay() - print("Passed\n") + self.log.info("Passed") # Test that BIP68 is not in effect if tx version is 1, or if # the first sequence bit is set. @@ -90,12 +90,7 @@ class BIP68Test(BitcoinTestFramework): tx2.vout = [CTxOut(int(value-self.relayfee*COIN), CScript([b'a']))] tx2.rehash() - try: - self.nodes[0].sendrawtransaction(ToHex(tx2)) - except JSONRPCException as exp: - assert_equal(exp.error["message"], NOT_FINAL_ERROR) - else: - assert(False) + assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2)) # Setting the version back down to 1 should disable the sequence lock, # so this should be accepted. @@ -190,14 +185,12 @@ class BIP68Test(BitcoinTestFramework): tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a']))) rawtx = self.nodes[0].signrawtransaction(ToHex(tx))["hex"] - try: - self.nodes[0].sendrawtransaction(rawtx) - except JSONRPCException as exp: - assert(not should_pass and using_sequence_locks) - assert_equal(exp.error["message"], NOT_FINAL_ERROR) + if (using_sequence_locks and not should_pass): + # This transaction should be rejected + assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, rawtx) else: - assert(should_pass or not using_sequence_locks) - # Recalculate utxos if we successfully sent the transaction + # This raw transaction should be accepted + self.nodes[0].sendrawtransaction(rawtx) utxos = self.nodes[0].listunspent() # Test that sequence locks on unconfirmed inputs must have nSequence @@ -239,14 +232,13 @@ class BIP68Test(BitcoinTestFramework): tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee*COIN), CScript([b'a']))] tx.rehash() - try: - node.sendrawtransaction(ToHex(tx)) - except JSONRPCException as exp: - assert_equal(exp.error["message"], NOT_FINAL_ERROR) - assert(orig_tx.hash in node.getrawmempool()) + if (orig_tx.hash in node.getrawmempool()): + # sendrawtransaction should fail if the tx is in the mempool + assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, node.sendrawtransaction, ToHex(tx)) else: - # orig_tx must not be in mempool - assert(orig_tx.hash not in node.getrawmempool()) + # sendrawtransaction should succeed if the tx is not in the mempool + node.sendrawtransaction(ToHex(tx)) + return tx test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=True) @@ -295,12 +287,7 @@ class BIP68Test(BitcoinTestFramework): tx5.vout[0].nValue += int(utxos[0]["amount"]*COIN) raw_tx5 = self.nodes[0].signrawtransaction(ToHex(tx5))["hex"] - try: - self.nodes[0].sendrawtransaction(raw_tx5) - except JSONRPCException as exp: - assert_equal(exp.error["message"], NOT_FINAL_ERROR) - else: - assert(False) + assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, raw_tx5) # Test mempool-BIP68 consistency after reorg # @@ -373,12 +360,7 @@ class BIP68Test(BitcoinTestFramework): tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))] tx3.rehash() - try: - self.nodes[0].sendrawtransaction(ToHex(tx3)) - except JSONRPCException as exp: - assert_equal(exp.error["message"], NOT_FINAL_ERROR) - else: - assert(False) + assert_raises_jsonrpc(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3)) # make a block that violates bip68; ensure that the tip updates tip = int(self.nodes[0].getbestblockhash(), 16) @@ -396,8 +378,8 @@ class BIP68Test(BitcoinTestFramework): # activation should happen at block height 432 (3 periods) min_activation_height = 432 height = self.nodes[0].getblockcount() - assert(height < 432) - self.nodes[0].generate(432-height) + assert(height < min_activation_height) + self.nodes[0].generate(min_activation_height-height) assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') sync_blocks(self.nodes) diff --git a/qa/rpc-tests/bip9-softforks.py b/test/functional/bip9-softforks.py index 70d4be3f69..0dffd06e1a 100755 --- a/qa/rpc-tests/bip9-softforks.py +++ b/test/functional/bip9-softforks.py @@ -35,7 +35,7 @@ class BIP9SoftForksTest(ComparisonTestFramework): def setup_network(self): self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1']], + extra_args=[['-whitelist=127.0.0.1']], binary=[self.options.testbinary]) def run_test(self): diff --git a/qa/rpc-tests/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index b82ef89395..22bd39fbe5 100755 --- a/qa/rpc-tests/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -50,7 +50,7 @@ class BIP66Test(ComparisonTestFramework): def setup_network(self): # Must set the blockversion for this test self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1', '-blockversion=2']], + extra_args=[['-whitelist=127.0.0.1', '-blockversion=2']], binary=[self.options.testbinary]) def run_test(self): diff --git a/qa/rpc-tests/bipdersig.py b/test/functional/bipdersig.py index fa54bc2749..371cc41bb7 100755 --- a/qa/rpc-tests/bipdersig.py +++ b/test/functional/bipdersig.py @@ -68,12 +68,8 @@ class BIP66Test(BitcoinTestFramework): if (self.nodes[0].getblockcount() != cnt + 1051): raise AssertionError("Failed to mine a version=3 block") - # Mine 1 old-version blocks - try: - self.nodes[1].generate(1) - raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks") - except JSONRPCException: - pass + # Mine 1 old-version blocks. This should fail + assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed: bad-version(0x00000002)", self.nodes[1].generate, 1) self.sync_all() if (self.nodes[0].getblockcount() != cnt + 1051): raise AssertionError("Accepted a version=2 block after 950 version=3 blocks") diff --git a/qa/rpc-tests/blockchain.py b/test/functional/blockchain.py index 67b5826840..596aed50ec 100755 --- a/qa/rpc-tests/blockchain.py +++ b/test/functional/blockchain.py @@ -14,10 +14,9 @@ Tests correspond to code in rpc/blockchain.cpp. from decimal import Decimal from test_framework.test_framework import BitcoinTestFramework -from test_framework.authproxy import JSONRPCException from test_framework.util import ( assert_equal, - assert_raises, + assert_raises_jsonrpc, assert_is_hex_string, assert_is_hash_string, start_nodes, @@ -58,8 +57,7 @@ class BlockchainTest(BitcoinTestFramework): def _test_getblockheader(self): node = self.nodes[0] - assert_raises( - JSONRPCException, lambda: node.getblockheader('nonsense')) + assert_raises_jsonrpc(-5, "Block not found", node.getblockheader, "nonsense") besthash = node.getbestblockhash() secondbesthash = node.getblockhash(199) diff --git a/qa/rpc-tests/bumpfee.py b/test/functional/bumpfee.py index cc897a32c7..c51a75cc26 100755 --- a/qa/rpc-tests/bumpfee.py +++ b/test/functional/bumpfee.py @@ -2,7 +2,17 @@ # 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. -"""Test the bumpfee RPC.""" +"""Test the bumpfee RPC. + +Verifies that the bumpfee RPC creates replacement transactions successfully when +its preconditions are met, and returns appropriate errors in other cases. + +This module consists of around a dozen individual test cases implemented in the +top-level functions named as test_<test_case_description>. The test functions +can be disabled or reordered if needed for debugging. If new test cases are +added in the the future, they should try to follow the same convention and not +make assumptions about execution order. +""" from segwit import send_to_witness from test_framework.test_framework import BitcoinTestFramework @@ -26,7 +36,7 @@ class BumpFeeTest(BitcoinTestFramework): self.setup_clean_chain = True def setup_network(self, split=False): - extra_args = [["-debug", "-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] + extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] for i in range(self.num_nodes)] self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) @@ -45,7 +55,7 @@ class BumpFeeTest(BitcoinTestFramework): rbf_node_address = rbf_node.getnewaddress() # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis) - print("Mining blocks...") + self.log.info("Mining blocks...") peer_node.generate(110) self.sync_all() for i in range(25): @@ -55,26 +65,26 @@ class BumpFeeTest(BitcoinTestFramework): self.sync_all() assert_equal(rbf_node.getbalance(), Decimal("0.025")) - print("Running tests") + self.log.info("Running tests") dest_address = peer_node.getnewaddress() - test_small_output_fails(rbf_node, dest_address) - test_dust_to_fee(rbf_node, dest_address) test_simple_bumpfee_succeeds(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) test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address) + test_small_output_fails(rbf_node, dest_address) + test_dust_to_fee(rbf_node, dest_address) test_settxfee(rbf_node, dest_address) test_rebumping(rbf_node, dest_address) test_rebumping_not_replaceable(rbf_node, dest_address) test_unconfirmed_not_spendable(rbf_node, rbf_node_address) test_bumpfee_metadata(rbf_node, dest_address) test_locked_wallet_fails(rbf_node, dest_address) - print("Success") + self.log.info("Success") def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address): - rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) + rbfid = spend_one_input(rbf_node, dest_address) rbftx = rbf_node.gettransaction(rbfid) sync_mempools((rbf_node, peer_node)) assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() @@ -102,7 +112,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address): segwit_out = rbf_node.validateaddress(rbf_node.getnewaddress()) rbf_node.addwitnessaddress(segwit_out["address"]) segwitid = send_to_witness( - version=0, + use_p2wsh=False, node=rbf_node, utxo=segwit_in, pubkey=segwit_out["pubkey"], @@ -115,7 +125,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address): 'vout': 0, "sequence": BIP125_SEQUENCE_NUMBER }], {dest_address: Decimal("0.0005"), - get_change_address(rbf_node): Decimal("0.0003")}) + rbf_node.getrawchangeaddress(): Decimal("0.0003")}) rbfsigned = rbf_node.signrawtransaction(rbfraw) rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"]) assert rbfid in rbf_node.getrawmempool() @@ -127,8 +137,8 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address): def test_nonrbf_bumpfee_fails(peer_node, dest_address): # cannot replace a non RBF transaction (from node which did not enable RBF) - not_rbfid = create_fund_sign_send(peer_node, {dest_address: 0.00090000}) - assert_raises_message(JSONRPCException, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) + not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000")) + assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): @@ -148,82 +158,73 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): signedtx = rbf_node.signrawtransaction(rawtx) signedtx = peer_node.signrawtransaction(signedtx["hex"]) rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) - assert_raises_message(JSONRPCException, "Transaction contains inputs that don't belong to this wallet", + assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet", rbf_node.bumpfee, rbfid) def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address): # cannot bump fee if the transaction has a descendant # parent is send-to-self, so we don't have to check which output is change when creating the child tx - parent_id = create_fund_sign_send(rbf_node, {rbf_node_address: 0.00050000}) + parent_id = spend_one_input(rbf_node, rbf_node_address) tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000}) tx = rbf_node.signrawtransaction(tx) txid = rbf_node.sendrawtransaction(tx["hex"]) - assert_raises_message(JSONRPCException, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) + assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) def test_small_output_fails(rbf_node, dest_address): # cannot bump fee with a too-small output - rbfid = spend_one_input(rbf_node, - Decimal("0.00100000"), - {dest_address: 0.00080000, - get_change_address(rbf_node): Decimal("0.00010000")}) - rbf_node.bumpfee(rbfid, {"totalFee": 20000}) + rbfid = spend_one_input(rbf_node, dest_address) + rbf_node.bumpfee(rbfid, {"totalFee": 50000}) - rbfid = spend_one_input(rbf_node, - Decimal("0.00100000"), - {dest_address: 0.00080000, - get_change_address(rbf_node): Decimal("0.00010000")}) - assert_raises_message(JSONRPCException, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001}) + rbfid = spend_one_input(rbf_node, dest_address) + assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001}) def test_dust_to_fee(rbf_node, dest_address): # check that if output is reduced to dust, it will be converted to fee - # the bumped tx sets fee=9900, but it converts to 10,000 - rbfid = spend_one_input(rbf_node, - Decimal("0.00100000"), - {dest_address: 0.00080000, - get_change_address(rbf_node): Decimal("0.00010000")}) + # the bumped tx sets fee=49,900, but it converts to 50,000 + rbfid = spend_one_input(rbf_node, dest_address) fulltx = rbf_node.getrawtransaction(rbfid, 1) - bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 19900}) + bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 49900}) full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1) - assert_equal(bumped_tx["fee"], Decimal("0.00020000")) + assert_equal(bumped_tx["fee"], Decimal("0.00050000")) assert_equal(len(fulltx["vout"]), 2) assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated def test_settxfee(rbf_node, dest_address): # check that bumpfee reacts correctly to the use of settxfee (paytxfee) - # increase feerate by 2.5x, test that fee increased at least 2x - rbf_node.settxfee(Decimal("0.00001000")) - rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) - rbftx = rbf_node.gettransaction(rbfid) - rbf_node.settxfee(Decimal("0.00002500")) + rbfid = spend_one_input(rbf_node, dest_address) + requested_feerate = Decimal("0.00025000") + rbf_node.settxfee(requested_feerate) bumped_tx = rbf_node.bumpfee(rbfid) - assert bumped_tx["fee"] > 2 * abs(rbftx["fee"]) + actual_feerate = bumped_tx["fee"] * 1000 / rbf_node.getrawtransaction(bumped_tx["txid"], True)["size"] + # Assert that the difference between the requested feerate and the actual + # feerate of the bumped transaction is small. + assert_greater_than(Decimal("0.00001000"), abs(requested_feerate - actual_feerate)) rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee def test_rebumping(rbf_node, dest_address): # check that re-bumping the original tx fails, but bumping the bumper succeeds - rbf_node.settxfee(Decimal("0.00001000")) - rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) - bumped = rbf_node.bumpfee(rbfid, {"totalFee": 1000}) - assert_raises_message(JSONRPCException, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000}) - rbf_node.bumpfee(bumped["txid"], {"totalFee": 2000}) + rbfid = spend_one_input(rbf_node, dest_address) + bumped = rbf_node.bumpfee(rbfid, {"totalFee": 2000}) + assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000}) + rbf_node.bumpfee(bumped["txid"], {"totalFee": 3000}) def test_rebumping_not_replaceable(rbf_node, dest_address): # check that re-bumping a non-replaceable bump tx fails - rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) + rbfid = spend_one_input(rbf_node, dest_address) bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False}) - assert_raises_message(JSONRPCException, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], + assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], {"totalFee": 20000}) def test_unconfirmed_not_spendable(rbf_node, rbf_node_address): # check that unconfirmed outputs from bumped transactions are not spendable - rbfid = create_fund_sign_send(rbf_node, {rbf_node_address: 0.00090000}) + rbfid = spend_one_input(rbf_node, rbf_node_address) rbftx = rbf_node.gettransaction(rbfid)["hex"] assert rbfid in rbf_node.getrawmempool() bumpid = rbf_node.bumpfee(rbfid)["txid"] @@ -258,7 +259,7 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address): def test_bumpfee_metadata(rbf_node, dest_address): - rbfid = rbf_node.sendtoaddress(dest_address, 0.00090000, "comment value", "to value") + rbfid = rbf_node.sendtoaddress(dest_address, Decimal("0.00100000"), "comment value", "to value") bumped_tx = rbf_node.bumpfee(rbfid) bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"]) assert_equal(bumped_wtx["comment"], "comment value") @@ -266,43 +267,23 @@ def test_bumpfee_metadata(rbf_node, dest_address): def test_locked_wallet_fails(rbf_node, dest_address): - rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000}) + rbfid = spend_one_input(rbf_node, dest_address) rbf_node.walletlock() - assert_raises_message(JSONRPCException, "Please enter the wallet passphrase with walletpassphrase first.", + assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.", rbf_node.bumpfee, rbfid) -def create_fund_sign_send(node, outputs): - rawtx = node.createrawtransaction([], outputs) - fundtx = node.fundrawtransaction(rawtx) - signedtx = node.signrawtransaction(fundtx["hex"]) - txid = node.sendrawtransaction(signedtx["hex"]) - return txid - - -def spend_one_input(node, input_amount, outputs): - input = dict(sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == input_amount)) - rawtx = node.createrawtransaction([input], outputs) +def spend_one_input(node, dest_address): + 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")}) signedtx = node.signrawtransaction(rawtx) txid = node.sendrawtransaction(signedtx["hex"]) return txid -def get_change_address(node): - """Get a wallet change address. - - There is no wallet RPC to access unused change addresses, so this creates a - dummy transaction, calls fundrawtransaction to give add an input and change - output, then returns the change address.""" - dest_address = node.getnewaddress() - dest_amount = Decimal("0.00012345") - rawtx = node.createrawtransaction([], {dest_address: dest_amount}) - fundtx = node.fundrawtransaction(rawtx) - info = node.decoderawtransaction(fundtx["hex"]) - return next(address for out in info["vout"] - if out["value"] != dest_amount for address in out["scriptPubKey"]["addresses"]) - - def submit_block_with_tx(node, tx): ctx = CTransaction() ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx))) @@ -315,9 +296,7 @@ def submit_block_with_tx(node, tx): block.rehash() block.hashMerkleRoot = block.calc_merkle_root() block.solve() - error = node.submitblock(bytes_to_hex_str(block.serialize(True))) - if error is not None: - raise Exception(error) + node.submitblock(bytes_to_hex_str(block.serialize(True))) return block diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py new file mode 100755 index 0000000000..3ca74ea35e --- /dev/null +++ b/test/functional/combine_logs.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +"""Combine logs from multiple bitcoin nodes as well as the test_framework log. + +This streams the combined log output to stdout. Use combine_logs.py > outputfile +to write to an outputfile.""" + +import argparse +from collections import defaultdict, namedtuple +import heapq +import itertools +import os +import re +import sys + +# Matches on the date format at the start of the log event +TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{6}") + +LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event']) + +def main(): + """Main function. Parses args, reads the log files and renders them as text or html.""" + + parser = argparse.ArgumentParser(usage='%(prog)s [options] <test temporary directory>', description=__doc__) + parser.add_argument('-c', '--color', dest='color', action='store_true', help='outputs the combined log with events colored by source (requires posix terminal colors. Use less -r for viewing)') + parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2') + args, unknown_args = parser.parse_known_args() + + if args.color and os.name != 'posix': + print("Color output requires posix terminal colors.") + sys.exit(1) + + if args.html and args.color: + print("Only one out of --color or --html should be specified") + sys.exit(1) + + # There should only be one unknown argument - the path of the temporary test directory + if len(unknown_args) != 1: + print("Unexpected arguments" + str(unknown_args)) + sys.exit(1) + + log_events = read_logs(unknown_args[0]) + + print_logs(log_events, color=args.color, html=args.html) + +def read_logs(tmp_dir): + """Reads log files. + + Delegates to generator function get_log_events() to provide individual log events + for each of the input log files.""" + + files = [("test", "%s/test_framework.log" % tmp_dir)] + for i in itertools.count(): + logfile = "{}/node{}/regtest/debug.log".format(tmp_dir, i) + if not os.path.isfile(logfile): + break + files.append(("node%d" % i, logfile)) + + return heapq.merge(*[get_log_events(source, f) for source, f in files]) + +def get_log_events(source, logfile): + """Generator function that returns individual log events. + + Log events may be split over multiple lines. We use the timestamp + regex match as the marker for a new log event.""" + try: + with open(logfile, 'r') as infile: + event = '' + timestamp = '' + for line in infile: + # skip blank lines + if line == '\n': + continue + # if this line has a timestamp, it's the start of a new log event. + time_match = TIMESTAMP_PATTERN.match(line) + if time_match: + if event: + yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip()) + event = line + timestamp = time_match.group() + # if it doesn't have a timestamp, it's a continuation line of the previous log. + else: + event += "\n" + line + # Flush the final event + yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip()) + 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 + + for event in log_events: + print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, event.event, colors["reset"])) + + else: + try: + import jinja2 + except ImportError: + print("jinja2 not found. Try `pip install jinja2`") + sys.exit(1) + print(jinja2.Environment(loader=jinja2.FileSystemLoader('./')) + .get_template('combined_log_template.html') + .render(title="Combined Logs from testcase", log_events=[event._asdict() for event in log_events])) + +if __name__ == '__main__': + main() diff --git a/test/functional/combined_log_template.html b/test/functional/combined_log_template.html new file mode 100644 index 0000000000..c0b854b080 --- /dev/null +++ b/test/functional/combined_log_template.html @@ -0,0 +1,40 @@ +<html lang="en"> +<head> + <title> {{ title }} </title> + <style> + ul { + list-style-type: none; + font-family: monospace; + } + li { + border: 1px solid slategray; + margin-bottom: 1px; + } + li:hover { + filter: brightness(85%); + } + li.log-test { + background-color: cyan; + } + li.log-node0 { + background-color: lightblue; + } + li.log-node1 { + background-color: lightgreen; + } + li.log-node2 { + background-color: lightsalmon; + } + li.log-node3 { + background-color: lightyellow; + } + </style> +</head> +<body> +<ul> +{% for event in log_events %} +<li class="log-{{ event.source }}"> {{ event.source }} {{ event.timestamp }} {{event.event}}</li> +{% endfor %} +</ul> +</body> +</html> diff --git a/qa/pull-tester/tests_config.ini.in b/test/functional/config.ini.in index e3e457d0b1..29586c555d 100644 --- a/qa/pull-tester/tests_config.ini.in +++ b/test/functional/config.ini.in @@ -3,7 +3,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # These environment variables are set by the build process and read by -# rpc-tests.py +# test/functional/test_runner.py [environment] SRCDIR=@abs_top_srcdir@ diff --git a/qa/rpc-tests/create_cache.py b/test/functional/create_cache.py index 13eac92bbc..39c4c0f47e 100755 --- a/qa/rpc-tests/create_cache.py +++ b/test/functional/create_cache.py @@ -5,7 +5,7 @@ """Create a blockchain cache. Creating a cache of the blockchain speeds up test execution when running -multiple qa tests. This helper script is executed by rpc-tests when multiple +multiple functional tests. This helper script is executed by test_runner when multiple tests are being run in parallel. """ diff --git a/qa/rpc-tests/decodescript.py b/test/functional/decodescript.py index 5555e96c44..5555e96c44 100755 --- a/qa/rpc-tests/decodescript.py +++ b/test/functional/decodescript.py diff --git a/qa/rpc-tests/disablewallet.py b/test/functional/disablewallet.py index ff7121659b..2f729e19bf 100755 --- a/qa/rpc-tests/disablewallet.py +++ b/test/functional/disablewallet.py @@ -30,19 +30,10 @@ class DisableWalletTest (BitcoinTestFramework): x = self.nodes[0].validateaddress('mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') assert(x['isvalid'] == True) - # Checking mining to an address without a wallet - try: - self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') - except JSONRPCException as e: - assert("Invalid address" not in e.error['message']) - assert("ProcessNewBlock, block not accepted" not in e.error['message']) - assert("Couldn't create new block" not in e.error['message']) - - try: - self.nodes[0].generatetoaddress(1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') - raise AssertionError("Must not mine to invalid address!") - except JSONRPCException as e: - assert("Invalid address" in e.error['message']) + # Checking mining to an address without a wallet. Generating to a valid address should succeed + # but generating to an invalid address will fail. + self.nodes[0].generatetoaddress(1, 'mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ') + assert_raises_jsonrpc(-5, "Invalid address", self.nodes[0].generatetoaddress, 1, '3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy') if __name__ == '__main__': DisableWalletTest ().main () diff --git a/qa/rpc-tests/forknotify.py b/test/functional/forknotify.py index c2724ba5df..c2724ba5df 100755 --- a/qa/rpc-tests/forknotify.py +++ b/test/functional/forknotify.py diff --git a/qa/rpc-tests/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 7892e85e22..b86ea2d877 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -34,8 +34,6 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() def run_test(self): - print("Mining blocks...") - min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee'] # This test is not meant to test fee estimation and we'd like # to be sure all txs are sent at a consistent desired feerate @@ -182,12 +180,7 @@ class RawTransactionsTest(BitcoinTestFramework): dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) - try: - self.nodes[2].fundrawtransaction(rawtx, {'foo': 'bar'}) - raise AssertionError("Accepted invalid option foo") - except JSONRPCException as e: - assert("Unexpected key foo" in e.error['message']) - + assert_raises_jsonrpc(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'}) ############################################################ # test a fundrawtransaction with an invalid change address # @@ -200,12 +193,7 @@ class RawTransactionsTest(BitcoinTestFramework): dec_tx = self.nodes[2].decoderawtransaction(rawtx) assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) - try: - self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': 'foobar'}) - raise AssertionError("Accepted invalid bitcoin address") - except JSONRPCException as e: - assert("changeAddress must be a valid bitcoin address" in e.error['message']) - + assert_raises_jsonrpc(-5, "changeAddress must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'}) ############################################################ # test a fundrawtransaction with a provided change address # @@ -219,12 +207,7 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) change = self.nodes[2].getnewaddress() - try: - rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 2}) - except JSONRPCException as e: - assert('changePosition out of bounds' == e.error['message']) - else: - assert(False) + assert_raises_jsonrpc(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0}) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) out = dec_tx['vout'][0] @@ -333,19 +316,14 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) dec_tx = self.nodes[2].decoderawtransaction(rawtx) - try: - rawtxfund = self.nodes[2].fundrawtransaction(rawtx) - raise AssertionError("Spent more than available") - except JSONRPCException as e: - assert("Insufficient" in e.error['message']) - + assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].fundrawtransaction, rawtx) ############################################################ #compare fee of a standard pubkeyhash transaction inputs = [] outputs = {self.nodes[1].getnewaddress():1.1} - rawTx = self.nodes[0].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[0].fundrawtransaction(rawTx) + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1) @@ -360,8 +338,8 @@ class RawTransactionsTest(BitcoinTestFramework): #compare fee of a standard pubkeyhash transaction with multiple outputs inputs = [] outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3} - rawTx = self.nodes[0].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[0].fundrawtransaction(rawTx) + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendmany("", outputs) signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] @@ -386,8 +364,8 @@ class RawTransactionsTest(BitcoinTestFramework): inputs = [] outputs = {mSigObj:1.1} - rawTx = self.nodes[0].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[0].fundrawtransaction(rawTx) + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) @@ -419,8 +397,8 @@ class RawTransactionsTest(BitcoinTestFramework): inputs = [] outputs = {mSigObj:1.1} - rawTx = self.nodes[0].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[0].fundrawtransaction(rawTx) + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[0].sendtoaddress(mSigObj, 1.1) @@ -454,8 +432,8 @@ class RawTransactionsTest(BitcoinTestFramework): oldBalance = self.nodes[1].getbalance() inputs = [] outputs = {self.nodes[1].getnewaddress():1.1} - rawTx = self.nodes[2].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[2].fundrawtransaction(rawTx) + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[2].fundrawtransaction(rawtx) signedTx = self.nodes[2].signrawtransaction(fundedTx['hex']) txId = self.nodes[2].sendrawtransaction(signedTx['hex']) @@ -489,33 +467,27 @@ class RawTransactionsTest(BitcoinTestFramework): # drain the keypool self.nodes[1].getnewaddress() + self.nodes[1].getrawchangeaddress() inputs = [] outputs = {self.nodes[0].getnewaddress():1.1} - rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) # fund a transaction that requires a new key for the change output # creating the key must be impossible because the wallet is locked - try: - fundedTx = self.nodes[1].fundrawtransaction(rawTx) - raise AssertionError("Wallet unlocked without passphrase") - except JSONRPCException as e: - assert('Keypool ran out' in e.error['message']) + assert_raises_jsonrpc(-4, "Keypool ran out, please call keypoolrefill first", self.nodes[1].fundrawtransaction, rawtx) #refill the keypool self.nodes[1].walletpassphrase("test", 100) + self.nodes[1].keypoolrefill(8) #need to refill the keypool to get an internal change address self.nodes[1].walletlock() - try: - self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2) - raise AssertionError("Wallet unlocked without passphrase") - except JSONRPCException as e: - assert('walletpassphrase' in e.error['message']) + assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2) oldBalance = self.nodes[0].getbalance() inputs = [] outputs = {self.nodes[0].getnewaddress():1.1} - rawTx = self.nodes[1].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[1].fundrawtransaction(rawTx) + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawtx) #now we need to unlock self.nodes[1].walletpassphrase("test", 600) @@ -546,8 +518,8 @@ class RawTransactionsTest(BitcoinTestFramework): #fund a tx with ~20 small inputs inputs = [] outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} - rawTx = self.nodes[1].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[1].fundrawtransaction(rawTx) + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawtx) #create same transaction over sendtoaddress txId = self.nodes[1].sendmany("", outputs) @@ -578,8 +550,8 @@ class RawTransactionsTest(BitcoinTestFramework): inputs = [] outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} - rawTx = self.nodes[1].createrawtransaction(inputs, outputs) - fundedTx = self.nodes[1].fundrawtransaction(rawTx) + rawtx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawtx) fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex']) self.sync_all() @@ -674,7 +646,7 @@ class RawTransactionsTest(BitcoinTestFramework): if out['value'] > 1.0: changeaddress += out['scriptPubKey']['addresses'][0] assert(changeaddress != "") - nextaddr = self.nodes[3].getnewaddress() + nextaddr = self.nodes[3].getrawchangeaddress() # frt should not have removed the key from the keypool assert(changeaddress == nextaddr) @@ -721,7 +693,6 @@ class RawTransactionsTest(BitcoinTestFramework): inputs = [] outputs = {self.nodes[2].getnewaddress(): value for value in (1.0, 1.1, 1.2, 1.3)} - keys = list(outputs.keys()) rawtx = self.nodes[3].createrawtransaction(inputs, outputs) result = [self.nodes[3].fundrawtransaction(rawtx), diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index b73fea0695..bbe1dda5f7 100755 --- a/qa/rpc-tests/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -29,7 +29,7 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): self.setup_clean_chain = False def run_test(self): - print("Warning: this test will take about 70 seconds in the best case. Be patient.") + self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.") self.nodes[0].generate(10) templat = self.nodes[0].getblocktemplate() longpollid = templat['longpollid'] @@ -61,7 +61,9 @@ class GetBlockTemplateLPTest(BitcoinTestFramework): thr = LongpollThread(self.nodes[0]) thr.start() # generate a random transaction and submit it - (txid, txhex, fee) = random_transaction(self.nodes, Decimal("1.1"), Decimal("0.0"), Decimal("0.001"), 20) + min_relay_fee = self.nodes[0].getnetworkinfo()["relayfee"] + # min_relay_fee is fee per 1000 bytes, which should be more than enough. + (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()) diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/test/functional/getblocktemplate_proposals.py index 3b17dfcfb5..67745f77d1 100755 --- a/qa/rpc-tests/getblocktemplate_proposals.py +++ b/test/functional/getblocktemplate_proposals.py @@ -105,7 +105,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 3: Truncated final tx lastbyte = txlist[-1].pop() - assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a') + assert_raises_jsonrpc(-22, "Block decode failed", assert_template, node, tmpl, txlist, 'n/a') txlist[-1].append(lastbyte) # Test 4: Add an invalid tx to the end (duplicate of gen tx) @@ -126,7 +126,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): # Test 7: Bad tx count txlist.append(b'') - assert_raises(JSONRPCException, assert_template, node, tmpl, txlist, 'n/a') + assert_raises_jsonrpc(-22, 'Block decode failed', assert_template, node, tmpl, txlist, 'n/a') txlist.pop() # Test 8: Bad bits diff --git a/qa/rpc-tests/getchaintips.py b/test/functional/getchaintips.py index 14222334a6..14222334a6 100755 --- a/qa/rpc-tests/getchaintips.py +++ b/test/functional/getchaintips.py diff --git a/qa/rpc-tests/httpbasics.py b/test/functional/httpbasics.py index 8f35f0ab87..8f35f0ab87 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/test/functional/httpbasics.py diff --git a/qa/rpc-tests/import-rescan.py b/test/functional/import-rescan.py index 64e0eec61e..5be095e62d 100755 --- a/qa/rpc-tests/import-rescan.py +++ b/test/functional/import-rescan.py @@ -7,11 +7,11 @@ Test rescan behavior of importaddress, importpubkey, importprivkey, and importmulti RPCs with different types of keys and rescan options. -In the first part of the test, node 1 creates an address for each type of -import RPC call and node 0 sends BTC to it. Then other nodes import the -addresses, and the test makes listtransactions and getbalance calls to confirm -that the importing node either did or did not execute rescans picking up the -send transactions. +In the first part of the test, node 0 creates an address for each type of +import RPC call and sends BTC to it. Then other nodes import the addresses, +and the test makes listtransactions and getbalance calls to confirm that the +importing node either did or did not execute rescans picking up the send +transactions. In the second part of the test, node 0 sends more BTC to each address, and the test makes more listtransactions and getbalance calls to confirm that the @@ -22,7 +22,6 @@ happened previously. from test_framework.authproxy import JSONRPCException from test_framework.test_framework import BitcoinTestFramework from test_framework.util import (start_nodes, connect_nodes, sync_blocks, assert_equal, set_node_times) -from decimal import Decimal import collections import enum @@ -117,7 +116,7 @@ class ImportRescanTest(BitcoinTestFramework): self.num_nodes = 2 + len(IMPORT_NODES) def setup_network(self): - extra_args = [["-debug=1"] for _ in range(self.num_nodes)] + extra_args = [[] for _ in range(self.num_nodes)] for i, import_node in enumerate(IMPORT_NODES, 2): if import_node.prune: extra_args[i] += ["-prune=1"] diff --git a/qa/rpc-tests/importmulti.py b/test/functional/importmulti.py index 015336effe..e049302632 100755 --- a/qa/rpc-tests/importmulti.py +++ b/test/functional/importmulti.py @@ -17,7 +17,7 @@ class ImportMultiTest (BitcoinTestFramework): self.is_network_split=False def run_test (self): - print ("Mining blocks...") + self.log.info("Mining blocks...") self.nodes[0].generate(1) self.nodes[1].generate(1) timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] @@ -48,7 +48,7 @@ class ImportMultiTest (BitcoinTestFramework): # RPC importmulti ----------------------------------------------- # Bitcoin Address - print("Should import an address") + self.log.info("Should import an address") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": { @@ -64,7 +64,7 @@ class ImportMultiTest (BitcoinTestFramework): watchonly_address = address['address'] watchonly_timestamp = timestamp - print("Should not import an invalid address") + self.log.info("Should not import an invalid address") result = self.nodes[1].importmulti([{ "scriptPubKey": { "address": "not valid address", @@ -76,7 +76,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(result[0]['error']['message'], 'Invalid address') # ScriptPubKey + internal - print("Should import a scriptPubKey with internal flag") + self.log.info("Should import a scriptPubKey with internal flag") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": address['scriptPubKey'], @@ -90,7 +90,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['timestamp'], timestamp) # ScriptPubKey + !internal - print("Should not import a scriptPubKey without internal flag") + self.log.info("Should not import a scriptPubKey without internal flag") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": address['scriptPubKey'], @@ -106,7 +106,7 @@ class ImportMultiTest (BitcoinTestFramework): # Address + Public key + !Internal - print("Should import an address with public key") + self.log.info("Should import an address with public key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": { @@ -123,7 +123,7 @@ class ImportMultiTest (BitcoinTestFramework): # ScriptPubKey + Public key + internal - print("Should import a scriptPubKey with internal and with public key") + self.log.info("Should import a scriptPubKey with internal and with public key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) request = [{ "scriptPubKey": address['scriptPubKey'], @@ -139,7 +139,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['timestamp'], timestamp) # ScriptPubKey + Public key + !internal - print("Should not import a scriptPubKey without internal and with public key") + self.log.info("Should not import a scriptPubKey without internal and with public key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) request = [{ "scriptPubKey": address['scriptPubKey'], @@ -156,7 +156,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal('timestamp' in address_assert, False) # Address + Private key + !watchonly - print("Should import an address with private key") + self.log.info("Should import an address with private key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": { @@ -172,7 +172,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['timestamp'], timestamp) # Address + Private key + watchonly - print("Should not import an address with private key and with watchonly") + self.log.info("Should not import an address with private key and with watchonly") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": { @@ -191,7 +191,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal('timestamp' in address_assert, False) # ScriptPubKey + Private key + internal - print("Should import a scriptPubKey with internal and with private key") + self.log.info("Should import a scriptPubKey with internal and with private key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": address['scriptPubKey'], @@ -206,7 +206,7 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['timestamp'], timestamp) # ScriptPubKey + Private key + !internal - print("Should not import a scriptPubKey without internal and with private key") + self.log.info("Should not import a scriptPubKey without internal and with private key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ "scriptPubKey": address['scriptPubKey'], @@ -233,7 +233,7 @@ class ImportMultiTest (BitcoinTestFramework): timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] transaction = self.nodes[1].gettransaction(transactionid) - print("Should import a p2sh") + self.log.info("Should import a p2sh") result = self.nodes[1].importmulti([{ "scriptPubKey": { "address": multi_sig_script['address'] @@ -261,7 +261,7 @@ class ImportMultiTest (BitcoinTestFramework): timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] transaction = self.nodes[1].gettransaction(transactionid) - print("Should import a p2sh with respective redeem script") + self.log.info("Should import a p2sh with respective redeem script") result = self.nodes[1].importmulti([{ "scriptPubKey": { "address": multi_sig_script['address'] @@ -289,7 +289,7 @@ class ImportMultiTest (BitcoinTestFramework): timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] transaction = self.nodes[1].gettransaction(transactionid) - print("Should import a p2sh with respective redeem script and private keys") + self.log.info("Should import a p2sh with respective redeem script and private keys") result = self.nodes[1].importmulti([{ "scriptPubKey": { "address": multi_sig_script['address'] @@ -314,9 +314,10 @@ class ImportMultiTest (BitcoinTestFramework): self.nodes[1].generate(100) transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00) self.nodes[1].generate(1) + timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime'] transaction = self.nodes[1].gettransaction(transactionid) - print("Should import a p2sh with respective redeem script and private keys") + self.log.info("Should import a p2sh with respective redeem script and private keys") result = self.nodes[1].importmulti([{ "scriptPubKey": { "address": multi_sig_script['address'] @@ -332,7 +333,7 @@ class ImportMultiTest (BitcoinTestFramework): # Address + Public key + !Internal + Wrong pubkey - print("Should not import an address with a wrong public key") + self.log.info("Should not import an address with a wrong public key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ @@ -352,7 +353,7 @@ class ImportMultiTest (BitcoinTestFramework): # ScriptPubKey + Public key + internal + Wrong pubkey - print("Should not import a scriptPubKey with internal and with a wrong public key") + self.log.info("Should not import a scriptPubKey with internal and with a wrong public key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) request = [{ @@ -372,7 +373,7 @@ class ImportMultiTest (BitcoinTestFramework): # Address + Private key + !watchonly + Wrong private key - print("Should not import an address with a wrong private key") + self.log.info("Should not import an address with a wrong private key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ @@ -392,7 +393,7 @@ class ImportMultiTest (BitcoinTestFramework): # ScriptPubKey + Private key + internal + Wrong private key - print("Should not import a scriptPubKey with internal and with a wrong private key") + self.log.info("Should not import a scriptPubKey with internal and with a wrong private key") address = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) address2 = self.nodes[0].validateaddress(self.nodes[0].getnewaddress()) result = self.nodes[1].importmulti([{ @@ -409,16 +410,34 @@ class ImportMultiTest (BitcoinTestFramework): assert_equal(address_assert['ismine'], False) assert_equal('timestamp' in address_assert, False) + + # Importing existing watch only address with new timestamp should replace saved timestamp. + assert_greater_than(timestamp, watchonly_timestamp) + self.log.info("Should replace previously saved watch only timestamp.") + result = self.nodes[1].importmulti([{ + "scriptPubKey": { + "address": watchonly_address, + }, + "timestamp": "now", + }]) + assert_equal(result[0]['success'], True) + address_assert = self.nodes[1].validateaddress(watchonly_address) + assert_equal(address_assert['iswatchonly'], True) + assert_equal(address_assert['ismine'], False) + assert_equal(address_assert['timestamp'], timestamp) + watchonly_timestamp = timestamp + + # restart nodes to check for proper serialization/deserialization of watch only address stop_nodes(self.nodes) self.nodes = start_nodes(2, self.options.tmpdir) address_assert = self.nodes[1].validateaddress(watchonly_address) assert_equal(address_assert['iswatchonly'], True) assert_equal(address_assert['ismine'], False) - assert_equal(address_assert['timestamp'], watchonly_timestamp); + assert_equal(address_assert['timestamp'], watchonly_timestamp) # Bad or missing timestamps - print("Should throw on invalid or missing timestamp values") + self.log.info("Should throw on invalid or missing timestamp values") assert_raises_message(JSONRPCException, 'Missing required timestamp field for key', self.nodes[1].importmulti, [{ "scriptPubKey": address['scriptPubKey'], diff --git a/qa/rpc-tests/importprunedfunds.py b/test/functional/importprunedfunds.py index a941124656..b4c8ee6c70 100755 --- a/qa/rpc-tests/importprunedfunds.py +++ b/test/functional/importprunedfunds.py @@ -21,7 +21,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): self.sync_all() def run_test(self): - print("Mining blocks...") + self.log.info("Mining blocks...") self.nodes[0].generate(101) self.sync_all() @@ -76,12 +76,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): self.sync_all() #Import with no affiliated address - try: - self.nodes[1].importprunedfunds(rawtxn1, proof1) - except JSONRPCException as e: - assert('No addresses' in e.error['message']) - else: - assert(False) + assert_raises_jsonrpc(-5, "No addresses", self.nodes[1].importprunedfunds, rawtxn1, proof1) balance1 = self.nodes[1].getbalance("", 0, True) assert_equal(balance1, Decimal(0)) @@ -112,12 +107,7 @@ class ImportPrunedFundsTest(BitcoinTestFramework): assert_equal(address_info['ismine'], True) #Remove transactions - try: - self.nodes[1].removeprunedfunds(txnid1) - except JSONRPCException as e: - assert('does not exist' in e.error['message']) - else: - assert(False) + assert_raises_jsonrpc(-8, "Transaction does not exist in wallet.", self.nodes[1].removeprunedfunds, txnid1) balance1 = self.nodes[1].getbalance("*", 0, True) assert_equal(balance1, Decimal('0.075')) diff --git a/qa/rpc-tests/invalidateblock.py b/test/functional/invalidateblock.py index 92e65927d5..8c80b64003 100755 --- a/qa/rpc-tests/invalidateblock.py +++ b/test/functional/invalidateblock.py @@ -18,53 +18,51 @@ class InvalidateTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] self.is_network_split = False - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(0, self.options.tmpdir)) + self.nodes.append(start_node(1, self.options.tmpdir)) + self.nodes.append(start_node(2, self.options.tmpdir)) def run_test(self): - print("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") - print("Mine 4 blocks on Node 0") + self.log.info("Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:") + self.log.info("Mine 4 blocks on Node 0") self.nodes[0].generate(4) assert(self.nodes[0].getblockcount() == 4) besthash = self.nodes[0].getbestblockhash() - print("Mine competing 6 blocks on Node 1") + self.log.info("Mine competing 6 blocks on Node 1") self.nodes[1].generate(6) assert(self.nodes[1].getblockcount() == 6) - print("Connect nodes to force a reorg") + self.log.info("Connect nodes to force a reorg") connect_nodes_bi(self.nodes,0,1) sync_blocks(self.nodes[0:2]) assert(self.nodes[0].getblockcount() == 6) badhash = self.nodes[1].getblockhash(2) - print("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") + self.log.info("Invalidate block 2 on node 0 and verify we reorg to node 0's original chain") self.nodes[0].invalidateblock(badhash) newheight = self.nodes[0].getblockcount() newhash = self.nodes[0].getbestblockhash() if (newheight != 4 or newhash != besthash): raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight)) - print("\nMake sure we won't reorg to a lower work chain:") + self.log.info("Make sure we won't reorg to a lower work chain:") connect_nodes_bi(self.nodes,1,2) - print("Sync node 2 to node 1 so both have 6 blocks") + self.log.info("Sync node 2 to node 1 so both have 6 blocks") sync_blocks(self.nodes[1:3]) assert(self.nodes[2].getblockcount() == 6) - print("Invalidate block 5 on node 1 so its tip is now at 4") + 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)) assert(self.nodes[1].getblockcount() == 4) - print("Invalidate block 3 on node 2, so its tip is now 2") + self.log.info("Invalidate block 3 on node 2, so its tip is now 2") self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) assert(self.nodes[2].getblockcount() == 2) - print("..and then mine a block") + self.log.info("..and then mine a block") self.nodes[2].generate(1) - print("Verify all nodes are at the right height") + self.log.info("Verify all nodes are at the right height") time.sleep(5) - for i in range(3): - print(i,self.nodes[i].getblockcount()) - assert(self.nodes[2].getblockcount() == 3) - assert(self.nodes[0].getblockcount() == 4) + assert_equal(self.nodes[2].getblockcount(), 3) + assert_equal(self.nodes[0].getblockcount(), 4) node1height = self.nodes[1].getblockcount() if node1height < 4: raise AssertionError("Node 1 reorged to a lower height: %d"%node1height) diff --git a/qa/rpc-tests/invalidblockrequest.py b/test/functional/invalidblockrequest.py index eabc0db8df..eabc0db8df 100755 --- a/qa/rpc-tests/invalidblockrequest.py +++ b/test/functional/invalidblockrequest.py diff --git a/qa/rpc-tests/invalidtxrequest.py b/test/functional/invalidtxrequest.py index a9ac231f09..a9ac231f09 100755 --- a/qa/rpc-tests/invalidtxrequest.py +++ b/test/functional/invalidtxrequest.py diff --git a/qa/rpc-tests/keypool.py b/test/functional/keypool.py index 4b9936a1fd..cb9ab688d1 100755 --- a/qa/rpc-tests/keypool.py +++ b/test/functional/keypool.py @@ -27,36 +27,42 @@ class KeyPoolTest(BitcoinTestFramework): wallet_info = nodes[0].getwalletinfo() assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid']) assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid']) - - try: - addr = nodes[0].getnewaddress() - raise AssertionError('Keypool should be exhausted after one address') - except JSONRPCException as e: - assert(e.error['code']==-12) + assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) - # put three new keys in the keypool + # put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min) nodes[0].walletpassphrase('test', 12000) - nodes[0].keypoolrefill(3) + nodes[0].keypoolrefill(6) nodes[0].walletlock() + wi = nodes[0].getwalletinfo() + assert_equal(wi['keypoolsize_hd_internal'], 6) + assert_equal(wi['keypoolsize'], 6) - # drain the keys + # drain the internal keys + nodes[0].getrawchangeaddress() + nodes[0].getrawchangeaddress() + nodes[0].getrawchangeaddress() + nodes[0].getrawchangeaddress() + nodes[0].getrawchangeaddress() + nodes[0].getrawchangeaddress() addr = set() - addr.add(nodes[0].getrawchangeaddress()) - addr.add(nodes[0].getrawchangeaddress()) - addr.add(nodes[0].getrawchangeaddress()) - addr.add(nodes[0].getrawchangeaddress()) - # assert that four unique addresses were returned - assert(len(addr) == 4) # the next one should fail - try: - addr = nodes[0].getrawchangeaddress() - raise AssertionError('Keypool should be exhausted after three addresses') - except JSONRPCException as e: - assert(e.error['code']==-12) + assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].getrawchangeaddress) + + # drain the external keys + addr.add(nodes[0].getnewaddress()) + addr.add(nodes[0].getnewaddress()) + addr.add(nodes[0].getnewaddress()) + addr.add(nodes[0].getnewaddress()) + addr.add(nodes[0].getnewaddress()) + addr.add(nodes[0].getnewaddress()) + assert(len(addr) == 6) + # the next one should fail + assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress) # refill keypool with three new addresses nodes[0].walletpassphrase('test', 1) nodes[0].keypoolrefill(3) + # test walletpassphrase timeout time.sleep(1.1) assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0) @@ -65,12 +71,13 @@ class KeyPoolTest(BitcoinTestFramework): nodes[0].generate(1) nodes[0].generate(1) nodes[0].generate(1) - nodes[0].generate(1) - try: - nodes[0].generate(1) - raise AssertionError('Keypool should be exhausted after three addesses') - except JSONRPCException as e: - assert(e.error['code']==-12) + assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].generate, 1) + + nodes[0].walletpassphrase('test', 100) + nodes[0].keypoolrefill(100) + wi = nodes[0].getwalletinfo() + assert_equal(wi['keypoolsize_hd_internal'], 100) + assert_equal(wi['keypoolsize'], 100) def __init__(self): super().__init__() diff --git a/qa/rpc-tests/listsinceblock.py b/test/functional/listsinceblock.py index 88304af5b0..a75e66c8c4 100755 --- a/qa/rpc-tests/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -62,7 +62,7 @@ class ListSinceBlockTest (BitcoinTestFramework): # generate on both sides lastblockhash = self.nodes[1].generate(6)[5] self.nodes[2].generate(7) - print('lastblockhash=%s' % (lastblockhash)) + self.log.info('lastblockhash=%s' % (lastblockhash)) self.sync_all() diff --git a/qa/rpc-tests/listtransactions.py b/test/functional/listtransactions.py index 92fb96c809..68d14093ce 100755 --- a/qa/rpc-tests/listtransactions.py +++ b/test/functional/listtransactions.py @@ -126,7 +126,11 @@ class ListTransactionsTest(BitcoinTestFramework): 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. + utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[0], txid_1) + assert_equal(utxo_to_use["safe"], True) utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) + utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_1) + assert_equal(utxo_to_use["safe"], False) # Create tx2 using createrawtransaction inputs = [{"txid":utxo_to_use["txid"], "vout":utxo_to_use["vout"]}] diff --git a/qa/rpc-tests/maxblocksinflight.py b/test/functional/maxblocksinflight.py index 8ea405b4d5..4ef2a35a44 100755 --- a/qa/rpc-tests/maxblocksinflight.py +++ b/test/functional/maxblocksinflight.py @@ -13,12 +13,10 @@ reach. [0.10 clients shouldn't request more than 16 from a single peer.] from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -import logging MAX_REQUESTS = 128 class TestManager(NodeConnCB): - # set up NodeConnCB callbacks, overriding base class def on_getdata(self, conn, message): self.log.debug("got getdata %s" % repr(message)) # Log the requests @@ -31,12 +29,8 @@ class TestManager(NodeConnCB): if not self.disconnectOkay: raise EarlyDisconnectError(0) - def __init__(self): - NodeConnCB.__init__(self) - self.log = logging.getLogger("BlockRelayTest") - def add_new_connection(self, connection): - self.connection = connection + super().add_connection(connection) self.blockReqCounts = {} self.disconnectOkay = False @@ -65,7 +59,7 @@ class TestManager(NodeConnCB): raise AssertionError("Error, test failed: block %064x requested more than once" % key) if total_requests > MAX_REQUESTS: raise AssertionError("Error, too many blocks (%d) requested" % total_requests) - print("Round %d: success (total requests: %d)" % (count, total_requests)) + self.log.info("Round %d: success (total requests: %d)" % (count, total_requests)) self.disconnectOkay = True self.connection.disconnect_node() @@ -84,11 +78,13 @@ class MaxBlocksInFlightTest(BitcoinTestFramework): def setup_network(self): self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1']], + extra_args=[['-whitelist=127.0.0.1']], binary=[self.options.testbinary]) def run_test(self): test = TestManager() + # pass log handler through to the test manager object + test.log = self.log test.add_new_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test)) NetworkThread().start() # Start up network handling in another thread test.run() diff --git a/qa/rpc-tests/maxuploadtarget.py b/test/functional/maxuploadtarget.py index 757aa60afd..b26c10796d 100755 --- a/qa/rpc-tests/maxuploadtarget.py +++ b/test/functional/maxuploadtarget.py @@ -20,7 +20,7 @@ import time # p2p messages to a node, generating the messages in the main testing logic. class TestNode(NodeConnCB): def __init__(self): - NodeConnCB.__init__(self) + super().__init__() self.connection = None self.ping_counter = 1 self.last_pong = msg_pong() @@ -90,7 +90,7 @@ class MaxUploadTest(BitcoinTestFramework): def setup_network(self): # Start a node with maxuploadtarget of 200 MB (/24h) self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-maxuploadtarget=800", "-blockmaxsize=999000"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxuploadtarget=800", "-blockmaxsize=999000"])) def run_test(self): # Before we connect anything, we first set the time on the node @@ -161,7 +161,7 @@ class MaxUploadTest(BitcoinTestFramework): test_nodes[0].send_message(getdata_request) test_nodes[0].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 2) - print("Peer 0 disconnected after downloading old block too many times") + self.log.info("Peer 0 disconnected after downloading old block too many times") # Requesting the current block on test_nodes[1] should succeed indefinitely, # even when over the max upload target. @@ -172,7 +172,7 @@ class MaxUploadTest(BitcoinTestFramework): test_nodes[1].sync_with_ping() assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1) - print("Peer 1 able to repeatedly download new block") + self.log.info("Peer 1 able to repeatedly download new block") # But if test_nodes[1] tries for an old block, it gets disconnected too. getdata_request.inv = [CInv(2, big_old_block)] @@ -180,9 +180,9 @@ class MaxUploadTest(BitcoinTestFramework): test_nodes[1].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 1) - print("Peer 1 disconnected after trying to download old block") + self.log.info("Peer 1 disconnected after trying to download old block") - print("Advancing system time on node to clear counters...") + self.log.info("Advancing system time on node to clear counters...") # If we advance the time by 24 hours, then the counters should reset, # and test_nodes[2] should be able to retrieve the old block. @@ -192,14 +192,14 @@ class MaxUploadTest(BitcoinTestFramework): test_nodes[2].sync_with_ping() assert_equal(test_nodes[2].block_receive_map[big_old_block], 1) - print("Peer 2 able to download old block") + self.log.info("Peer 2 able to download old block") [c.disconnect_node() for c in connections] #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1 - print("Restarting nodes with -whitelist=127.0.0.1") + self.log.info("Restarting nodes with -whitelist=127.0.0.1") stop_node(self.nodes[0], 0) - self.nodes[0] = start_node(0, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) + self.nodes[0] = start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) #recreate/reconnect 3 test nodes test_nodes = [] @@ -225,7 +225,7 @@ class MaxUploadTest(BitcoinTestFramework): test_nodes[1].wait_for_disconnect() assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist - print("Peer 1 still connected after trying to download old block (whitelisted)") + self.log.info("Peer 1 still connected after trying to download old block (whitelisted)") [c.disconnect_node() for c in connections] diff --git a/qa/rpc-tests/mempool_limit.py b/test/functional/mempool_limit.py index 8fae92ad2b..a7ca576aee 100755 --- a/qa/rpc-tests/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -11,7 +11,7 @@ class MempoolLimitTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0", "-debug"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxmempool=5", "-spendzeroconfchange=0"])) self.is_network_split = False self.sync_all() self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] diff --git a/qa/rpc-tests/mempool_packages.py b/test/functional/mempool_packages.py index 3437c89ec7..17e3a9a967 100755 --- a/qa/rpc-tests/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -19,8 +19,8 @@ class MempoolPackagesTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-limitancestorcount=5", "-debug"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-maxorphantx=1000", "-limitancestorcount=5"])) connect_nodes(self.nodes[0], 1) self.is_network_split = False self.sync_all() @@ -112,10 +112,7 @@ class MempoolPackagesTest(BitcoinTestFramework): assert_equal(mempool[x]['descendantfees'], descendant_fees * COIN + 1000) # Adding one more transaction on to the chain should fail. - try: - self.chain_transaction(self.nodes[0], txid, vout, value, fee, 1) - except JSONRPCException as e: - print("too-long-ancestor-chain successfully rejected") + assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], txid, vout, value, fee, 1) # Check that prioritising a tx before it's added to the mempool works # First clear the mempool by mining a block. @@ -155,19 +152,19 @@ class MempoolPackagesTest(BitcoinTestFramework): for i in range(10): transaction_package.append({'txid': txid, 'vout': i, 'amount': sent_value}) - for i in range(MAX_DESCENDANTS): + # Sign and send up to MAX_DESCENDANT transactions chained off the parent tx + for i in range(MAX_DESCENDANTS - 1): utxo = transaction_package.pop(0) - try: - (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) - for j in range(10): - transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) - if i == MAX_DESCENDANTS - 2: - mempool = self.nodes[0].getrawmempool(True) - assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS) - except JSONRPCException as e: - print(e.error['message']) - assert_equal(i, MAX_DESCENDANTS - 1) - print("tx that would create too large descendant package successfully rejected") + (txid, sent_value) = self.chain_transaction(self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) + for j in range(10): + transaction_package.append({'txid': txid, 'vout': j, 'amount': sent_value}) + + mempool = self.nodes[0].getrawmempool(True) + assert_equal(mempool[parent_transaction]['descendantcount'], MAX_DESCENDANTS) + + # Sending one more chained transaction will fail + utxo = transaction_package.pop(0) + assert_raises_jsonrpc(-26, "too-long-mempool-chain", self.chain_transaction, self.nodes[0], utxo['txid'], utxo['vout'], utxo['amount'], fee, 10) # TODO: check that node1's mempool is as expected diff --git a/qa/rpc-tests/mempool_reorg.py b/test/functional/mempool_reorg.py index 2cd5573277..812b54ffcb 100755 --- a/qa/rpc-tests/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -21,7 +21,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): alert_filename = None # Set by setup_network def setup_network(self): - args = ["-checkmempool", "-debug=mempool"] + args = ["-checkmempool"] self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.nodes.append(start_node(1, self.options.tmpdir, args)) @@ -30,9 +30,10 @@ class MempoolCoinbaseTest(BitcoinTestFramework): self.sync_all() def run_test(self): - start_count = self.nodes[0].getblockcount() + # Start with a 200 block chain + assert_equal(self.nodes[0].getblockcount(), 200) - # Mine three blocks. After this, nodes[0] blocks + # Mine four blocks. After this, nodes[0] blocks # 101, 102, and 103 are spend-able. new_blocks = self.nodes[1].generate(4) self.sync_all() @@ -52,19 +53,21 @@ class MempoolCoinbaseTest(BitcoinTestFramework): spend_102_raw = create_tx(self.nodes[0], coinbase_txids[2], node0_address, 49.99) spend_103_raw = create_tx(self.nodes[0], coinbase_txids[3], node0_address, 49.99) - # Create a block-height-locked transaction which will be invalid after reorg + # Create a transaction which is time-locked to two blocks in the future timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 49.99}) # Set the time lock timelock_tx = timelock_tx.replace("ffffffff", "11111191", 1) timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000" timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"] - assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) + # This will raise an exception because the timelock transaction is too immature to spend + assert_raises_jsonrpc(-26, "non-final", self.nodes[0].sendrawtransaction, timelock_tx) # Broadcast and mine spend_102 and 103: spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) self.nodes[0].generate(1) - assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx) + # Time-locked transaction is still too immature to spend + assert_raises_jsonrpc(-26,'non-final', self.nodes[0].sendrawtransaction, timelock_tx) # Create 102_1 and 103_1: spend_102_1_raw = create_tx(self.nodes[0], spend_102_id, node1_address, 49.98) @@ -73,6 +76,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Broadcast and mine 103_1: spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) last_block = self.nodes[0].generate(1) + # Time-locked transaction can now be spent timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx) # ... now put spend_101 and spend_102_1 in memory pools: @@ -85,6 +89,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework): for node in self.nodes: node.invalidateblock(last_block[0]) + # Time-locked transaction is now too immature and has been removed from the mempool + # spend_103_1 has been re-orged out of the chain and is back in the mempool assert_equal(set(self.nodes[0].getrawmempool()), {spend_101_id, spend_102_1_id, spend_103_1_id}) # Use invalidateblock to re-org back and make all those coinbase spends diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/test/functional/mempool_resurrect_test.py index c7f37aaa44..727892d1f2 100755 --- a/qa/rpc-tests/mempool_resurrect_test.py +++ b/test/functional/mempool_resurrect_test.py @@ -17,7 +17,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): def setup_network(self): # Just need one node for this test - args = ["-checkmempool", "-debug=mempool"] + args = ["-checkmempool"] self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.is_network_split = False diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/test/functional/mempool_spendcoinbase.py index da8485e2a2..f562a93d86 100755 --- a/qa/rpc-tests/mempool_spendcoinbase.py +++ b/test/functional/mempool_spendcoinbase.py @@ -25,7 +25,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): def setup_network(self): # Just need one node for this test - args = ["-checkmempool", "-debug=mempool"] + args = ["-checkmempool"] self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, args)) self.is_network_split = False @@ -45,7 +45,7 @@ class MempoolSpendCoinbaseTest(BitcoinTestFramework): spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0]) # coinbase at height 102 should be too immature to spend - assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1]) + assert_raises_jsonrpc(-26,"bad-txns-premature-spend-of-coinbase", self.nodes[0].sendrawtransaction, spends_raw[1]) # mempool should have just spend_101: assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ]) diff --git a/qa/rpc-tests/merkle_blocks.py b/test/functional/merkle_blocks.py index c4b45425d7..5963f2e7b6 100755 --- a/qa/rpc-tests/merkle_blocks.py +++ b/test/functional/merkle_blocks.py @@ -17,11 +17,11 @@ class MerkleBlockTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] # Nodes 0/1 are "wallet" nodes - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(0, self.options.tmpdir)) + self.nodes.append(start_node(1, self.options.tmpdir)) # Nodes 2/3 are used for testing - self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-txindex"])) + self.nodes.append(start_node(2, self.options.tmpdir)) + self.nodes.append(start_node(3, self.options.tmpdir, ["-txindex"])) connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[0], 2) connect_nodes(self.nodes[0], 3) @@ -30,7 +30,7 @@ class MerkleBlockTest(BitcoinTestFramework): self.sync_all() def run_test(self): - print("Mining blocks...") + self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() diff --git a/qa/rpc-tests/multi_rpc.py b/test/functional/multi_rpc.py index 3b74bf1c46..a9701c548b 100755 --- a/qa/rpc-tests/multi_rpc.py +++ b/test/functional/multi_rpc.py @@ -41,11 +41,9 @@ class HTTPBasicsTest (BitcoinTestFramework): authpair = url.username + ':' + url.password #New authpair generated via share/rpcuser tool - rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM=" #Second authpair with different username - rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI=" authpairnew = "rt:"+password diff --git a/qa/rpc-tests/nodehandling.py b/test/functional/nodehandling.py index 89059d2760..a6b10a0d83 100755 --- a/qa/rpc-tests/nodehandling.py +++ b/test/functional/nodehandling.py @@ -29,15 +29,13 @@ class NodeHandlingTest (BitcoinTestFramework): assert_equal(len(self.nodes[2].listbanned()), 0) self.nodes[2].setban("127.0.0.0/24", "add") assert_equal(len(self.nodes[2].listbanned()), 1) - try: - self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24 - except: - pass + # This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24 + assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[2].setban, "127.0.0.1", "add") + # This will throw an exception because 127.0.0.1/42 is not a real subnet + assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[2].setban, "127.0.0.1/42", "add") assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 - try: - self.nodes[2].setban("127.0.0.1", "remove") - except: - pass + # This will throw an exception because 127.0.0.1 was not added above + assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[2].setban, "127.0.0.1", "remove") assert_equal(len(self.nodes[2].listbanned()), 1) self.nodes[2].setban("127.0.0.0/24", "remove") assert_equal(len(self.nodes[2].listbanned()), 0) diff --git a/qa/rpc-tests/nulldummy.py b/test/functional/nulldummy.py index b44a98bfd5..369c593a90 100755 --- a/qa/rpc-tests/nulldummy.py +++ b/test/functional/nulldummy.py @@ -45,7 +45,7 @@ class NULLDUMMYTest(BitcoinTestFramework): def setup_network(self): # Must set the blockversion for this test self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1', '-walletprematurewitness']]) + extra_args=[['-whitelist=127.0.0.1', '-walletprematurewitness']]) def run_test(self): self.address = self.nodes[0].getnewaddress() @@ -64,40 +64,40 @@ class NULLDUMMYTest(BitcoinTestFramework): self.lastblockheight = 429 self.lastblocktime = int(time.time()) + 429 - print ("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]") + self.log.info("Test 1: NULLDUMMY compliant base transactions should be accepted to mempool and mined before activation [430]") test1txs = [self.create_transaction(self.nodes[0], coinbase_txid[0], self.ms_address, 49)] - txid1 = self.tx_submit(self.nodes[0], test1txs[0]) + txid1 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[0].serialize_with_witness()), True) test1txs.append(self.create_transaction(self.nodes[0], txid1, self.ms_address, 48)) - txid2 = self.tx_submit(self.nodes[0], test1txs[1]) + txid2 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[1].serialize_with_witness()), True) test1txs.append(self.create_transaction(self.nodes[0], coinbase_txid[1], self.wit_ms_address, 49)) - txid3 = self.tx_submit(self.nodes[0], test1txs[2]) + txid3 = self.nodes[0].sendrawtransaction(bytes_to_hex_str(test1txs[2].serialize_with_witness()), True) self.block_submit(self.nodes[0], test1txs, False, True) - print ("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation") + self.log.info("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation") test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 47) trueDummy(test2tx) - txid4 = self.tx_submit(self.nodes[0], test2tx, NULLDUMMY_ERROR) + assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test2tx.serialize_with_witness()), True) - print ("Test 3: Non-NULLDUMMY base transactions should be accepted in a block before activation [431]") + 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) - print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation") - test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 46) + self.log.info("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation") + test4tx = self.create_transaction(self.nodes[0], test2tx.hash, self.address, 46) test6txs=[CTransaction(test4tx)] trueDummy(test4tx) - self.tx_submit(self.nodes[0], test4tx, NULLDUMMY_ERROR) + assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test4tx.serialize_with_witness()), True) self.block_submit(self.nodes[0], [test4tx]) - print ("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation") + self.log.info("Test 5: Non-NULLDUMMY P2WSH multisig transaction invalid after activation") test5tx = self.create_transaction(self.nodes[0], txid3, self.wit_address, 48) test6txs.append(CTransaction(test5tx)) test5tx.wit.vtxinwit[0].scriptWitness.stack[0] = b'\x01' - self.tx_submit(self.nodes[0], test5tx, NULLDUMMY_ERROR) + assert_raises_jsonrpc(-26, NULLDUMMY_ERROR, self.nodes[0].sendrawtransaction, bytes_to_hex_str(test5tx.serialize_with_witness()), True) self.block_submit(self.nodes[0], [test5tx], True) - print ("Test 6: NULLDUMMY compliant base/witness transactions should be accepted to mempool and in block after activation [432]") + 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.tx_submit(self.nodes[0], i) + self.nodes[0].sendrawtransaction(bytes_to_hex_str(i.serialize_with_witness()), True) self.block_submit(self.nodes[0], test6txs, True, True) @@ -112,17 +112,6 @@ class NULLDUMMYTest(BitcoinTestFramework): return tx - def tx_submit(self, node, tx, msg = ""): - tx.rehash() - try: - node.sendrawtransaction(bytes_to_hex_str(tx.serialize_with_witness()), True) - except JSONRPCException as exp: - assert_equal(exp.error["message"], msg) - else: - assert_equal('', msg) - return tx.hash - - def block_submit(self, node, txs, witness = False, accept = False): block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1) block.nVersion = 4 diff --git a/qa/rpc-tests/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 2f21fa149a..7bdbe2bb12 100755 --- a/qa/rpc-tests/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -58,7 +58,7 @@ from test_framework.blocktools import create_block, create_coinbase # p2p messages to a node, generating the messages in the main testing logic. class TestNode(NodeConnCB): def __init__(self): - NodeConnCB.__init__(self) + super().__init__() self.connection = None self.ping_counter = 1 self.last_pong = msg_pong() @@ -119,10 +119,10 @@ class AcceptBlockTest(BitcoinTestFramework): # from peers which are not whitelisted, while Node1 will be used for # the whitelisted case. self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"], + self.nodes.append(start_node(0, self.options.tmpdir, binary=self.options.testbinary)) self.nodes.append(start_node(1, self.options.tmpdir, - ["-debug", "-whitelist=127.0.0.1"], + ["-whitelist=127.0.0.1"], binary=self.options.testbinary)) def run_test(self): @@ -160,7 +160,7 @@ class AcceptBlockTest(BitcoinTestFramework): [ x.sync_with_ping() for x in [test_node, white_node] ] assert_equal(self.nodes[0].getblockcount(), 2) assert_equal(self.nodes[1].getblockcount(), 2) - print("First height 2 block accepted by both nodes") + self.log.info("First height 2 block accepted by both nodes") # 3. Send another block that builds on the original tip. blocks_h2f = [] # Blocks at height 2 that fork off the main chain @@ -179,7 +179,7 @@ class AcceptBlockTest(BitcoinTestFramework): if x['hash'] == blocks_h2f[1].hash: assert_equal(x['status'], "valid-headers") - print("Second height 2 block accepted only from whitelisted peer") + self.log.info("Second height 2 block accepted only from whitelisted peer") # 4. Now send another block that builds on the forking chain. blocks_h3 = [] @@ -197,15 +197,12 @@ class AcceptBlockTest(BitcoinTestFramework): assert_equal(x['status'], "headers-only") # But this block should be accepted by node0 since it has more work. - try: - self.nodes[0].getblock(blocks_h3[0].hash) - print("Unrequested more-work block accepted from non-whitelisted peer") - except: - raise AssertionError("Unrequested more work block was not processed") + self.nodes[0].getblock(blocks_h3[0].hash) + self.log.info("Unrequested more-work block accepted from non-whitelisted peer") # Node1 should have accepted and reorged. assert_equal(self.nodes[1].getblockcount(), 3) - print("Successfully reorged to length 3 chain from whitelisted peer") + self.log.info("Successfully reorged to length 3 chain from whitelisted peer") # 4b. Now mine 288 more blocks and deliver; all should be processed but # the last (height-too-high) on node0. Node1 should process the tip if @@ -225,26 +222,17 @@ class AcceptBlockTest(BitcoinTestFramework): tips[j] = next_block time.sleep(2) - for x in all_blocks: - try: - self.nodes[0].getblock(x.hash) - if x == all_blocks[287]: - raise AssertionError("Unrequested block too far-ahead should have been ignored") - except: - if x == all_blocks[287]: - print("Unrequested block too far-ahead not processed") - else: - raise AssertionError("Unrequested block with more work should have been accepted") + # Blocks 1-287 should be accepted, block 288 should be ignored because it's too far ahead + for x in all_blocks[:-1]: + self.nodes[0].getblock(x.hash) + assert_raises_jsonrpc(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[-1].hash) headers_message.headers.pop() # Ensure the last block is unrequested white_node.send_message(headers_message) # Send headers leading to tip white_node.send_message(msg_block(tips[1])) # Now deliver the tip - try: - white_node.sync_with_ping() - self.nodes[1].getblock(tips[1].hash) - print("Unrequested block far ahead of tip accepted from whitelisted peer") - except: - raise AssertionError("Unrequested block from whitelisted peer not accepted") + white_node.sync_with_ping() + self.nodes[1].getblock(tips[1].hash) + self.log.info("Unrequested block far ahead of tip accepted from whitelisted peer") # 5. Test handling of unrequested block on the node that didn't process # Should still not be processed (even though it has a child that has more @@ -258,7 +246,7 @@ class AcceptBlockTest(BitcoinTestFramework): # a getdata request for this block. test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) - print("Unrequested block that would complete more-work chain was ignored") + self.log.info("Unrequested block that would complete more-work chain was ignored") # 6. Try to get node to request the missing block. # Poke the node with an inv for block at height 3 and see if that @@ -274,14 +262,14 @@ class AcceptBlockTest(BitcoinTestFramework): # Check that the getdata includes the right block assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256) - print("Inv at tip triggered getdata for unprocessed block") + self.log.info("Inv at tip triggered getdata for unprocessed block") # 7. Send the missing block for the third time (now it is requested) test_node.send_message(msg_block(blocks_h2f[0])) test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 290) - print("Successfully reorged to longer chain from non-whitelisted peer") + self.log.info("Successfully reorged to longer chain from non-whitelisted peer") [ c.disconnect_node() for c in connections ] diff --git a/qa/rpc-tests/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py index 79561f35f7..86b767b98a 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/test/functional/p2p-compactblocks.py @@ -15,9 +15,9 @@ from test_framework.blocktools import create_block, create_coinbase, add_witness from test_framework.script import CScript, OP_TRUE # TestNode: A peer we use to send messages to bitcoind, and store responses. -class TestNode(SingleNodeConnCB): +class TestNode(NodeConnCB): def __init__(self): - SingleNodeConnCB.__init__(self) + super().__init__() self.last_sendcmpct = [] self.last_headers = None self.last_inv = None @@ -120,8 +120,8 @@ class CompactBlocksTest(BitcoinTestFramework): # Start up node0 to be a version 1, pre-segwit node. self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - [["-debug", "-logtimemicros=1", "-bip9params=segwit:0:0"], - ["-debug", "-logtimemicros", "-txindex"]]) + [["-bip9params=segwit:0:0"], + ["-txindex"]]) connect_nodes(self.nodes[0], 1) def build_block_on_tip(self, node, segwit=False): @@ -846,102 +846,102 @@ class CompactBlocksTest(BitcoinTestFramework): # We will need UTXOs to construct transactions in later tests. self.make_utxos() - print("Running tests, pre-segwit activation:") + self.log.info("Running tests, pre-segwit activation:") - print("\tTesting SENDCMPCT p2p message... ") + 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) - print("\tTesting compactblock construction...") + 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) - print("\tTesting compactblock requests... ") + 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) - print("\tTesting getblocktxn requests...") + 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) - print("\tTesting getblocktxn handler...") + 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) - print("\tTesting compactblock requests/announcements not at chain tip...") + 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) - print("\tTesting handling of incorrect blocktxn responses...") + 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 - print("\tTesting end-to-end block relay...") + 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]) - print("\tTesting handling of invalid compact blocks...") + 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) - print("\tTesting reconstructing compact blocks from all peers...") + 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 - print ("\nAdvancing to segwit activation\n") + self.log.info("Advancing to segwit activation") self.activate_segwit(self.nodes[1]) - print ("Running tests, post-segwit activation...") + self.log.info("Running tests, post-segwit activation...") - print("\tTesting compactblock construction...") + 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) - print("\tTesting compactblock requests (unupgraded node)... ") + self.log.info("Testing compactblock requests (unupgraded node)... ") self.test_compactblock_requests(self.nodes[0], self.test_node, 1, True) - print("\tTesting getblocktxn requests (unupgraded node)...") + 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. - print("\tSyncing nodes...") + 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()) - print("\tTesting compactblock requests (segwit node)... ") + self.log.info("Testing compactblock requests (segwit node)... ") self.test_compactblock_requests(self.nodes[1], self.segwit_node, 2, True) - print("\tTesting getblocktxn requests (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) - print("\tTesting getblocktxn handler (segwit node should return witnesses)...") + 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) @@ -949,18 +949,18 @@ class CompactBlocksTest(BitcoinTestFramework): # 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.) - print("\tTesting end-to-end block relay...") + 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]) - print("\tTesting handling of invalid compact blocks...") + 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) - print("\tTesting invalid index in cmpctblock message...") + self.log.info("Testing invalid index in cmpctblock message...") self.test_invalid_cmpctblock_message() diff --git a/qa/rpc-tests/p2p-feefilter.py b/test/functional/p2p-feefilter.py index 1c62961db0..12539be950 100755 --- a/qa/rpc-tests/p2p-feefilter.py +++ b/test/functional/p2p-feefilter.py @@ -24,9 +24,9 @@ def allInvsMatch(invsExpected, testnode): # TestNode: bare-bones "peer". Used to track which invs are received from a node # and to send the node feefilter messages. -class TestNode(SingleNodeConnCB): +class TestNode(NodeConnCB): def __init__(self): - SingleNodeConnCB.__init__(self) + super().__init__() self.txinvs = [] def on_inv(self, conn, message): @@ -53,8 +53,8 @@ class FeeFilterTest(BitcoinTestFramework): # Node1 will be used to generate txs which should be relayed from Node0 # to our test node self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros"])) + self.nodes.append(start_node(0, self.options.tmpdir)) + self.nodes.append(start_node(1, self.options.tmpdir)) connect_nodes(self.nodes[0], 1) def run_test(self): diff --git a/qa/rpc-tests/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py index 274dbb8a92..274dbb8a92 100755 --- a/qa/rpc-tests/p2p-fullblocktest.py +++ b/test/functional/p2p-fullblocktest.py diff --git a/qa/rpc-tests/p2p-leaktests.py b/test/functional/p2p-leaktests.py index bf08ea32f4..5853ec86f0 100755 --- a/qa/rpc-tests/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -19,10 +19,10 @@ banscore = 10 class CLazyNode(NodeConnCB): def __init__(self): + super().__init__() self.connection = None self.unexpected_msg = False self.connected = False - super().__init__() def add_connection(self, conn): self.connection = conn @@ -32,7 +32,7 @@ class CLazyNode(NodeConnCB): def bad_message(self, message): self.unexpected_msg = True - print("should not have received message: %s" % message.command) + self.log.info("should not have received message: %s" % message.command) def on_open(self, conn): self.connected = True @@ -102,7 +102,7 @@ class P2PLeakTest(BitcoinTestFramework): super().__init__() self.num_nodes = 1 def setup_network(self): - extra_args = [['-debug', '-banscore='+str(banscore)] + extra_args = [['-banscore='+str(banscore)] for i in range(self.num_nodes)] self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) diff --git a/qa/rpc-tests/p2p-mempool.py b/test/functional/p2p-mempool.py index c6b1490211..3d3a9939d4 100755 --- a/qa/rpc-tests/p2p-mempool.py +++ b/test/functional/p2p-mempool.py @@ -14,7 +14,7 @@ from test_framework.util import * class TestNode(NodeConnCB): def __init__(self): - NodeConnCB.__init__(self) + super().__init__() self.connection = None self.ping_counter = 1 self.last_pong = msg_pong() @@ -85,7 +85,7 @@ class P2PMempoolTests(BitcoinTestFramework): def setup_network(self): # Start a node with maxuploadtarget of 200 MB (/24h) self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-peerbloomfilters=0"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-peerbloomfilters=0"])) def run_test(self): #connect a mininode diff --git a/qa/rpc-tests/p2p-segwit.py b/test/functional/p2p-segwit.py index 470a5398b6..69f829279c 100755 --- a/qa/rpc-tests/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -32,10 +32,9 @@ def get_virtual_size(witness_block): vsize = int((3*base_size + total_size + 3)/4) return vsize -# Note: we can reduce code by using SingleNodeConnCB (in master, not 0.12) class TestNode(NodeConnCB): def __init__(self): - NodeConnCB.__init__(self) + super().__init__() self.connection = None self.ping_counter = 1 self.last_pong = msg_pong(0) @@ -70,7 +69,6 @@ class TestNode(NodeConnCB): def on_reject(self, conn, message): self.last_reject = message - #print (message) # Syncing helpers def sync(self, test_function, timeout=60): @@ -195,13 +193,13 @@ class SegWitTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1"])) # Start a node for testing IsStandard rules. - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-logtimemicros=1", "-whitelist=127.0.0.1", "-acceptnonstdtxn=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"])) connect_nodes(self.nodes[0], 1) # Disable segwit's bip9 parameter to simulate upgrading after activation. - self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-whitelist=127.0.0.1", "-bip9params=segwit:0:0"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-whitelist=127.0.0.1", "-bip9params=segwit:0:0"])) connect_nodes(self.nodes[0], 2) ''' Helpers ''' @@ -224,7 +222,7 @@ class SegWitTest(BitcoinTestFramework): ''' Individual tests ''' def test_witness_services(self): - print("\tVerifying NODE_WITNESS service bit") + self.log.info("Verifying NODE_WITNESS service bit") assert((self.test_node.connection.nServices & NODE_WITNESS) != 0) @@ -233,7 +231,7 @@ class SegWitTest(BitcoinTestFramework): def test_non_witness_transaction(self): # Mine a block with an anyone-can-spend coinbase, # let it mature, then try to spend it. - print("\tTesting non-witness transaction") + self.log.info("Testing non-witness transaction") block = self.build_next_block(nVersion=1) block.solve() self.test_node.send_message(msg_block(block)) @@ -262,7 +260,7 @@ class SegWitTest(BitcoinTestFramework): # Verify that blocks with witnesses are rejected before activation. def test_unnecessary_witness_before_segwit_activation(self): - print("\tTesting behavior of unnecessary witnesses") + self.log.info("Testing behavior of unnecessary witnesses") # For now, rely on earlier tests to have created at least one utxo for # us to use assert(len(self.utxo) > 0) @@ -389,7 +387,7 @@ class SegWitTest(BitcoinTestFramework): # This test can only be run after segwit has activated def test_witness_commitments(self): - print("\tTesting witness commitments") + self.log.info("Testing witness commitments") # First try a correct witness commitment. block = self.build_next_block() @@ -478,7 +476,7 @@ class SegWitTest(BitcoinTestFramework): def test_block_malleability(self): - print("\tTesting witness block malleability") + self.log.info("Testing witness block malleability") # Make sure that a block that has too big a virtual size # because of a too-large coinbase witness is not permanently @@ -519,7 +517,7 @@ class SegWitTest(BitcoinTestFramework): def test_witness_block_size(self): - print("\tTesting witness block size limit") + self.log.info("Testing witness block size limit") # TODO: Test that non-witness carrying blocks can't exceed 1MB # Skipping this test for now; this is covered in p2p-fullblocktest.py @@ -636,7 +634,7 @@ class SegWitTest(BitcoinTestFramework): # Consensus tests of extra witness data in a transaction. def test_extra_witness_data(self): - print("\tTesting extra witness data in tx") + self.log.info("Testing extra witness data in tx") assert(len(self.utxo) > 0) @@ -712,7 +710,7 @@ class SegWitTest(BitcoinTestFramework): def test_max_witness_push_length(self): ''' Should only allow up to 520 byte pushes in witness stack ''' - print("\tTesting maximum witness push size") + self.log.info("Testing maximum witness push size") MAX_SCRIPT_ELEMENT_SIZE = 520 assert(len(self.utxo)) @@ -752,7 +750,7 @@ class SegWitTest(BitcoinTestFramework): def test_max_witness_program_length(self): # Can create witness outputs that are long, but can't be greater than # 10k bytes to successfully spend - print("\tTesting maximum witness program length") + self.log.info("Testing maximum witness program length") assert(len(self.utxo)) MAX_PROGRAM_LENGTH = 10000 @@ -801,7 +799,7 @@ class SegWitTest(BitcoinTestFramework): def test_witness_input_length(self): ''' Ensure that vin length must match vtxinwit length ''' - print("\tTesting witness input length") + self.log.info("Testing witness input length") assert(len(self.utxo)) witness_program = CScript([OP_DROP, OP_TRUE]) @@ -884,7 +882,7 @@ class SegWitTest(BitcoinTestFramework): def test_witness_tx_relay_before_segwit_activation(self): - print("\tTesting relay of witness transactions") + self.log.info("Testing relay of witness transactions") # Generate a transaction that doesn't require a witness, but send it # with a witness. Should be rejected for premature-witness, but should # not be added to recently rejected list. @@ -908,7 +906,7 @@ class SegWitTest(BitcoinTestFramework): # a witness transaction ought not result in a getdata. try: self.test_node.announce_tx_and_wait_for_getdata(tx, timeout=2) - print("Error: duplicate tx getdata!") + self.log.error("Error: duplicate tx getdata!") assert(False) except AssertionError as e: pass @@ -936,7 +934,7 @@ class SegWitTest(BitcoinTestFramework): # - accepts transactions with valid witnesses # and that witness transactions are relayed to non-upgraded peers. def test_tx_relay_after_segwit_activation(self): - print("\tTesting relay of witness transactions") + self.log.info("Testing relay of witness transactions") # Generate a transaction that doesn't require a witness, but send it # with a witness. Should be rejected because we can't use a witness # when spending a non-witness output. @@ -1025,7 +1023,7 @@ class SegWitTest(BitcoinTestFramework): # This is true regardless of segwit activation. # Also test that we don't ask for blocks from unupgraded peers def test_block_relay(self, segwit_activated): - print("\tTesting block relay") + self.log.info("Testing block relay") blocktype = 2|MSG_WITNESS_FLAG @@ -1113,7 +1111,7 @@ class SegWitTest(BitcoinTestFramework): # V0 segwit outputs should be standard after activation, but not before. def test_standardness_v0(self, segwit_activated): - print("\tTesting standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before")) + self.log.info("Testing standardness of v0 outputs (%s activation)" % ("after" if segwit_activated else "before")) assert(len(self.utxo)) witness_program = CScript([OP_TRUE]) @@ -1190,7 +1188,7 @@ class SegWitTest(BitcoinTestFramework): # Verify that future segwit upgraded transactions are non-standard, # but valid in blocks. Can run this before and after segwit activation. def test_segwit_versions(self): - print("\tTesting standardness/consensus for segwit versions (0-16)") + self.log.info("Testing standardness/consensus for segwit versions (0-16)") assert(len(self.utxo)) NUM_TESTS = 17 # will test OP_0, OP1, ..., OP_16 if (len(self.utxo) < NUM_TESTS): @@ -1274,7 +1272,7 @@ class SegWitTest(BitcoinTestFramework): def test_premature_coinbase_witness_spend(self): - print("\tTesting premature coinbase witness spend") + self.log.info("Testing premature coinbase witness spend") block = self.build_next_block() # Change the output of the block to be a witness output. witness_program = CScript([OP_TRUE]) @@ -1309,7 +1307,7 @@ class SegWitTest(BitcoinTestFramework): def test_signature_version_1(self): - print("\tTesting segwit signature hash version 1") + self.log.info("Testing segwit signature hash version 1") key = CECKey() key.set_secretbytes(b"9") pubkey = CPubKey(key.get_pubkey()) @@ -1428,7 +1426,7 @@ class SegWitTest(BitcoinTestFramework): block = self.build_next_block() if (not used_sighash_single_out_of_bounds): - print("WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value") + self.log.info("WARNING: this test run didn't attempt SIGHASH_SINGLE with out-of-bounds index value") # Test the transactions we've added to the block if (len(block.vtx) > 1): self.update_witness_block_with_transactions(block, []) @@ -1491,7 +1489,7 @@ class SegWitTest(BitcoinTestFramework): # Test P2SH wrapped witness programs. def test_p2sh_witness(self, segwit_activated): - print("\tTesting P2SH witness transactions") + self.log.info("Testing P2SH witness transactions") assert(len(self.utxo)) @@ -1564,7 +1562,7 @@ class SegWitTest(BitcoinTestFramework): # To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to # the test. def test_upgrade_after_activation(self, node, node_id): - print("\tTesting software upgrade after softfork activation") + self.log.info("Testing software upgrade after softfork activation") assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind @@ -1573,7 +1571,7 @@ class SegWitTest(BitcoinTestFramework): # Restart with the new binary stop_node(node, node_id) - self.nodes[node_id] = start_node(node_id, self.options.tmpdir, ["-debug"]) + self.nodes[node_id] = start_node(node_id, self.options.tmpdir) connect_nodes(self.nodes[0], node_id) sync_blocks(self.nodes) @@ -1592,7 +1590,7 @@ class SegWitTest(BitcoinTestFramework): def test_witness_sigops(self): '''Ensure sigop counting is correct inside witnesses.''' - print("\tTesting sigops limit") + self.log.info("Testing sigops limit") assert(len(self.utxo)) @@ -1694,14 +1692,16 @@ class SegWitTest(BitcoinTestFramework): # TODO: test p2sh sigop counting def test_getblocktemplate_before_lockin(self): - print("\tTesting getblocktemplate setting of segwit versionbit (before lockin)") + self.log.info("Testing getblocktemplate setting of segwit versionbit (before lockin)") # Node0 is segwit aware, node2 is not. for node in [self.nodes[0], self.nodes[2]]: gbt_results = node.getblocktemplate() block_version = gbt_results['version'] - # If we're not indicating segwit support, we should not be signalling - # for segwit activation, nor should we get a witness commitment. - assert_equal(block_version & (1 << VB_WITNESS_BIT), 0) + # If we're not indicating segwit support, we will still be + # signalling for segwit activation. + assert_equal((block_version & (1 << VB_WITNESS_BIT) != 0), node == self.nodes[0]) + # If we don't specify the segwit rule, then we won't get a default + # commitment. assert('default_witness_commitment' not in gbt_results) # Workaround: @@ -1746,7 +1746,7 @@ class SegWitTest(BitcoinTestFramework): # Uncompressed pubkeys are no longer supported in default relay policy, # but (for now) are still valid in blocks. def test_uncompressed_pubkey(self): - print("\tTesting uncompressed pubkeys") + self.log.info("Testing uncompressed pubkeys") # Segwit transactions using uncompressed pubkeys are not accepted # under default policy, but should still pass consensus. key = CECKey() @@ -1848,7 +1848,7 @@ class SegWitTest(BitcoinTestFramework): self.utxo.append(UTXO(tx5.sha256, 0, tx5.vout[0].nValue)) def test_non_standard_witness(self): - print("\tTesting detection of non-standard P2WSH witness") + self.log.info("Testing detection of non-standard P2WSH witness") pad = chr(1).encode('latin-1') # Create scripts for tests @@ -1972,7 +1972,7 @@ class SegWitTest(BitcoinTestFramework): # Test logic begins here self.test_node.wait_for_verack() - print("\nStarting tests before segwit lock in:") + self.log.info("Starting tests before segwit lock in:") self.test_witness_services() # Verifies NODE_WITNESS self.test_non_witness_transaction() # non-witness tx's are accepted @@ -1987,7 +1987,7 @@ class SegWitTest(BitcoinTestFramework): sync_blocks(self.nodes) # At lockin, nothing should change. - print("\nTesting behavior post lockin, pre-activation") + self.log.info("Testing behavior post lockin, pre-activation") self.advance_to_segwit_lockin() # Retest unnecessary witnesses @@ -2000,7 +2000,7 @@ class SegWitTest(BitcoinTestFramework): sync_blocks(self.nodes) # Now activate segwit - print("\nTesting behavior after segwit activation") + self.log.info("Testing behavior after segwit activation") self.advance_to_segwit_active() sync_blocks(self.nodes) diff --git a/qa/rpc-tests/p2p-timeouts.py b/test/functional/p2p-timeouts.py index 7f596b6e4b..de4edd6800 100755 --- a/qa/rpc-tests/p2p-timeouts.py +++ b/test/functional/p2p-timeouts.py @@ -27,9 +27,9 @@ from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -class TestNode(SingleNodeConnCB): +class TestNode(NodeConnCB): def __init__(self): - SingleNodeConnCB.__init__(self) + super().__init__() self.connected = False self.received_version = False @@ -53,8 +53,7 @@ class TimeoutsTest(BitcoinTestFramework): self.nodes = [] # Start up node0 to be a version 1, pre-segwit node. - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, - [["-debug", "-logtimemicros=1"]]) + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir) def run_test(self): # Setup the p2p connections and start up the network thread. diff --git a/qa/rpc-tests/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index 8e3e361fc1..d4d03861a4 100755 --- a/qa/rpc-tests/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -28,7 +28,7 @@ VB_PATTERN = re.compile("^Warning.*versionbit") # p2p messages to a node, generating the messages in the main testing logic. class TestNode(NodeConnCB): def __init__(self): - NodeConnCB.__init__(self) + super().__init__() self.connection = None self.ping_counter = 1 self.last_pong = msg_pong() @@ -72,7 +72,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): # Open and close to create zero-length file with open(self.alert_filename, 'w', encoding='utf8') as _: pass - self.extra_args = [["-debug", "-logtimemicros=1", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""]] + self.extra_args = [["-alertnotify=echo %s >> \"" + self.alert_filename + "\""]] self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) # Send numblocks blocks via peer with nVersionToUse set. diff --git a/qa/rpc-tests/preciousblock.py b/test/functional/preciousblock.py index dde164f329..30b0b5a301 100755 --- a/qa/rpc-tests/preciousblock.py +++ b/test/functional/preciousblock.py @@ -39,13 +39,12 @@ class PreciousTest(BitcoinTestFramework): super().__init__() self.setup_clean_chain = True self.num_nodes = 3 - self.extra_args = [["-debug"]] * self.num_nodes def setup_network(self): self.nodes = self.setup_nodes() def run_test(self): - print("Ensure submitblock can in principle reorg to a competing chain") + self.log.info("Ensure submitblock can in principle reorg to a competing chain") self.nodes[0].generate(1) assert_equal(self.nodes[0].getblockcount(), 1) (hashY, hashZ) = self.nodes[1].generate(2) @@ -53,62 +52,62 @@ class PreciousTest(BitcoinTestFramework): node_sync_via_rpc(self.nodes[0:3]) assert_equal(self.nodes[0].getbestblockhash(), hashZ) - print("Mine blocks A-B-C on Node 0") + self.log.info("Mine blocks A-B-C on Node 0") (hashA, hashB, hashC) = self.nodes[0].generate(3) assert_equal(self.nodes[0].getblockcount(), 5) - print("Mine competing blocks E-F-G on Node 1") + self.log.info("Mine competing blocks E-F-G on Node 1") (hashE, hashF, hashG) = self.nodes[1].generate(3) assert_equal(self.nodes[1].getblockcount(), 5) assert(hashC != hashG) - print("Connect nodes and check no reorg occurs") + 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]) connect_nodes_bi(self.nodes,0,1) assert_equal(self.nodes[0].getbestblockhash(), hashC) assert_equal(self.nodes[1].getbestblockhash(), hashG) - print("Make Node0 prefer block G") + self.log.info("Make Node0 prefer block G") self.nodes[0].preciousblock(hashG) assert_equal(self.nodes[0].getbestblockhash(), hashG) - print("Make Node0 prefer block C again") + self.log.info("Make Node0 prefer block C again") self.nodes[0].preciousblock(hashC) assert_equal(self.nodes[0].getbestblockhash(), hashC) - print("Make Node1 prefer block C") + self.log.info("Make Node1 prefer block C") self.nodes[1].preciousblock(hashC) sync_chain(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC assert_equal(self.nodes[1].getbestblockhash(), hashC) - print("Make Node1 prefer block G again") + self.log.info("Make Node1 prefer block G again") self.nodes[1].preciousblock(hashG) assert_equal(self.nodes[1].getbestblockhash(), hashG) - print("Make Node0 prefer block G again") + self.log.info("Make Node0 prefer block G again") self.nodes[0].preciousblock(hashG) assert_equal(self.nodes[0].getbestblockhash(), hashG) - print("Make Node1 prefer block C again") + self.log.info("Make Node1 prefer block C again") self.nodes[1].preciousblock(hashC) assert_equal(self.nodes[1].getbestblockhash(), hashC) - print("Mine another block (E-F-G-)H on Node 0 and reorg Node 1") + self.log.info("Mine another block (E-F-G-)H on Node 0 and reorg Node 1") self.nodes[0].generate(1) assert_equal(self.nodes[0].getblockcount(), 6) sync_blocks(self.nodes[0:2]) hashH = self.nodes[0].getbestblockhash() assert_equal(self.nodes[1].getbestblockhash(), hashH) - print("Node1 should not be able to prefer block C anymore") + self.log.info("Node1 should not be able to prefer block C anymore") self.nodes[1].preciousblock(hashC) assert_equal(self.nodes[1].getbestblockhash(), hashH) - print("Mine competing blocks I-J-K-L on Node 2") + self.log.info("Mine competing blocks I-J-K-L on Node 2") self.nodes[2].generate(4) assert_equal(self.nodes[2].getblockcount(), 6) hashL = self.nodes[2].getbestblockhash() - print("Connect nodes and check no reorg occurs") + self.log.info("Connect nodes and check no reorg occurs") node_sync_via_rpc(self.nodes[1:3]) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) assert_equal(self.nodes[0].getbestblockhash(), hashH) assert_equal(self.nodes[1].getbestblockhash(), hashH) assert_equal(self.nodes[2].getbestblockhash(), hashL) - print("Make Node1 prefer block L") + self.log.info("Make Node1 prefer block L") self.nodes[1].preciousblock(hashL) assert_equal(self.nodes[1].getbestblockhash(), hashL) - print("Make Node2 prefer block H") + self.log.info("Make Node2 prefer block H") self.nodes[2].preciousblock(hashH) assert_equal(self.nodes[2].getbestblockhash(), hashH) diff --git a/qa/rpc-tests/prioritise_transaction.py b/test/functional/prioritise_transaction.py index 13be6eeead..0b04ad17ab 100755 --- a/qa/rpc-tests/prioritise_transaction.py +++ b/test/functional/prioritise_transaction.py @@ -21,7 +21,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.nodes = [] self.is_network_split = False - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-printpriority=1"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-printpriority=1"])) self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] def run_test(self): @@ -56,7 +56,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework): self.nodes[0].generate(1) mempool = self.nodes[0].getrawmempool() - print("Assert that prioritised transaction was mined") + self.log.info("Assert that prioritised transaction was mined") assert(txids[0][0] not in mempool) assert(txids[0][1] in mempool) @@ -88,7 +88,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework): # High fee transaction should not have been mined, but other high fee rate # transactions should have been. mempool = self.nodes[0].getrawmempool() - print("Assert that de-prioritised transaction is still in mempool") + self.log.info("Assert that de-prioritised transaction is still in mempool") assert(high_fee_tx in mempool) for x in txids[2]: if (x != high_fee_tx): @@ -107,20 +107,16 @@ class PrioritiseTransactionTest(BitcoinTestFramework): tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"] tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"] - try: - self.nodes[0].sendrawtransaction(tx_hex) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) # insufficient fee - assert(tx_id not in self.nodes[0].getrawmempool()) - else: - assert(False) + # This will raise an exception due to min relay fee not being met + assert_raises_jsonrpc(-26, "66: min relay fee not met", self.nodes[0].sendrawtransaction, tx_hex) + 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 # accepted. self.nodes[0].prioritisetransaction(tx_id, int(self.relayfee*COIN)) - print("Assert that prioritised free transaction is accepted to mempool") + 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()) diff --git a/qa/rpc-tests/proxy_test.py b/test/functional/proxy_test.py index e4e231f312..748e3e69f6 100755 --- a/qa/rpc-tests/proxy_test.py +++ b/test/functional/proxy_test.py @@ -49,6 +49,7 @@ class ProxyTest(BitcoinTestFramework): self.num_nodes = 4 self.setup_clean_chain = False + def setup_nodes(self): self.have_ipv6 = test_ipv6_local() # Create two proxies on different ports # ... one unauthenticated @@ -69,7 +70,7 @@ class ProxyTest(BitcoinTestFramework): self.conf3.unauth = True self.conf3.auth = True else: - print("Warning: testing without local IPv6 support") + self.log.warning("Testing without local IPv6 support") self.serv1 = Socks5Server(self.conf1) self.serv1.start() @@ -79,17 +80,16 @@ class ProxyTest(BitcoinTestFramework): self.serv3 = Socks5Server(self.conf3) self.serv3.start() - def setup_nodes(self): # Note: proxies are not used to connect to local nodes # this is because the proxy to use is based on CService.GetNetwork(), which return NET_UNROUTABLE for localhost args = [ - ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], - ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], - ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], + ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], + ['-listen', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], + ['-listen', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], [] ] if self.have_ipv6: - args[3] = ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] + args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] return start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) def node_test(self, node, proxies, auth, test_onion=True): diff --git a/qa/rpc-tests/pruning.py b/test/functional/pruning.py index d4924d058c..cc84c8c085 100755 --- a/qa/rpc-tests/pruning.py +++ b/test/functional/pruning.py @@ -41,19 +41,19 @@ class PruneTest(BitcoinTestFramework): self.is_network_split = False # Create nodes 0 and 1 to mine - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) + self.nodes.append(start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900)) # Create node 2 to test pruning - self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-prune=550"], timewait=900)) + self.nodes.append(start_node(2, self.options.tmpdir, ["-maxreceivebuffer=20000","-prune=550"], timewait=900)) self.prunedir = self.options.tmpdir+"/node2/regtest/blocks/" # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later) - self.nodes.append(start_node(3, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900)) - self.nodes.append(start_node(4, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900)) + self.nodes.append(start_node(3, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900)) + self.nodes.append(start_node(4, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900)) # Create nodes 5 to test wallet in prune mode, but do not connect - self.nodes.append(start_node(5, self.options.tmpdir, ["-debug=0", "-prune=550"])) + self.nodes.append(start_node(5, self.options.tmpdir, ["-prune=550"])) # Determine default relay fee self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] @@ -79,9 +79,9 @@ class PruneTest(BitcoinTestFramework): def test_height_min(self): if not os.path.isfile(self.prunedir+"blk00000.dat"): raise AssertionError("blk00000.dat is missing, pruning too early") - print("Success") - print("Though we're already using more than 550MiB, current usage:", calc_usage(self.prunedir)) - print("Mining 25 more blocks should cause the first block file to be pruned") + 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) @@ -92,22 +92,22 @@ class PruneTest(BitcoinTestFramework): if time.time() - waitstart > 30: raise AssertionError("blk00000.dat not pruned when it should be") - print("Success") + self.log.info("Success") usage = calc_usage(self.prunedir) - print("Usage should be below target:", usage) + self.log.info("Usage should be below target: %d" % usage) if (usage > 550): raise AssertionError("Pruning target not being met") def create_chain_with_staleblocks(self): # Create stale blocks in manageable sized chunks - print("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds") + self.log.info("Mine 24 (stale) blocks on Node 1, followed by 25 (main chain) block reorg from Node 0, for 12 rounds") 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.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900) + self.nodes[0]=start_node(0, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=999000", "-checkblocks=5"], timewait=900) # Mine 24 blocks in node 1 for i in range(24): if j == 0: @@ -124,7 +124,7 @@ class PruneTest(BitcoinTestFramework): connect_nodes(self.nodes[2], 0) sync_blocks(self.nodes[0:3]) - print("Usage can be over target because of high stale rate:", calc_usage(self.prunedir)) + 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 @@ -132,14 +132,14 @@ class PruneTest(BitcoinTestFramework): # 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.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) height = self.nodes[1].getblockcount() - print("Current block height:", height) + self.log.info("Current block height: %d" % height) invalidheight = height-287 badhash = self.nodes[1].getblockhash(invalidheight) - print("Invalidating block at height:",invalidheight,badhash) + self.log.info("Invalidating block %s at height %d" % (badhash,invalidheight)) self.nodes[1].invalidateblock(badhash) # We've now switched to our previously mined-24 block fork on node 1, but thats not what we want @@ -151,24 +151,24 @@ class PruneTest(BitcoinTestFramework): curhash = self.nodes[1].getblockhash(invalidheight - 1) assert(self.nodes[1].getblockcount() == invalidheight - 1) - print("New best height", self.nodes[1].getblockcount()) + 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.nodes[1]=start_node(1, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + self.nodes[1]=start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) - print("Generating new longer chain of 300 more blocks") + self.log.info("Generating new longer chain of 300 more blocks") self.nodes[1].generate(300) - print("Reconnect nodes") + 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) - print("Verify height on node 2:",self.nodes[2].getblockcount()) - print("Usage possibly still high bc of stale blocks in block files:", calc_usage(self.prunedir)) + 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)) - print("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 blocks so we have requisite history (some blocks will be big and cause pruning of previous chain)") for i in range(22): # This can be slow, so do this in multiple RPC calls to avoid # RPC timeouts. @@ -176,7 +176,7 @@ class PruneTest(BitcoinTestFramework): sync_blocks(self.nodes[0:3], timeout=300) usage = calc_usage(self.prunedir) - print("Usage should be below target:", usage) + self.log.info("Usage should be below target: %d" % usage) if (usage > 550): raise AssertionError("Pruning target not being met") @@ -184,11 +184,8 @@ class PruneTest(BitcoinTestFramework): def reorg_back(self): # Verify that a block on the old main chain fork has been pruned away - try: - self.nodes[2].getblock(self.forkhash) - raise AssertionError("Old block wasn't pruned so can't test redownload") - except JSONRPCException as e: - print("Will need to redownload block",self.forkheight) + assert_raises_jsonrpc(-1, "Block not available (pruned data)", self.nodes[2].getblock, self.forkhash) + self.log.info("Will need to redownload block %d" % self.forkheight) # Verify that we have enough history to reorg back to the fork point # Although this is more than 288 blocks, because this chain was written more recently @@ -212,14 +209,14 @@ class PruneTest(BitcoinTestFramework): # At this point node 2 is within 288 blocks of the fork point so it will preserve its ability to reorg if self.nodes[2].getblockcount() < self.mainchainheight: blocks_to_mine = first_reorg_height + 1 - self.mainchainheight - print("Rewind node 0 to prev main chain to mine longer chain to trigger redownload. Blocks needed:", blocks_to_mine) + 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) goalbesthash = self.nodes[0].generate(blocks_to_mine)[-1] goalbestheight = first_reorg_height + 1 - print("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload") + self.log.info("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload") waitstart = time.time() while self.nodes[2].getblockcount() < goalbestheight: time.sleep(0.1) @@ -231,13 +228,13 @@ class PruneTest(BitcoinTestFramework): def manual_test(self, node_number, use_timestamp): # at this point, node has 995 blocks and has not yet run in prune mode - node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0"], timewait=900) + node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, timewait=900) assert_equal(node.getblockcount(), 995) - assert_raises_message(JSONRPCException, "not in prune mode", node.pruneblockchain, 500) + assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500) self.stop_node(node_number) # now re-start in manual pruning mode - node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0","-prune=1"], timewait=900) + node = self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900) assert_equal(node.getblockcount(), 995) def height(index): @@ -265,14 +262,14 @@ class PruneTest(BitcoinTestFramework): return os.path.isfile(self.options.tmpdir + "/node{}/regtest/blocks/blk{:05}.dat".format(node_number, index)) # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000) - assert_raises_message(JSONRPCException, "Blockchain is too short for pruning", node.pruneblockchain, height(500)) + assert_raises_jsonrpc(-1, "Blockchain is too short for pruning", node.pruneblockchain, height(500)) # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight) node.generate(6) assert_equal(node.getblockchaininfo()["blocks"], 1001) # negative heights should raise an exception - assert_raises_message(JSONRPCException, "Negative", node.pruneblockchain, -10) + assert_raises_jsonrpc(-8, "Negative", node.pruneblockchain, -10) # height=100 too low to prune first block file so this is a no-op prune(100) @@ -311,36 +308,30 @@ class PruneTest(BitcoinTestFramework): # stop node, start back up with auto-prune at 550MB, make sure still runs self.stop_node(node_number) - self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-debug=0","-prune=550"], timewait=900) + self.nodes[node_number] = start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900) - print("Success") + self.log.info("Success") def wallet_test(self): # check that the pruning node's wallet is still in good shape - print("Stop and start pruning node to trigger wallet rescan") - try: - self.stop_node(2) - start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"]) - print("Success") - except Exception as detail: - raise AssertionError("Wallet test: unable to re-start the pruning node") + self.log.info("Stop and start pruning node to trigger wallet rescan") + self.stop_node(2) + start_node(2, self.options.tmpdir, ["-prune=550"]) + self.log.info("Success") # check that wallet loads loads successfully when restarting a pruned node after IBD. # this was reported to fail in #7494. - print ("Syncing node 5 to test wallet") + 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) - try: - self.stop_node(5) #stop and start to trigger rescan - start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"]) - print ("Success") - except Exception as detail: - raise AssertionError("Wallet test: unable to re-start node5") + self.stop_node(5) #stop and start to trigger rescan + start_node(5, self.options.tmpdir, ["-prune=550"]) + self.log.info("Success") def run_test(self): - print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)") - print("Mining a big blockchain of 995 blocks") + 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") self.create_big_chain() # Chain diagram key: # * blocks on main chain @@ -355,12 +346,12 @@ class PruneTest(BitcoinTestFramework): self.stop_node(3) self.stop_node(4) - print("Check that we haven't started pruning yet because we're below PruneAfterHeight") + self.log.info("Check that we haven't started pruning yet because we're below PruneAfterHeight") self.test_height_min() # Extend this chain past the PruneAfterHeight # N0=N1=N2 **...*(1020) - print("Check that we'll exceed disk space target if we have a very high stale block rate") + self.log.info("Check that we'll exceed disk space target if we have a very high stale block rate") self.create_chain_with_staleblocks() # Disconnect N0 # And mine a 24 block chain on N1 and a separate 25 block chain on N0 @@ -384,7 +375,7 @@ class PruneTest(BitcoinTestFramework): self.mainchainheight = self.nodes[2].getblockcount() #1320 self.mainchainhash2 = self.nodes[2].getblockhash(self.mainchainheight) - print("Check that we can survive a 288 block reorg still") + self.log.info("Check that we can survive a 288 block reorg still") (self.forkheight,self.forkhash) = self.reorg_test() #(1033, ) # Now create a 288 block reorg by mining a longer chain on N1 # First disconnect N1 @@ -417,7 +408,7 @@ class PruneTest(BitcoinTestFramework): # \ # *...**(1320) - print("Test that we can rerequest a block we previously pruned if needed for a reorg") + self.log.info("Test that we can rerequest a block we previously pruned if needed for a reorg") self.reorg_back() # Verify that N2 still has block 1033 on current chain (@), but not on main chain (*) # Invalidate 1033 on current chain (@) on N2 and we should be able to reorg to @@ -437,16 +428,16 @@ class PruneTest(BitcoinTestFramework): # # N1 doesn't change because 1033 on main chain (*) is invalid - print("Test manual pruning with block indices") + self.log.info("Test manual pruning with block indices") self.manual_test(3, use_timestamp=False) - print("Test manual pruning with timestamps") + self.log.info("Test manual pruning with timestamps") self.manual_test(4, use_timestamp=True) - print("Test wallet re-scan") + self.log.info("Test wallet re-scan") self.wallet_test() - print("Done") + self.log.info("Done") if __name__ == '__main__': PruneTest().main() diff --git a/qa/rpc-tests/rawtransactions.py b/test/functional/rawtransactions.py index 5adef31207..d4c684136c 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/test/functional/rawtransactions.py @@ -61,13 +61,8 @@ class RawTransactionsTest(BitcoinTestFramework): rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].signrawtransaction(rawtx) - try: - rawtx = self.nodes[2].sendrawtransaction(rawtx['hex']) - except JSONRPCException as e: - assert("Missing inputs" in e.error['message']) - else: - assert(False) - + # This will raise an exception since there are missing inputs + assert_raises_jsonrpc(-25, "Missing inputs", self.nodes[2].sendrawtransaction, rawtx['hex']) ######################### # RAW TX MULTISIG TESTS # @@ -109,7 +104,6 @@ class RawTransactionsTest(BitcoinTestFramework): txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) decTx = self.nodes[0].gettransaction(txId) rawTx = self.nodes[0].decoderawtransaction(decTx['hex']) - sPK = rawTx['vout'][0]['scriptPubKey']['hex'] self.sync_all() self.nodes[0].generate(1) self.sync_all() @@ -161,13 +155,13 @@ class RawTransactionsTest(BitcoinTestFramework): assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex']) # 6. invalid parameters - supply txid and string "Flase" - assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, "Flase") + assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase") # 7. invalid parameters - supply txid and empty array - assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, []) + assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, []) # 8. invalid parameters - supply txid and empty dict - assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, {}) + assert_raises_jsonrpc(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {}) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] outputs = { self.nodes[0].getnewaddress() : 1 } @@ -175,13 +169,15 @@ class RawTransactionsTest(BitcoinTestFramework): decrawtx= self.nodes[0].decoderawtransaction(rawtx) assert_equal(decrawtx['vin'][0]['sequence'], 1000) + # 9. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}] outputs = { self.nodes[0].getnewaddress() : 1 } - assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs) + assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) + # 10. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}] outputs = { self.nodes[0].getnewaddress() : 1 } - assert_raises(JSONRPCException, self.nodes[0].createrawtransaction, inputs, outputs) + assert_raises_jsonrpc(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}] outputs = { self.nodes[0].getnewaddress() : 1 } diff --git a/qa/rpc-tests/receivedby.py b/test/functional/receivedby.py index 248bcdbd68..248bcdbd68 100755 --- a/qa/rpc-tests/receivedby.py +++ b/test/functional/receivedby.py diff --git a/qa/rpc-tests/reindex.py b/test/functional/reindex.py index 1b547a920f..0cebb0466f 100755 --- a/qa/rpc-tests/reindex.py +++ b/test/functional/reindex.py @@ -31,12 +31,12 @@ class ReindexTest(BitcoinTestFramework): self.nodes[0].generate(3) blockcount = self.nodes[0].getblockcount() stop_nodes(self.nodes) - extra_args = [["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]] + extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]] self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args) while self.nodes[0].getblockcount() < blockcount: time.sleep(0.1) assert_equal(self.nodes[0].getblockcount(), blockcount) - print("Success") + self.log.info("Success") def run_test(self): self.reindex(False) diff --git a/qa/rpc-tests/replace-by-fee.py b/test/functional/replace-by-fee.py index 51cbb4dc4c..163c304eba 100755 --- a/qa/rpc-tests/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -25,19 +25,15 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): fee = 1*COIN while node.getbalance() < satoshi_round((amount + fee)/COIN): node.generate(100) - #print (node.getbalance(), amount, fee) new_addr = node.getnewaddress() - #print new_addr txid = node.sendtoaddress(new_addr, satoshi_round((amount+fee)/COIN)) tx1 = node.getrawtransaction(txid, 1) txid = int(txid, 16) i = None for i, txout in enumerate(tx1['vout']): - #print i, txout['scriptPubKey']['addresses'] if txout['scriptPubKey']['addresses'] == [new_addr]: - #print i break assert i is not None @@ -72,7 +68,7 @@ class ReplaceByFeeTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-debug", + self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-whitelist=127.0.0.1", "-limitancestorcount=50", "-limitancestorsize=101", @@ -84,34 +80,34 @@ class ReplaceByFeeTest(BitcoinTestFramework): def run_test(self): make_utxo(self.nodes[0], 1*COIN) - print("Running test simple doublespend...") + self.log.info("Running test simple doublespend...") self.test_simple_doublespend() - print("Running test doublespend chain...") + self.log.info("Running test doublespend chain...") self.test_doublespend_chain() - print("Running test doublespend tree...") + self.log.info("Running test doublespend tree...") self.test_doublespend_tree() - print("Running test replacement feeperkb...") + self.log.info("Running test replacement feeperkb...") self.test_replacement_feeperkb() - print("Running test spends of conflicting outputs...") + self.log.info("Running test spends of conflicting outputs...") self.test_spends_of_conflicting_outputs() - print("Running test new unconfirmed inputs...") + self.log.info("Running test new unconfirmed inputs...") self.test_new_unconfirmed_inputs() - print("Running test too many replacements...") + self.log.info("Running test too many replacements...") self.test_too_many_replacements() - print("Running test opt-in...") + self.log.info("Running test opt-in...") self.test_opt_in() - print("Running test prioritised transactions...") + self.log.info("Running test prioritised transactions...") self.test_prioritised_transactions() - print("Passed\n") + self.log.info("Passed") def test_simple_doublespend(self): """Simple doublespend""" @@ -129,12 +125,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx1b.vout = [CTxOut(1*COIN, CScript([b'b']))] tx1b_hex = txToHex(tx1b) - try: - tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) # insufficient fee - else: - assert(False) + # This will raise an exception due to insufficient fee + assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) # Extra 0.1 BTC fee tx1b = CTransaction() @@ -176,12 +168,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): dbl_tx.vout = [CTxOut(initial_nValue - 30*COIN, CScript([1]))] dbl_tx_hex = txToHex(dbl_tx) - try: - self.nodes[0].sendrawtransaction(dbl_tx_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) # insufficient fee - else: - assert(False) # transaction mistakenly accepted! + # This will raise an exception due to insufficient fee + assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) # Accepted with sufficient fee dbl_tx = CTransaction() @@ -241,12 +229,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] dbl_tx.vout = [CTxOut(initial_nValue - fee*n, CScript([1]))] dbl_tx_hex = txToHex(dbl_tx) - try: - self.nodes[0].sendrawtransaction(dbl_tx_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) # insufficient fee - else: - assert(False) + # This will raise an exception due to insufficient fee + assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) # 1 BTC fee is enough dbl_tx = CTransaction() @@ -273,13 +257,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)] dbl_tx.vout = [CTxOut(initial_nValue - 2*fee*n, CScript([1]))] dbl_tx_hex = txToHex(dbl_tx) - try: - self.nodes[0].sendrawtransaction(dbl_tx_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - assert_equal("too many potential replacements" in exp.error['message'], True) - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, True) for tx in tree_txs: tx.rehash() @@ -302,12 +281,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx1b.vout = [CTxOut(int(0.001*COIN), CScript([b'a'*999000]))] tx1b_hex = txToHex(tx1b) - try: - tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) # insufficient fee - else: - assert(False) + # This will raise an exception due to insufficient fee + assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) def test_spends_of_conflicting_outputs(self): """Replacements that spend conflicting tx outputs are rejected""" @@ -329,12 +304,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx2.vout = tx1a.vout tx2_hex = txToHex(tx2) - try: - tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True) # Spend tx1a's output to test the indirect case. tx1b = CTransaction() @@ -350,12 +321,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx2.vout = tx1a.vout tx2_hex = txToHex(tx2) - try: - tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "bad-txns-spends-conflicting-tx", self.nodes[0].sendrawtransaction, tx2_hex, True) def test_new_unconfirmed_inputs(self): """Replacements that add new unconfirmed inputs are rejected""" @@ -373,12 +340,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx2.vout = tx1.vout tx2_hex = txToHex(tx2) - try: - tx2_txid = self.nodes[0].sendrawtransaction(tx2_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "replacement-adds-unconfirmed", self.nodes[0].sendrawtransaction, tx2_hex, True) def test_too_many_replacements(self): """Replacements that evict too many transactions are rejected""" @@ -423,13 +386,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): double_tx.vout = [CTxOut(double_spend_value, CScript([b'a']))] double_tx_hex = txToHex(double_tx) - try: - self.nodes[0].sendrawtransaction(double_tx_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - assert_equal("too many potential replacements" in exp.error['message'], True) - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, double_tx_hex, True) # If we remove an input, it should pass double_tx = CTransaction() @@ -455,13 +413,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] tx1b_hex = txToHex(tx1b) - try: - tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - print(tx1b_txid) - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx1b_hex, True) tx1_outpoint = make_utxo(self.nodes[0], int(1.1*COIN)) @@ -478,12 +431,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx2b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] tx2b_hex = txToHex(tx2b) - try: - tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[0].sendrawtransaction, tx2b_hex, True) # Now create a new transaction that spends from tx1a and tx2a # opt-in on one of the inputs @@ -535,12 +484,7 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx1b_hex = txToHex(tx1b) # Verify tx1b cannot replace tx1a. - try: - tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - assert(False) + assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) # Use prioritisetransaction to set tx1a's fee to 0. self.nodes[0].prioritisetransaction(tx1a_txid, int(-0.1*COIN)) @@ -567,12 +511,7 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx2b_hex = txToHex(tx2b) # Verify tx2b cannot replace tx2a. - try: - tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) - except JSONRPCException as exp: - assert_equal(exp.error['code'], -26) - else: - assert(False) + assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx2b_hex, True) # Now prioritise tx2b to have a higher modified fee self.nodes[0].prioritisetransaction(tx2b.hash, int(0.1*COIN)) diff --git a/qa/rpc-tests/rest.py b/test/functional/rest.py index 9ca1cc187a..776211d301 100755 --- a/qa/rpc-tests/rest.py +++ b/test/functional/rest.py @@ -58,7 +58,7 @@ class RESTTest (BitcoinTestFramework): def run_test(self): url = urllib.parse.urlparse(self.nodes[0].url) - print("Mining blocks...") + self.log.info("Mining blocks...") self.nodes[0].generate(1) self.sync_all() diff --git a/qa/rpc-tests/rpcbind_test.py b/test/functional/rpcbind_test.py index 499fe33679..efc36481d1 100755 --- a/qa/rpc-tests/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -4,6 +4,9 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test running bitcoind with the -rpcbind and -rpcallowip options.""" +import socket +import sys + from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * from test_framework.netutil import * @@ -52,7 +55,9 @@ class RPCBindTest(BitcoinTestFramework): def run_test(self): # due to OS-specific network stats queries, this test works only on Linux - assert(sys.platform.startswith('linux')) + if not sys.platform.startswith('linux'): + self.log.warning("This test can only be run on linux. Skipping test.") + sys.exit(self.TEST_EXIT_SKIPPED) # find the first non-loopback interface for testing non_loopback_ip = None for name,ip in all_interfaces(): @@ -60,8 +65,17 @@ class RPCBindTest(BitcoinTestFramework): non_loopback_ip = ip break if non_loopback_ip is None: - assert(not 'This test requires at least one non-loopback IPv4 interface') - print("Using interface %s for testing" % non_loopback_ip) + self.log.warning("This test requires at least one non-loopback IPv4 interface. Skipping test.") + sys.exit(self.TEST_EXIT_SKIPPED) + try: + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s.connect(("::1",1)) + s.close + except OSError: + self.log.warning("This test requires IPv6 support. Skipping test.") + sys.exit(self.TEST_EXIT_SKIPPED) + + self.log.info("Using interface %s for testing" % non_loopback_ip) defaultport = rpc_port(0) @@ -92,11 +106,7 @@ class RPCBindTest(BitcoinTestFramework): # Check that with invalid rpcallowip, we are denied self.run_allowip_test([non_loopback_ip], non_loopback_ip, defaultport) - try: - self.run_allowip_test(['1.1.1.1'], non_loopback_ip, defaultport) - assert(not 'Connection not denied by rpcallowip as expected') - except JSONRPCException: - pass + assert_raises_jsonrpc(-342, "non-JSON HTTP response with '403 Forbidden' from server", self.run_allowip_test, ['1.1.1.1'], non_loopback_ip, defaultport) if __name__ == '__main__': RPCBindTest().main() diff --git a/qa/rpc-tests/rpcnamedargs.py b/test/functional/rpcnamedargs.py index f6175c8ca7..f6175c8ca7 100755 --- a/qa/rpc-tests/rpcnamedargs.py +++ b/test/functional/rpcnamedargs.py diff --git a/qa/rpc-tests/segwit.py b/test/functional/segwit.py index 761c00dc01..a1fffcb81a 100755 --- a/qa/rpc-tests/segwit.py +++ b/test/functional/segwit.py @@ -6,11 +6,10 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -from test_framework.mininode import sha256, ripemd160, CTransaction, CTxIn, COutPoint, CTxOut +from test_framework.mininode import sha256, CTransaction, CTxIn, COutPoint, CTxOut, COIN, ToHex, FromHex from test_framework.address import script_to_p2sh, key_to_p2pkh -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 +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 from io import BytesIO -from test_framework.mininode import FromHex NODE_0 = 0 NODE_1 = 1 @@ -18,47 +17,49 @@ NODE_2 = 2 WIT_V0 = 0 WIT_V1 = 1 -def witness_script(version, pubkey): - if (version == 0): - pubkeyhash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pubkey)))) - pkscript = "0014" + pubkeyhash - elif (version == 1): - # 1-of-1 multisig - scripthash = bytes_to_hex_str(sha256(hex_str_to_bytes("5121" + pubkey + "51ae"))) - pkscript = "0020" + scripthash +# Create a scriptPubKey corresponding to either a P2WPKH output for the +# given pubkey, or a P2WSH output of a 1-of-1 multisig for the given +# pubkey. Returns the hex encoding of the scriptPubKey. +def witness_script(use_p2wsh, pubkey): + if (use_p2wsh == False): + # P2WPKH instead + pubkeyhash = hash160(hex_str_to_bytes(pubkey)) + pkscript = CScript([OP_0, pubkeyhash]) else: - assert("Wrong version" == "0 or 1") - return pkscript - -def addlength(script): - scriptlen = format(len(script)//2, 'x') - assert(len(scriptlen) == 2) - return scriptlen + script - -def create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount): - pkscript = witness_script(version, pubkey) + # 1-of-1 multisig + 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 a transaction (in hex) that spends the given utxo to a segwit output, +# optionally wrapping the segwit output using P2SH. +def create_witnessprogram(use_p2wsh, utxo, pubkey, encode_p2sh, amount): + pkscript = hex_str_to_bytes(witness_script(use_p2wsh, pubkey)) if (encode_p2sh): - p2sh_hash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pkscript)))) - pkscript = "a914"+p2sh_hash+"87" - inputs = [] - outputs = {} - inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]} ) - DUMMY_P2SH = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP" - outputs[DUMMY_P2SH] = amount - tx_to_witness = node.createrawtransaction(inputs,outputs) - #replace dummy output with our own - tx_to_witness = tx_to_witness[0:110] + addlength(pkscript) + tx_to_witness[-8:] - return tx_to_witness - -def send_to_witness(version, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""): - tx_to_witness = create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount) + p2sh_hash = hash160(pkscript) + pkscript = CScript([OP_HASH160, p2sh_hash, OP_EQUAL]) + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), b"")) + tx.vout.append(CTxOut(int(amount*COIN), pkscript)) + return ToHex(tx) + +# Create a transaction spending a given utxo to a segwit output corresponding +# to the given pubkey: use_p2wsh determines whether to use P2WPKH or P2WSH; +# encode_p2sh determines whether to wrap in P2SH. +# sign=True will have the given node sign the transaction. +# insert_redeem_script will be added to the scriptSig, if given. +def send_to_witness(use_p2wsh, node, utxo, pubkey, encode_p2sh, amount, sign=True, insert_redeem_script=""): + tx_to_witness = create_witnessprogram(use_p2wsh, utxo, pubkey, encode_p2sh, amount) if (sign): signed = node.signrawtransaction(tx_to_witness) assert("errors" not in signed or len(["errors"]) == 0) return node.sendrawtransaction(signed["hex"]) else: if (insert_redeem_script): - tx_to_witness = tx_to_witness[0:82] + addlength(insert_redeem_script) + tx_to_witness[84:] + tx = FromHex(CTransaction(), tx_to_witness) + tx.vin[0].scriptSig += CScript([hex_str_to_bytes(insert_redeem_script)]) + tx_to_witness = ToHex(tx) return node.sendrawtransaction(tx_to_witness) @@ -82,9 +83,9 @@ class SegWitTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, ["-logtimemicros", "-debug", "-walletprematurewitness", "-rpcserialversion=0"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"])) - self.nodes.append(start_node(2, self.options.tmpdir, ["-logtimemicros", "-debug", "-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) + self.nodes.append(start_node(0, self.options.tmpdir, ["-walletprematurewitness", "-rpcserialversion=0"])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=4", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness", "-rpcserialversion=1"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=536870915", "-promiscuousmempoolflags=517", "-prematurewitness", "-walletprematurewitness"])) connect_nodes(self.nodes[1], 0) connect_nodes(self.nodes[2], 1) connect_nodes(self.nodes[0], 2) @@ -103,28 +104,18 @@ class SegWitTest(BitcoinTestFramework): assert_equal(len(node.getblock(block[0])["tx"]), 1) sync_blocks(self.nodes) - def fail_accept(self, node, txid, sign, redeem_script=""): - try: - send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) - except JSONRPCException as exp: - assert(exp.error["code"] == -26) - else: - raise AssertionError("Tx should not have been accepted") + def fail_accept(self, node, error_msg, txid, sign, redeem_script=""): + assert_raises_jsonrpc(-26, error_msg, send_to_witness, 1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) def fail_mine(self, node, txid, sign, redeem_script=""): send_to_witness(1, node, getutxo(txid), self.pubkey[0], False, Decimal("49.998"), sign, redeem_script) - try: - node.generate(1) - except JSONRPCException as exp: - assert(exp.error["code"] == -1) - else: - raise AssertionError("Created valid block when TestBlockValidity should have failed") + assert_raises_jsonrpc(-1, "CreateNewBlock: TestBlockValidity failed", node.generate, 1) sync_blocks(self.nodes) def run_test(self): self.nodes[0].generate(161) #block 161 - print("Verify sigops are counted in GBT with pre-BIP141 rules before the fork") + 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({}) assert(tmpl['sizelimit'] == 1000000) @@ -173,22 +164,22 @@ class SegWitTest(BitcoinTestFramework): self.nodes[0].generate(260) #block 423 sync_blocks(self.nodes) - print("Verify default node can't accept any witness format txs before fork") + self.log.info("Verify default node can't accept any witness format txs before fork") # unsigned, no scriptsig - self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], False) - self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], False) - self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False) - self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False) + self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False) + self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False) + self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False) + self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False) # unsigned with redeem script - self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], False, addlength(witness_script(0, self.pubkey[0]))) - self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], False, addlength(witness_script(1, self.pubkey[0]))) + self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0])) + self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0])) # signed - self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) - self.fail_accept(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) - self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) - self.fail_accept(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) + self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True) + self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True) + self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True) + self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True) - print("Verify witness txs are skipped for mining before the fork") + 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 self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425 self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426 @@ -196,19 +187,19 @@ class SegWitTest(BitcoinTestFramework): # TODO: An old node would see these txs without witnesses and be able to mine them - print("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork") + self.log.info("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork") self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428 self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429 - print("Verify unsigned p2sh witness txs without a redeem script are invalid") - self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False) - self.fail_accept(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False) + self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid") + self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False) + self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False) - print("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork") - self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, addlength(witness_script(0, self.pubkey[2]))) #block 430 - self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, addlength(witness_script(1, self.pubkey[2]))) #block 431 + self.log.info("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork") + self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, witness_script(False, self.pubkey[2])) #block 430 + self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, witness_script(True, self.pubkey[2])) #block 431 - print("Verify previous witness txs skipped for mining can now be mined") + self.log.info("Verify previous witness txs skipped for mining can now be mined") assert_equal(len(self.nodes[2].getrawmempool()), 4) block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3) sync_blocks(self.nodes) @@ -216,7 +207,7 @@ class SegWitTest(BitcoinTestFramework): segwit_tx_list = self.nodes[2].getblock(block[0])["tx"] assert_equal(len(segwit_tx_list), 5) - print("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") + self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) for i in range(len(segwit_tx_list)): @@ -227,19 +218,19 @@ class SegWitTest(BitcoinTestFramework): assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness())) - print("Verify witness txs without witness data are invalid after the fork") + self.log.info("Verify witness txs without witness data are invalid after the fork") self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False) self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False) - self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, addlength(witness_script(0, self.pubkey[2]))) - self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, addlength(witness_script(1, self.pubkey[2]))) + self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, witness_script(False, self.pubkey[2])) + self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, witness_script(True, self.pubkey[2])) - print("Verify default node can now use witness txs") + self.log.info("Verify default node can now use witness txs") self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432 self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435 - print("Verify sigops are counted in GBT with BIP141 rules after the fork") + 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 @@ -248,11 +239,56 @@ class SegWitTest(BitcoinTestFramework): assert(tmpl['transactions'][0]['txid'] == txid) assert(tmpl['transactions'][0]['sigops'] == 8) - print("Non-segwit miners are not able to use GBT response after activation.") - send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.998")) - assert_raises_jsonrpc(-8, "Support for 'segwit' rule requires explicit client support", self.nodes[0].getblocktemplate, {}) + self.nodes[0].generate(1) # Mine a block to clear the gbt cache - print("Verify behaviour of importaddress, addwitnessaddress and listunspent") + self.log.info("Non-segwit miners are able to use GBT response after activation.") + # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) -> + # tx2 (segwit input, paying to a non-segwit output) -> + # tx3 (non-segwit input, paying to a non-segwit output). + # tx1 is allowed to appear in the block, but no others. + txid1 = send_to_witness(1, self.nodes[0], find_unspent(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()) + + # Now create tx2, which will spend from txid1. + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b'')) + tx.vout.append(CTxOut(int(49.99*COIN), CScript([OP_TRUE]))) + tx2_hex = self.nodes[0].signrawtransaction(ToHex(tx))['hex'] + txid2 = self.nodes[0].sendrawtransaction(tx2_hex) + tx = FromHex(CTransaction(), tx2_hex) + assert(not tx.wit.is_null()) + + # Now create tx3, which will spend from txid2 + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b"")) + tx.vout.append(CTxOut(int(49.95*COIN), CScript([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()) + + # Now try calling getblocktemplate() without segwit support. + template = self.nodes[0].getblocktemplate() + + # Check that tx1 is the only transaction of the 3 in the template. + template_txids = [ t['txid'] for t in template['transactions'] ] + assert(txid2 not in template_txids and txid3 not in template_txids) + assert(txid1 in template_txids) + + # Check that running with segwit support results in all 3 being included. + 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) + + # Mine a block to clear the gbt cache again. + self.nodes[0].generate(1) + + self.log.info("Verify behaviour of importaddress, addwitnessaddress and listunspent") # Some public keys to be used later pubkeys = [ @@ -410,10 +446,13 @@ class SegWitTest(BitcoinTestFramework): importlist.append(bytes_to_hex_str(p2wshop1)) for i in importlist: + # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC + # exceptions and continue. try: self.nodes[0].importaddress(i,"",False,True) except JSONRPCException as exp: assert_equal(exp.error["message"], "The wallet already contains the private key for this address or script") + assert_equal(exp.error["code"], -4) self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey @@ -428,12 +467,7 @@ class SegWitTest(BitcoinTestFramework): # note that no witness address should be returned by unsolvable addresses # the multisig_without_privkey_address will fail because its keys were not added with importpubkey for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address + [multisig_without_privkey_address]: - try: - self.nodes[0].addwitnessaddress(i) - except JSONRPCException as exp: - assert_equal(exp.error["message"], "Public key or redeemscript not known to wallet, or the key is uncompressed") - else: - assert(False) + assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) for i in compressed_spendable_address + compressed_solvable_address: witaddress = self.nodes[0].addwitnessaddress(i) @@ -512,12 +546,8 @@ class SegWitTest(BitcoinTestFramework): # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress # premature_witaddress are not accepted until the script is added with addwitnessaddress first for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress + [compressed_solvable_address[1]]: - try: - self.nodes[0].addwitnessaddress(i) - except JSONRPCException as exp: - assert_equal(exp.error["message"], "Public key or redeemscript not known to wallet, or the key is uncompressed") - else: - assert(False) + # This will raise an exception + assert_raises_jsonrpc(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) # after importaddress it should pass addwitnessaddress v = self.nodes[0].validateaddress(compressed_solvable_address[1]) diff --git a/qa/rpc-tests/sendheaders.py b/test/functional/sendheaders.py index 16ca4a4913..1a7475ae84 100755 --- a/qa/rpc-tests/sendheaders.py +++ b/test/functional/sendheaders.py @@ -81,9 +81,9 @@ from test_framework.blocktools import create_block, create_coinbase direct_fetch_response_time = 0.05 -class BaseNode(SingleNodeConnCB): +class BaseNode(NodeConnCB): def __init__(self): - SingleNodeConnCB.__init__(self) + super().__init__() self.last_inv = None self.last_headers = None self.last_block = None @@ -229,7 +229,7 @@ class SendHeadersTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] - self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [["-debug", "-logtimemicros=1"]]*2) + self.nodes = start_nodes(self.num_nodes, self.options.tmpdir) connect_nodes(self.nodes[0], 1) # mine count blocks and return the new tip @@ -283,7 +283,7 @@ class SendHeadersTest(BitcoinTestFramework): # PART 1 # 1. Mine a block; expect inv announcements each time - print("Part 1: headers don't start before sendheaders message...") + self.log.info("Part 1: headers don't start before sendheaders message...") for i in range(4): old_tip = tip tip = self.mine_blocks(1) @@ -314,8 +314,8 @@ class SendHeadersTest(BitcoinTestFramework): inv_node.clear_last_announcement() test_node.clear_last_announcement() - print("Part 1: success!") - print("Part 2: announce blocks with headers after sendheaders message...") + self.log.info("Part 1: success!") + self.log.info("Part 2: announce blocks with headers after sendheaders message...") # PART 2 # 2. Send a sendheaders message and test that headers announcements # commence and keep working. @@ -376,9 +376,9 @@ class SendHeadersTest(BitcoinTestFramework): height += 1 block_time += 1 - print("Part 2: success!") + self.log.info("Part 2: success!") - print("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...") + self.log.info("Part 3: headers announcements can stop after large reorg, and resume after headers/inv from peer...") # PART 3. Headers announcements can stop after large reorg, and resume after # getheaders or inv from peer. @@ -440,9 +440,9 @@ class SendHeadersTest(BitcoinTestFramework): assert_equal(inv_node.check_last_announcement(inv=[tip]), True) assert_equal(test_node.check_last_announcement(headers=[tip]), True) - print("Part 3: success!") + self.log.info("Part 3: success!") - print("Part 4: Testing direct fetch behavior...") + self.log.info("Part 4: Testing direct fetch behavior...") tip = self.mine_blocks(1) height = self.nodes[0].getblockcount() + 1 last_time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] @@ -523,12 +523,12 @@ class SendHeadersTest(BitcoinTestFramework): with mininode_lock: assert_equal(test_node.last_getdata, None) - print("Part 4: success!") + self.log.info("Part 4: success!") # Now deliver all those blocks we announced. [ test_node.send_message(msg_block(x)) for x in blocks ] - print("Part 5: Testing handling of unconnecting headers") + self.log.info("Part 5: Testing handling of unconnecting headers") # First we test that receipt of an unconnecting header doesn't prevent # chain sync. for i in range(10): @@ -595,7 +595,7 @@ class SendHeadersTest(BitcoinTestFramework): with mininode_lock: self.last_getheaders = True - print("Part 5: success!") + self.log.info("Part 5: success!") # Finally, check that the inv node never received a getdata request, # throughout the test diff --git a/qa/rpc-tests/signmessages.py b/test/functional/signmessages.py index 91f5abef5d..91f5abef5d 100755 --- a/qa/rpc-tests/signmessages.py +++ b/test/functional/signmessages.py diff --git a/qa/rpc-tests/signrawtransactions.py b/test/functional/signrawtransactions.py index b24162ab97..b24162ab97 100755 --- a/qa/rpc-tests/signrawtransactions.py +++ b/test/functional/signrawtransactions.py diff --git a/qa/rpc-tests/smartfees.py b/test/functional/smartfees.py index 9ce5b8e865..b7f4b86e7b 100755 --- a/qa/rpc-tests/smartfees.py +++ b/test/functional/smartfees.py @@ -4,18 +4,23 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test fee estimation code.""" -from collections import OrderedDict from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * +from test_framework.script import CScript, OP_1, OP_DROP, OP_2, OP_HASH160, OP_EQUAL, hash160, OP_TRUE +from test_framework.mininode import CTransaction, CTxIn, CTxOut, COutPoint, ToHex, COIN # Construct 2 trivial P2SH's and the ScriptSigs that spend them # So we can create many many transactions without needing to spend # time signing. -P2SH_1 = "2MySexEGVzZpRgNQ1JdjdP5bRETznm3roQ2" # P2SH of "OP_1 OP_DROP" -P2SH_2 = "2NBdpwq8Aoo1EEKEXPNrKvr5xQr3M9UfcZA" # P2SH of "OP_2 OP_DROP" +redeem_script_1 = CScript([OP_1, OP_DROP]) +redeem_script_2 = CScript([OP_2, OP_DROP]) +P2SH_1 = CScript([OP_HASH160, hash160(redeem_script_1), OP_EQUAL]) +P2SH_2 = CScript([OP_HASH160, hash160(redeem_script_2), OP_EQUAL]) + # Associated ScriptSig's to spend satisfy P2SH_1 and P2SH_2 -# 4 bytes of OP_TRUE and push 2-byte redeem script of "OP_1 OP_DROP" or "OP_2 OP_DROP" -SCRIPT_SIG = ["0451025175", "0451025275"] +SCRIPT_SIG = [CScript([OP_TRUE, redeem_script_1]), CScript([OP_TRUE, redeem_script_2])] + +global log def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee_increment): """ @@ -33,39 +38,30 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee rand_fee = float(fee_increment)*(1.1892**random.randint(0,28)) # Total fee ranges from min_fee to min_fee + 127*fee_increment fee = min_fee - fee_increment + satoshi_round(rand_fee) - inputs = [] + tx = CTransaction() total_in = Decimal("0.00000000") while total_in <= (amount + fee) and len(conflist) > 0: t = conflist.pop(0) total_in += t["amount"] - inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} ) + tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b"")) if total_in <= amount + fee: while total_in <= (amount + fee) and len(unconflist) > 0: t = unconflist.pop(0) total_in += t["amount"] - inputs.append({ "txid" : t["txid"], "vout" : t["vout"]} ) + tx.vin.append(CTxIn(COutPoint(int(t["txid"], 16), t["vout"]), b"")) if total_in <= amount + fee: raise RuntimeError("Insufficient funds: need %d, have %d"%(amount+fee, total_in)) - outputs = {} - outputs = OrderedDict([(P2SH_1, total_in - amount - fee), - (P2SH_2, amount)]) - rawtx = from_node.createrawtransaction(inputs, outputs) - # createrawtransaction constructs a transaction that is ready to be signed. - # These transactions don't need to be signed, but we still have to insert the ScriptSig - # that will satisfy the ScriptPubKey. - completetx = rawtx[0:10] - inputnum = 0 - for inp in inputs: - completetx += rawtx[10+82*inputnum:82+82*inputnum] - completetx += SCRIPT_SIG[inp["vout"]] - completetx += rawtx[84+82*inputnum:92+82*inputnum] - inputnum += 1 - completetx += rawtx[10+82*inputnum:] - txid = from_node.sendrawtransaction(completetx, True) + tx.vout.append(CTxOut(int((total_in - amount - fee)*COIN), P2SH_1)) + tx.vout.append(CTxOut(int(amount*COIN), P2SH_2)) + # These transactions don't need to be signed, but we still have to insert + # 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) unconflist.append({ "txid" : txid, "vout" : 0 , "amount" : total_in - amount - fee}) unconflist.append({ "txid" : txid, "vout" : 1 , "amount" : amount}) - return (completetx, fee) + return (ToHex(tx), fee) def split_inputs(from_node, txins, txouts, initial_split = False): """ @@ -76,18 +72,21 @@ def split_inputs(from_node, txins, txouts, initial_split = False): a high coin age when the notion of priority still existed. """ prevtxout = txins.pop() - inputs = [] - inputs.append({ "txid" : prevtxout["txid"], "vout" : prevtxout["vout"] }) + tx = CTransaction() + tx.vin.append(CTxIn(COutPoint(int(prevtxout["txid"], 16), prevtxout["vout"]), b"")) + half_change = satoshi_round(prevtxout["amount"]/2) rem_change = prevtxout["amount"] - half_change - Decimal("0.00001000") - outputs = OrderedDict([(P2SH_1, half_change), (P2SH_2, rem_change)]) - rawtx = from_node.createrawtransaction(inputs, outputs) + tx.vout.append(CTxOut(int(half_change*COIN), P2SH_1)) + tx.vout.append(CTxOut(int(rem_change*COIN), P2SH_2)) + # If this is the initial split we actually need to sign the transaction - # Otherwise we just need to insert the property ScriptSig + # Otherwise we just need to insert the proper ScriptSig if (initial_split) : - completetx = from_node.signrawtransaction(rawtx)["hex"] + completetx = from_node.signrawtransaction(ToHex(tx))["hex"] else : - completetx = rawtx[0:82] + SCRIPT_SIG[prevtxout["vout"]] + rawtx[84:] + tx.vin[0].scriptSig = SCRIPT_SIG[prevtxout["vout"]] + completetx = ToHex(tx) txid = from_node.sendrawtransaction(completetx, True) txouts.append({ "txid" : txid, "vout" : 0 , "amount" : half_change}) txouts.append({ "txid" : txid, "vout" : 1 , "amount" : rem_change}) @@ -99,7 +98,7 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): """ all_estimates = [ node.estimatefee(i) for i in range(1,26) ] if print_estimates: - print([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]]) + log.info([str(all_estimates[e-1]) for e in [1,2,3,6,15,25]]) delta = 1.0e-6 # account for rounding error last_e = max(fees_seen) for e in [x for x in all_estimates if x >= 0]: @@ -159,8 +158,8 @@ class EstimateFeeTest(BitcoinTestFramework): self.nodes.append(start_node(0, self.options.tmpdir, ["-maxorphantx=1000", "-whitelist=127.0.0.1"])) - print("This test is time consuming, please be patient") - print("Splitting inputs so we can generate tx's") + self.log.info("This test is time consuming, please be patient") + self.log.info("Splitting inputs so we can generate tx's") self.txouts = [] self.txouts2 = [] # Split a coinbase into two transaction puzzle outputs @@ -185,7 +184,7 @@ class EstimateFeeTest(BitcoinTestFramework): while (len(self.nodes[0].getrawmempool()) > 0): self.nodes[0].generate(1) reps += 1 - print("Finished splitting") + self.log.info("Finished splitting") # Now we can connect the other nodes, didn't want to connect them earlier # so the estimates would not be affected by the splitting transactions @@ -193,8 +192,7 @@ class EstimateFeeTest(BitcoinTestFramework): # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # (17k is room enough for 110 or so transactions) self.nodes.append(start_node(1, self.options.tmpdir, - ["-blockmaxsize=17000", - "-maxorphantx=1000", "-debug=estimatefee"])) + ["-blockmaxsize=17000", "-maxorphantx=1000"])) connect_nodes(self.nodes[1], 0) # Node2 is a stingy miner, that @@ -235,18 +233,21 @@ class EstimateFeeTest(BitcoinTestFramework): self.memutxo = newmem def run_test(self): + # Make log handler available to helper functions + global log + log = self.log self.fees_per_kb = [] self.memutxo = [] self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting - print("Will output estimates for 1/2/3/6/15/25 blocks") + self.log.info("Will output estimates for 1/2/3/6/15/25 blocks") for i in range(2): - print("Creating transactions and mining them with a block size that can't keep up") + self.log.info("Creating transactions and mining them with a block size that can't keep up") # Create transactions and mine 10 small blocks with node 2, but create txs faster than we can mine self.transact_and_mine(10, self.nodes[2]) check_estimates(self.nodes[1], self.fees_per_kb, 14) - print("Creating transactions and mining them at a block size that is just big enough") + self.log.info("Creating transactions and mining them at a block size that is just big enough") # Generate transactions while mining 10 more blocks, this time with node1 # which mines blocks with capacity just above the rate that transactions are being created self.transact_and_mine(10, self.nodes[1]) @@ -257,7 +258,7 @@ class EstimateFeeTest(BitcoinTestFramework): self.nodes[1].generate(1) sync_blocks(self.nodes[0:3], wait=.1) - print("Final estimates after emptying mempools") + self.log.info("Final estimates after emptying mempools") check_estimates(self.nodes[1], self.fees_per_kb, 2) if __name__ == '__main__': diff --git a/qa/rpc-tests/test_framework/__init__.py b/test/functional/test_framework/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/qa/rpc-tests/test_framework/__init__.py +++ b/test/functional/test_framework/__init__.py diff --git a/qa/rpc-tests/test_framework/address.py b/test/functional/test_framework/address.py index 96bebe1ea1..96bebe1ea1 100644 --- a/qa/rpc-tests/test_framework/address.py +++ b/test/functional/test_framework/address.py diff --git a/qa/rpc-tests/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py index 9ab3094b06..9ab3094b06 100644 --- a/qa/rpc-tests/test_framework/authproxy.py +++ b/test/functional/test_framework/authproxy.py diff --git a/qa/rpc-tests/test_framework/bignum.py b/test/functional/test_framework/bignum.py index 024611da6e..024611da6e 100644 --- a/qa/rpc-tests/test_framework/bignum.py +++ b/test/functional/test_framework/bignum.py diff --git a/qa/rpc-tests/test_framework/blockstore.py b/test/functional/test_framework/blockstore.py index 5280d18cdc..4cfd682bb5 100644 --- a/qa/rpc-tests/test_framework/blockstore.py +++ b/test/functional/test_framework/blockstore.py @@ -8,6 +8,8 @@ from .mininode import * from io import BytesIO import dbm.dumb as dbmd +logger = logging.getLogger("TestFramework.blockstore") + class BlockStore(object): """BlockStore helper class. @@ -86,7 +88,7 @@ class BlockStore(object): try: self.blockDB[repr(block.sha256)] = bytes(block.serialize()) except TypeError as e: - print("Unexpected error: ", sys.exc_info()[0], e.args) + logger.exception("Unexpected error") self.currentBlock = block.sha256 self.headers_map[block.sha256] = CBlockHeader(block) @@ -156,7 +158,7 @@ class TxStore(object): try: self.txDB[repr(tx.sha256)] = bytes(tx.serialize()) except TypeError as e: - print("Unexpected error: ", sys.exc_info()[0], e.args) + logger.exception("Unexpected error") def get_transactions(self, inv): responses = [] diff --git a/qa/rpc-tests/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py index 2c9a0857df..2c9a0857df 100644 --- a/qa/rpc-tests/test_framework/blocktools.py +++ b/test/functional/test_framework/blocktools.py diff --git a/qa/rpc-tests/test_framework/comptool.py b/test/functional/test_framework/comptool.py index b617895cac..25c18bda82 100755 --- a/qa/rpc-tests/test_framework/comptool.py +++ b/test/functional/test_framework/comptool.py @@ -21,6 +21,10 @@ from .mininode import * from .blockstore import BlockStore, TxStore from .util import p2p_port +import logging + +logger=logging.getLogger("TestFramework.comptool") + global mininode_lock class RejectResult(object): @@ -38,7 +42,7 @@ class RejectResult(object): class TestNode(NodeConnCB): def __init__(self, block_store, tx_store): - NodeConnCB.__init__(self) + super().__init__() self.conn = None self.bestblockhash = None self.block_store = block_store @@ -209,7 +213,6 @@ class TestManager(object): # --> error if not requested if not wait_until(blocks_requested, attempts=20*num_blocks): - # print [ c.cb.block_request_map for c in self.connections ] raise AssertionError("Not all nodes requested block") # Send getheaders message @@ -231,7 +234,6 @@ class TestManager(object): # --> error if not requested if not wait_until(transaction_requested, attempts=20*num_events): - # print [ c.cb.tx_request_map for c in self.connections ] raise AssertionError("Not all nodes requested transaction") # Get the mempool @@ -258,13 +260,12 @@ class TestManager(object): if c.cb.bestblockhash == blockhash: return False if blockhash not in c.cb.block_reject_map: - print('Block not in reject map: %064x' % (blockhash)) + logger.error('Block not in reject map: %064x' % (blockhash)) return False if not outcome.match(c.cb.block_reject_map[blockhash]): - print('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash)) + logger.error('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash)) return False elif ((c.cb.bestblockhash == blockhash) != outcome): - # print c.cb.bestblockhash, blockhash, outcome return False return True @@ -280,19 +281,17 @@ class TestManager(object): if outcome is None: # Make sure the mempools agree with each other if c.cb.lastInv != self.connections[0].cb.lastInv: - # print c.rpc.getrawmempool() return False elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code if txhash in c.cb.lastInv: return False if txhash not in c.cb.tx_reject_map: - print('Tx not in reject map: %064x' % (txhash)) + logger.error('Tx not in reject map: %064x' % (txhash)) return False if not outcome.match(c.cb.tx_reject_map[txhash]): - print('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash)) + logger.error('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash)) return False elif ((txhash in c.cb.lastInv) != outcome): - # print c.rpc.getrawmempool(), c.cb.lastInv return False return True @@ -402,7 +401,7 @@ class TestManager(object): if (not self.check_mempool(tx.sha256, tx_outcome)): raise AssertionError("Mempool test failed at test %d" % test_number) - print("Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ]) + logger.info("Test %d: PASS" % test_number) test_number += 1 [ c.disconnect_node() for c in self.connections ] diff --git a/qa/rpc-tests/test_framework/coverage.py b/test/functional/test_framework/coverage.py index 3f87ef91f6..3f87ef91f6 100644 --- a/qa/rpc-tests/test_framework/coverage.py +++ b/test/functional/test_framework/coverage.py diff --git a/qa/rpc-tests/test_framework/key.py b/test/functional/test_framework/key.py index 85a6158a2f..85a6158a2f 100644 --- a/qa/rpc-tests/test_framework/key.py +++ b/test/functional/test_framework/key.py diff --git a/qa/rpc-tests/test_framework/mininode.py b/test/functional/test_framework/mininode.py index b2292f6477..b02ffbe14a 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -51,6 +51,8 @@ NODE_GETUTXO = (1 << 1) NODE_BLOOM = (1 << 2) NODE_WITNESS = (1 << 3) +logger = logging.getLogger("TestFramework.mininode") + # Keep our own socket map for asyncore, so that we can track disconnects # ourselves (to workaround an issue with closing an asyncore socket when # using select) @@ -1474,25 +1476,9 @@ class NodeConnCB(object): self.deliver_sleep_time = None # Remember the services our peer has advertised self.peer_services = None - - def set_deliver_sleep_time(self, value): - with mininode_lock: - self.deliver_sleep_time = value - - def get_deliver_sleep_time(self): - with mininode_lock: - return self.deliver_sleep_time - - # Spin until verack message is received from the node. - # Tests may want to use this as a signal that the test can begin. - # This can be called from the testing thread, so it needs to acquire the - # global lock. - def wait_for_verack(self): - while True: - with mininode_lock: - if self.verack_received: - return - time.sleep(0.05) + self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() def deliver(self, conn, message): deliver_sleep = self.get_deliver_sleep_time() @@ -1502,20 +1488,38 @@ class NodeConnCB(object): try: getattr(self, 'on_' + message.command.decode('ascii'))(conn, message) except: - print("ERROR delivering %s (%s)" % (repr(message), - sys.exc_info()[0])) + logger.exception("ERROR delivering %s" % repr(message)) - def on_version(self, conn, message): - if message.nVersion >= 209: - conn.send_message(msg_verack()) - conn.ver_send = min(MY_VERSION, message.nVersion) - if message.nVersion < 209: - conn.ver_recv = conn.ver_send - conn.nServices = message.nServices + def set_deliver_sleep_time(self, value): + with mininode_lock: + self.deliver_sleep_time = value - def on_verack(self, conn, message): - conn.ver_recv = conn.ver_send - self.verack_received = True + def get_deliver_sleep_time(self): + with mininode_lock: + return self.deliver_sleep_time + + # Callbacks which can be overridden by subclasses + ################################################# + + def on_addr(self, conn, message): pass + def on_alert(self, conn, message): pass + def on_block(self, conn, message): pass + def on_blocktxn(self, conn, message): pass + def on_close(self, conn): pass + def on_cmpctblock(self, conn, message): pass + def on_feefilter(self, conn, message): pass + def on_getaddr(self, conn, message): pass + def on_getblocks(self, conn, message): pass + def on_getblocktxn(self, conn, message): pass + def on_getdata(self, conn, message): pass + def on_getheaders(self, conn, message): pass + def on_headers(self, conn, message): pass + def on_mempool(self, conn): pass + def on_open(self, conn): pass + def on_reject(self, conn, message): pass + def on_sendcmpct(self, conn, message): pass + def on_sendheaders(self, conn, message): pass + def on_tx(self, conn, message): pass def on_inv(self, conn, message): want = msg_getdata() @@ -1525,37 +1529,27 @@ class NodeConnCB(object): if len(want.inv): conn.send_message(want) - def on_addr(self, conn, message): pass - def on_alert(self, conn, message): pass - def on_getdata(self, conn, message): pass - def on_getblocks(self, conn, message): pass - def on_tx(self, conn, message): pass - def on_block(self, conn, message): pass - def on_getaddr(self, conn, message): pass - def on_headers(self, conn, message): pass - def on_getheaders(self, conn, message): pass def on_ping(self, conn, message): if conn.ver_send > BIP0031_VERSION: conn.send_message(msg_pong(message.nonce)) - def on_reject(self, conn, message): pass - def on_open(self, conn): pass - def on_close(self, conn): pass - def on_mempool(self, conn): pass - def on_pong(self, conn, message): pass - def on_feefilter(self, conn, message): pass - def on_sendheaders(self, conn, message): pass - def on_sendcmpct(self, conn, message): pass - def on_cmpctblock(self, conn, message): pass - def on_getblocktxn(self, conn, message): pass - def on_blocktxn(self, conn, message): pass -# More useful callbacks and functions for NodeConnCB's which have a single NodeConn -class SingleNodeConnCB(NodeConnCB): - def __init__(self): - NodeConnCB.__init__(self) - self.connection = None - self.ping_counter = 1 - self.last_pong = msg_pong() + def on_pong(self, conn, message): + self.last_pong = message + + def on_verack(self, conn, message): + conn.ver_recv = conn.ver_send + self.verack_received = True + + def on_version(self, conn, message): + if message.nVersion >= 209: + conn.send_message(msg_verack()) + conn.ver_send = min(MY_VERSION, message.nVersion) + if message.nVersion < 209: + conn.ver_recv = conn.ver_send + conn.nServices = message.nServices + + # Helper functions + ################## def add_connection(self, conn): self.connection = conn @@ -1568,9 +1562,6 @@ class SingleNodeConnCB(NodeConnCB): self.send_message(message) self.sync_with_ping() - def on_pong(self, conn, message): - self.last_pong = message - # Sync up with the node def sync_with_ping(self, timeout=30): def received_pong(): @@ -1578,8 +1569,20 @@ class SingleNodeConnCB(NodeConnCB): self.send_message(msg_ping(nonce=self.ping_counter)) success = wait_until(received_pong, timeout=timeout) self.ping_counter += 1 + return success + # Spin until verack message is received from the node. + # Tests may want to use this as a signal that the test can begin. + # This can be called from the testing thread, so it needs to acquire the + # global lock. + def wait_for_verack(self): + while True: + with mininode_lock: + if self.verack_received: + return + time.sleep(0.05) + # The actual NodeConn class # This class provides an interface for a p2p connection to a specified node class NodeConn(asyncore.dispatcher): @@ -1615,7 +1618,6 @@ class NodeConn(asyncore.dispatcher): def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True): asyncore.dispatcher.__init__(self, map=mininode_socket_map) - self.log = logging.getLogger("NodeConn(%s:%d)" % (dstaddr, dstport)) self.dstaddr = dstaddr self.dstport = dstport self.create_socket(socket.AF_INET, socket.SOCK_STREAM) @@ -1640,8 +1642,7 @@ class NodeConn(asyncore.dispatcher): vt.addrFrom.port = 0 self.send_message(vt, True) - print('MiniNode: Connecting to Bitcoin Node IP # ' + dstaddr + ':' \ - + str(dstport)) + logger.info('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport)) try: self.connect((dstaddr, dstport)) @@ -1649,18 +1650,14 @@ class NodeConn(asyncore.dispatcher): self.handle_close() self.rpc = rpc - def show_debug_msg(self, msg): - self.log.debug(msg) - def handle_connect(self): if self.state != "connected": - self.show_debug_msg("MiniNode: Connected & Listening: \n") + logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport)) self.state = "connected" self.cb.on_open(self) def handle_close(self): - self.show_debug_msg("MiniNode: Closing Connection to %s:%d... " - % (self.dstaddr, self.dstport)) + logger.debug("Closing connection to: %s:%d" % (self.dstaddr, self.dstport)) self.state = "closed" self.recvbuf = b"" self.sendbuf = b"" @@ -1742,17 +1739,14 @@ class NodeConn(asyncore.dispatcher): t.deserialize(f) self.got_message(t) else: - self.show_debug_msg("Unknown command: '" + command + "' " + - repr(msg)) + logger.warning("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg))) except Exception as e: - print('got_data:', repr(e)) - # import traceback - # traceback.print_tb(sys.exc_info()[2]) + logger.exception('got_data:', repr(e)) def send_message(self, message, pushbuf=False): if self.state != "connected" and not pushbuf: raise IOError('Not connected, no pushbuf') - self.show_debug_msg("Send %s" % repr(message)) + logger.debug("Send message to %s:%d: %s" % (self.dstaddr, self.dstport, repr(message))) command = message.command data = message.serialize() tmsg = self.MAGIC_BYTES[self.network] @@ -1774,7 +1768,7 @@ class NodeConn(asyncore.dispatcher): self.messagemap[b'ping'] = msg_ping_prebip31 if self.last_sent + 30 * 60 < time.time(): self.send_message(self.messagemap[b'ping']()) - self.show_debug_msg("Recv %s" % repr(message)) + logger.debug("Received message from %s:%d: %s" % (self.dstaddr, self.dstport, repr(message))) self.cb.deliver(self, message) def disconnect_node(self): diff --git a/qa/rpc-tests/test_framework/netutil.py b/test/functional/test_framework/netutil.py index 45d8e22d22..45d8e22d22 100644 --- a/qa/rpc-tests/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py diff --git a/qa/rpc-tests/test_framework/script.py b/test/functional/test_framework/script.py index 3d9572788e..3d9572788e 100644 --- a/qa/rpc-tests/test_framework/script.py +++ b/test/functional/test_framework/script.py diff --git a/qa/rpc-tests/test_framework/siphash.py b/test/functional/test_framework/siphash.py index f68ecad36b..f68ecad36b 100644 --- a/qa/rpc-tests/test_framework/siphash.py +++ b/test/functional/test_framework/siphash.py diff --git a/qa/rpc-tests/test_framework/socks5.py b/test/functional/test_framework/socks5.py index 450bf3775e..a08b03ed24 100644 --- a/qa/rpc-tests/test_framework/socks5.py +++ b/test/functional/test_framework/socks5.py @@ -5,7 +5,9 @@ """Dummy Socks5 server for testing.""" import socket, threading, queue -import traceback, sys +import logging + +logger = logging.getLogger("TestFramework.socks5") ### Protocol constants class Command: @@ -112,10 +114,10 @@ class Socks5Connection(object): cmdin = Socks5Command(cmd, atyp, addr, port, username, password) self.serv.queue.put(cmdin) - print('Proxy: ', cmdin) + logger.info('Proxy: %s', cmdin) # Fall through to disconnect except Exception as e: - traceback.print_exc(file=sys.stderr) + logger.exception("socks5 request handling failed.") self.serv.queue.put(e) finally: self.conn.close() diff --git a/qa/rpc-tests/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index c5e9c6a658..473b7c14a9 100755 --- a/qa/rpc-tests/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -4,13 +4,14 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Base class for RPC testing.""" +from collections import deque import logging import optparse import os import sys import shutil import tempfile -import traceback +import time from .util import ( initialize_chain, @@ -27,9 +28,12 @@ from .util import ( ) from .authproxy import JSONRPCException - class BitcoinTestFramework(object): + TEST_EXIT_PASSED = 0 + TEST_EXIT_FAILED = 1 + TEST_EXIT_SKIPPED = 77 + def __init__(self): self.num_nodes = 4 self.setup_clean_chain = False @@ -42,7 +46,7 @@ class BitcoinTestFramework(object): pass def setup_chain(self): - print("Initializing test directory "+self.options.tmpdir) + self.log.info("Initializing test directory "+self.options.tmpdir) if self.setup_clean_chain: initialize_chain_clean(self.options.tmpdir, self.num_nodes) else: @@ -112,6 +116,8 @@ class BitcoinTestFramework(object): help="Directory for caching pregenerated datadirs") parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), help="Root directory for datadirs") + parser.add_option("-l", "--loglevel", dest="loglevel", default="INFO", + help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.") parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", help="Print out all RPC calls as they are made") parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int', @@ -124,9 +130,6 @@ class BitcoinTestFramework(object): # backup dir variable for removal at cleanup self.options.root, self.options.tmpdir = self.options.tmpdir, self.options.tmpdir + '/' + str(self.options.port_seed) - if self.options.trace_rpc: - logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) - if self.options.coveragedir: enable_coverage(self.options.coveragedir) @@ -136,58 +139,91 @@ class BitcoinTestFramework(object): check_json_precision() + # Set up temp directory and start logging + os.makedirs(self.options.tmpdir, exist_ok=False) + self._start_logging() + success = False + try: - os.makedirs(self.options.tmpdir, exist_ok=False) self.setup_chain() self.setup_network() self.run_test() success = True except JSONRPCException as e: - print("JSONRPC error: "+e.error['message']) - traceback.print_tb(sys.exc_info()[2]) + self.log.exception("JSONRPC error") except AssertionError as e: - print("Assertion failed: " + str(e)) - traceback.print_tb(sys.exc_info()[2]) + self.log.exception("Assertion failed") except KeyError as e: - print("key not found: "+ str(e)) - traceback.print_tb(sys.exc_info()[2]) + self.log.exception("Key error") except Exception as e: - print("Unexpected exception caught during testing: " + repr(e)) - traceback.print_tb(sys.exc_info()[2]) + self.log.exception("Unexpected exception caught during testing") except KeyboardInterrupt as e: - print("Exiting after " + repr(e)) + self.log.warning("Exiting after keyboard interrupt") if not self.options.noshutdown: - print("Stopping nodes") + self.log.info("Stopping nodes") stop_nodes(self.nodes) else: - print("Note: bitcoinds were not stopped and may still be running") + self.log.info("Note: bitcoinds were not stopped and may still be running") if not self.options.nocleanup and not self.options.noshutdown and success: - print("Cleaning up") + self.log.info("Cleaning up") shutil.rmtree(self.options.tmpdir) if not os.listdir(self.options.root): os.rmdir(self.options.root) else: - print("Not cleaning up dir %s" % self.options.tmpdir) + self.log.warning("Not cleaning up dir %s" % self.options.tmpdir) if os.getenv("PYTHON_DEBUG", ""): # Dump the end of the debug logs, to aid in debugging rare # travis failures. import glob - filenames = glob.glob(self.options.tmpdir + "/node*/regtest/debug.log") + filenames = [self.options.tmpdir + "/test_framework.log"] + filenames += glob.glob(self.options.tmpdir + "/node*/regtest/debug.log") MAX_LINES_TO_PRINT = 1000 - for f in filenames: - print("From" , f, ":") - from collections import deque - print("".join(deque(open(f), MAX_LINES_TO_PRINT))) + for fn in filenames: + try: + with open(fn, 'r') as f: + print("From" , fn, ":") + print("".join(deque(f, MAX_LINES_TO_PRINT))) + except OSError: + print("Opening file %s failed." % fn) + traceback.print_exc() if success: - print("Tests successful") - sys.exit(0) + self.log.info("Tests successful") + sys.exit(self.TEST_EXIT_PASSED) else: - print("Failed") - sys.exit(1) + self.log.error("Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir) + logging.shutdown() + sys.exit(self.TEST_EXIT_FAILED) + + def _start_logging(self): + # Add logger and logging handlers + self.log = logging.getLogger('TestFramework') + self.log.setLevel(logging.DEBUG) + # Create file handler to log all messages + fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log') + fh.setLevel(logging.DEBUG) + # Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel. + ch = logging.StreamHandler(sys.stdout) + # User can provide log level as a number or string (eg DEBUG). loglevel was caught as a string, so try to convert it to an int + ll = int(self.options.loglevel) if self.options.loglevel.isdigit() else self.options.loglevel.upper() + ch.setLevel(ll) + # Format logs the same as bitcoind's debug.log with microprecision (so log files can be concatenated and sorted) + formatter = logging.Formatter(fmt = '%(asctime)s.%(msecs)03d000 %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + formatter.converter = time.gmtime + fh.setFormatter(formatter) + ch.setFormatter(formatter) + # add the handlers to the logger + self.log.addHandler(fh) + self.log.addHandler(ch) + if self.options.trace_rpc: + rpc_logger = logging.getLogger("BitcoinRPC") + rpc_logger.setLevel(logging.DEBUG) + rpc_handler = logging.StreamHandler(sys.stdout) + rpc_handler.setLevel(logging.DEBUG) + rpc_logger.addHandler(rpc_handler) # Test framework for doing p2p comparison testing, which sets up some bitcoind # binaries: @@ -213,6 +249,6 @@ class ComparisonTestFramework(BitcoinTestFramework): def setup_network(self): self.nodes = start_nodes( self.num_nodes, self.options.tmpdir, - extra_args=[['-debug', '-whitelist=127.0.0.1']] * self.num_nodes, + extra_args=[['-whitelist=127.0.0.1']] * self.num_nodes, binary=[self.options.testbinary] + [self.options.refbinary]*(self.num_nodes-1)) diff --git a/qa/rpc-tests/test_framework/util.py b/test/functional/test_framework/util.py index ba56fddd77..23ac324510 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -19,12 +19,15 @@ import tempfile import time import re import errno +import logging from . import coverage from .authproxy import AuthServiceProxy, JSONRPCException COVERAGE_DIR = None +logger = logging.getLogger("TestFramework.utils") + # The maximum number of nodes a single test can spawn MAX_NODES = 8 # Don't assign rpc or p2p ports lower than this @@ -237,6 +240,7 @@ def initialize_chain(test_dir, num_nodes, cachedir): break if create_cache: + logger.debug("Creating data directories from cached datadir") #find and delete old cache directories if any exist for i in range(MAX_NODES): @@ -250,11 +254,9 @@ def initialize_chain(test_dir, num_nodes, cachedir): if i > 0: args.append("-connect=127.0.0.1:"+str(p2p_port(0))) bitcoind_processes[i] = subprocess.Popen(args) - if os.getenv("PYTHON_DEBUG", ""): - print("initialize_chain: bitcoind started, waiting for RPC to come up") + logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up") wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) - if os.getenv("PYTHON_DEBUG", ""): - print("initialize_chain: RPC successfully started") + logger.debug("initialize_chain: RPC successfully started") rpcs = [] for i in range(MAX_NODES): @@ -313,15 +315,13 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary= datadir = os.path.join(dirname, "node"+str(i)) if binary is None: binary = os.getenv("BITCOIND", "bitcoind") - args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-mocktime="+str(get_mocktime()) ] + args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-mocktime="+str(get_mocktime()) ] if extra_args is not None: args.extend(extra_args) bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr) - if os.getenv("PYTHON_DEBUG", ""): - print("start_node: bitcoind started, waiting for RPC to come up") + logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up") url = rpc_url(i, rpchost) wait_for_bitcoind_start(bitcoind_processes[i], url, i) - if os.getenv("PYTHON_DEBUG", ""): - print("start_node: RPC successfully started") + logger.debug("initialize_chain: RPC successfully started") proxy = get_rpc_proxy(url, i, timeout=timewait) if COVERAGE_DIR: @@ -367,10 +367,11 @@ def log_filename(dirname, n_node, logname): return os.path.join(dirname, "node"+str(n_node), "regtest", logname) def stop_node(node, i): + logger.debug("Stopping node %d" % i) try: node.stop() except http.client.CannotSendRequest as e: - print("WARN: Unable to stop node: " + repr(e)) + logger.exception("Unable to stop node") return_code = bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) assert_equal(return_code, 0) del bitcoind_processes[i] diff --git a/qa/pull-tester/rpc-tests.py b/test/functional/test_runner.py index 68e11b4c2b..37a2ab62a4 100755 --- a/qa/pull-tester/rpc-tests.py +++ b/test/functional/test_runner.py @@ -2,16 +2,15 @@ # Copyright (c) 2014-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. -""" -rpc-tests.py - run regression test suite +"""Run regression test suite. This module calls down into individual test cases via subprocess. It will forward all unrecognized arguments onto the individual test scripts. -RPC tests are disabled on Windows by default. Use --force to run them anyway. +Functional tests are disabled on Windows by default. Use --force to run them anyway. For a description of arguments recognized by test scripts, see -`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`. +`test/functional/test_framework/test_framework.py:BitcoinTestFramework.main`. """ @@ -24,6 +23,10 @@ import sys import subprocess import tempfile import re +import logging + +TEST_EXIT_PASSED = 0 +TEST_EXIT_SKIPPED = 77 BASE_SCRIPTS= [ # Scripts that are run by the travis build process. @@ -87,8 +90,8 @@ BASE_SCRIPTS= [ ZMQ_SCRIPTS = [ # ZMQ test can only be run if bitcoin was built with zmq-enabled. - # call rpc_tests.py with -nozmq to explicitly exclude these tests. - "zmq_test.py"] + # call test_runner.py with -nozmq to explicitly exclude these tests. + 'zmq_test.py'] EXTENDED_SCRIPTS = [ # These tests are not run by the travis build process. @@ -108,6 +111,7 @@ EXTENDED_SCRIPTS = [ 'p2p-feefilter.py', 'rpcbind_test.py', # vv Tests less than 30s vv + 'assumevalid.py', 'bip65-cltv.py', 'bip65-cltv-p2p.py', 'bipdersig-p2p.py', @@ -124,10 +128,17 @@ EXTENDED_SCRIPTS = [ ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS +NON_SCRIPTS = [ + # These are python files that live in the functional tests directory, but are not test scripts. + "combine_logs.py", + "create_cache.py", + "test_runner.py", +] + def main(): # Parse arguments and pass through unrecognised args parser = argparse.ArgumentParser(add_help=False, - usage='%(prog)s [rpc-test.py options] [script options] [scripts]', + usage='%(prog)s [test_runner.py options] [script options] [scripts]', description=__doc__, epilog=''' Help text and arguments for individual test script:''', @@ -138,6 +149,7 @@ def main(): parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).') parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit') parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.') + parser.add_argument('--quiet', '-q', action='store_true', help='only print results summary and failure logs') parser.add_argument('--nozmq', action='store_true', help='do not run the zmq tests') args, unknown_args = parser.parse_known_args() @@ -147,7 +159,11 @@ def main(): # Read config generated by configure. config = configparser.ConfigParser() - config.read_file(open(os.path.dirname(__file__) + "/tests_config.ini")) + config.read_file(open(os.path.dirname(__file__) + "/config.ini")) + + # Set up logging + logging_level = logging.INFO if args.quiet else logging.DEBUG + logging.basicConfig(format='%(message)s', level=logging_level) enable_wallet = config["components"].getboolean("ENABLE_WALLET") enable_utils = config["components"].getboolean("ENABLE_UTILS") @@ -161,7 +177,7 @@ def main(): sys.exit(0) if not (enable_wallet and enable_utils and enable_bitcoind): - print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled") + print("No functional tests to run. Wallet, utils, and bitcoind must all be enabled") print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make") sys.exit(0) @@ -171,7 +187,7 @@ def main(): import zmq except ImportError: print("ERROR: \"import zmq\" failed. Use -nozmq to run without the ZMQ tests." - "To run zmq tests, see dependency info in /qa/README.md.") + "To run zmq tests, see dependency info in /test/README.md.") raise # Build list of tests @@ -200,15 +216,17 @@ def main(): if not test_list: print("No valid test scripts specified. Check that your test is in one " - "of the test lists in rpc-tests.py, or run rpc-tests.py with no arguments to run all tests") + "of the test lists in test_runner.py, or run test_runner.py with no arguments to run all tests") sys.exit(0) if args.help: - # Print help for rpc-tests.py, then print help of the first script and exit. + # Print help for test_runner.py, then print help of the first script (with args removed) and exit. parser.print_help() - subprocess.check_call((config["environment"]["SRCDIR"] + '/qa/rpc-tests/' + test_list[0]).split() + ['-h']) + subprocess.check_call([(config["environment"]["SRCDIR"] + '/test/functional/' + test_list[0].split()[0])] + ['-h']) sys.exit(0) + check_script_list(config["environment"]["SRCDIR"]) + run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args) def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]): @@ -222,15 +240,15 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal if "BITCOIND" not in os.environ: os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext - tests_dir = src_dir + '/qa/rpc-tests/' + tests_dir = src_dir + '/test/functional/' flags = ["--srcdir={}/src".format(build_dir)] + args - flags.append("--cachedir=%s/qa/cache" % build_dir) + flags.append("--cachedir=%s/test/cache" % build_dir) if enable_coverage: coverage = RPCCoverage() flags.append(coverage.flag) - print("Initializing coverage directory at %s\n" % coverage.dir) + logging.debug("Initializing coverage directory at %s" % coverage.dir) else: coverage = None @@ -243,35 +261,39 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal time_sum = 0 time0 = time.time() - job_queue = RPCTestHandler(jobs, tests_dir, test_list, flags) + job_queue = TestHandler(jobs, tests_dir, test_list, flags) max_len_name = len(max(test_list, key=len)) - results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0] + results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0] for _ in range(len(test_list)): - (name, stdout, stderr, passed, duration) = job_queue.get_next() - all_passed = all_passed and passed + (name, stdout, stderr, status, duration) = job_queue.get_next() + all_passed = all_passed and status != "Failed" time_sum += duration - print('\n' + BOLD[1] + name + BOLD[0] + ":") - print('' if passed else stdout + '\n', end='') - print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='') - print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration)) + if status == "Passed": + logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], name, BOLD[0], duration)) + elif status == "Skipped": + logging.debug("\n%s%s%s skipped" % (BOLD[1], name, BOLD[0])) + else: + print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], name, BOLD[0], duration)) + print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n') + print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n') - results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration) + results += "%s | %s | %s s\n" % (name.ljust(max_len_name), status.ljust(7), duration) - results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0] + results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(7), time_sum) + BOLD[0] print(results) print("\nRuntime: %s s" % (int(time.time() - time0))) if coverage: coverage.report_rpc_coverage() - print("Cleaning up coverage data") + logging.debug("Cleaning up coverage data") coverage.cleanup() sys.exit(not all_passed) -class RPCTestHandler: +class TestHandler: """ Trigger the testscrips passed in via the list. """ @@ -297,9 +319,10 @@ class RPCTestHandler: port_seed = ["--portseed={}".format(len(self.test_list) + self.portseed_offset)] log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) + test_argv = t.split() self.jobs.append((t, time.time(), - subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed, + subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + port_seed, universal_newlines=True, stdout=log_stdout, stderr=log_stderr), @@ -316,16 +339,33 @@ class RPCTestHandler: log_out.seek(0), log_err.seek(0) [stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)] log_out.close(), log_err.close() - passed = stderr == "" and proc.returncode == 0 + if proc.returncode == TEST_EXIT_PASSED and stderr == "": + status = "Passed" + elif proc.returncode == TEST_EXIT_SKIPPED: + status = "Skipped" + else: + status = "Failed" self.num_running -= 1 self.jobs.remove(j) - return name, stdout, stderr, passed, int(time.time() - time0) + return name, stdout, stderr, status, int(time.time() - time0) print('.', end='', flush=True) +def check_script_list(src_dir): + """Check scripts directory. + + Check that there are no scripts in the functional tests directory which are + not being run by pull-tester.py.""" + script_dir = src_dir + '/test/functional/' + python_files = set([t for t in os.listdir(script_dir) if t[-3:] == ".py"]) + missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS))) + if len(missed_tests) != 0: + print("The following scripts are not being run:" + str(missed_tests)) + print("Check the test lists in test_runner.py") + sys.exit(1) class RPCCoverage(object): """ - Coverage reporting utilities for pull-tester. + Coverage reporting utilities for test_runner. Coverage calculation works by having each test script subprocess write coverage files into a particular directory. These files contain the RPC @@ -335,7 +375,7 @@ class RPCCoverage(object): After all tests complete, the commands run are combined and diff'd against the complete list to calculate uncovered RPC commands. - See also: qa/rpc-tests/test_framework/coverage.py + See also: test/functional/test_framework/coverage.py """ def __init__(self): @@ -363,7 +403,7 @@ class RPCCoverage(object): Return a set of currently untested RPC commands. """ - # This is shared from `qa/rpc-tests/test-framework/coverage.py` + # This is shared from `test/functional/test-framework/coverage.py` reference_filename = 'rpc_interface.txt' coverage_file_prefix = 'coverage.' diff --git a/qa/rpc-tests/txn_clone.py b/test/functional/txn_clone.py index 7a3b8d3474..7a3b8d3474 100755 --- a/qa/rpc-tests/txn_clone.py +++ b/test/functional/txn_clone.py diff --git a/qa/rpc-tests/txn_doublespend.py b/test/functional/txn_doublespend.py index 5b12cf4c29..5b12cf4c29 100755 --- a/qa/rpc-tests/txn_doublespend.py +++ b/test/functional/txn_doublespend.py diff --git a/qa/rpc-tests/wallet-accounts.py b/test/functional/wallet-accounts.py index ea12d4ec22..ea12d4ec22 100755 --- a/qa/rpc-tests/wallet-accounts.py +++ b/test/functional/wallet-accounts.py diff --git a/qa/rpc-tests/wallet-dump.py b/test/functional/wallet-dump.py index b819b72b75..8876f935a4 100755 --- a/qa/rpc-tests/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -88,7 +88,7 @@ class WalletDumpTest(BitcoinTestFramework): read_dump(tmpdir + "/node0/wallet.unencrypted.dump", addrs, None) assert_equal(found_addr, test_addr_count) # all keys must be in the dump assert_equal(found_addr_chg, 50) # 50 blocks where mined - assert_equal(found_addr_rsv, 90 + 1) # keypool size (TODO: fix off-by-one) + assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys #encrypt wallet, restart, unlock and dump self.nodes[0].encryptwallet('test') @@ -102,8 +102,8 @@ class WalletDumpTest(BitcoinTestFramework): found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_enc = \ read_dump(tmpdir + "/node0/wallet.encrypted.dump", addrs, hd_master_addr_unenc) assert_equal(found_addr, test_addr_count) - assert_equal(found_addr_chg, 90 + 1 + 50) # old reserve keys are marked as change now - assert_equal(found_addr_rsv, 90 + 1) # keypool size (TODO: fix off-by-one) + assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now + assert_equal(found_addr_rsv, 90*2) if __name__ == '__main__': WalletDumpTest().main () diff --git a/qa/rpc-tests/wallet-hd.py b/test/functional/wallet-hd.py index 1dcfe5300f..64a6c92782 100755 --- a/qa/rpc-tests/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -42,6 +42,11 @@ class WalletHDTest(BitcoinTestFramework): masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid'] assert_equal(len(masterkeyid), 40) + # create an internal key + change_addr = self.nodes[1].getrawchangeaddress() + change_addrV= self.nodes[1].validateaddress(change_addr); + assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key + # Import a non-HD private key in the HD wallet non_hd_add = self.nodes[0].getnewaddress() self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add)) @@ -65,10 +70,15 @@ class WalletHDTest(BitcoinTestFramework): self.nodes[0].sendtoaddress(non_hd_add, 1) self.nodes[0].generate(1) + # create an internal key (again) + change_addr = self.nodes[1].getrawchangeaddress() + change_addrV= self.nodes[1].validateaddress(change_addr); + assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key + self.sync_all() assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) - print("Restore backup ...") + self.log.info("Restore backup ...") self.stop_node(1) os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat") shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat") @@ -90,6 +100,15 @@ class WalletHDTest(BitcoinTestFramework): #connect_nodes_bi(self.nodes, 0, 1) assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) + # send a tx and make sure its using the internal chain for the changeoutput + txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) + outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout']; + keypath = "" + for out in outs: + if out['value'] != 1: + keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath'] + + assert_equal(keypath[0:7], "m/0'/1'") if __name__ == '__main__': WalletHDTest().main () diff --git a/qa/rpc-tests/wallet.py b/test/functional/wallet.py index ddeac657e5..80f74fa108 100755 --- a/qa/rpc-tests/wallet.py +++ b/test/functional/wallet.py @@ -35,7 +35,7 @@ class WalletTest (BitcoinTestFramework): assert_equal(len(self.nodes[1].listunspent()), 0) assert_equal(len(self.nodes[2].listunspent()), 0) - print("Mining blocks...") + self.log.info("Mining blocks...") self.nodes[0].generate(1) @@ -71,7 +71,7 @@ class WalletTest (BitcoinTestFramework): unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[2].lockunspent(False, [unspent_0]) - assert_raises_message(JSONRPCException, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) + assert_raises_jsonrpc(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) @@ -251,19 +251,11 @@ class WalletTest (BitcoinTestFramework): txObj = self.nodes[0].gettransaction(txId) assert_equal(txObj['amount'], Decimal('-0.0001')) - try: - txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4") - except JSONRPCException as e: - assert("Invalid amount" in e.error['message']) - else: - raise AssertionError("Must not parse invalid amounts") + # This will raise an exception because the amount type is wrong + assert_raises_jsonrpc(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") - - try: - self.nodes[0].generate("2") - raise AssertionError("Must not accept strings as numeric") - except JSONRPCException as e: - assert("not an integer" in e.error['message']) + # This will raise an exception since generate does not accept a string + assert_raises_jsonrpc(-1, "not an integer", self.nodes[0].generate, "2") # Import address and private key to check correct behavior of spendable unspents # 1. Send some coins to generate new UTXO @@ -332,7 +324,7 @@ class WalletTest (BitcoinTestFramework): ] chainlimit = 6 for m in maintenance: - print("check " + m) + self.log.info("check " + m) stop_nodes(self.nodes) # set lower ancestor limit for later self.nodes = start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3) @@ -394,7 +386,7 @@ class WalletTest (BitcoinTestFramework): node0_balance = self.nodes[0].getbalance() # With walletrejectlongchains we will not create the tx and store it in our wallet. - assert_raises_message(JSONRPCException, "mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) + assert_raises_jsonrpc(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) # Verify nothing new in wallet assert_equal(total_txs, len(self.nodes[0].listtransactions("*",99999))) diff --git a/qa/rpc-tests/walletbackup.py b/test/functional/walletbackup.py index ea249096cf..af1718572f 100755 --- a/qa/rpc-tests/walletbackup.py +++ b/test/functional/walletbackup.py @@ -34,8 +34,6 @@ and confirm again balances are correct. from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * from random import randint -import logging -logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO, stream=sys.stdout) class WalletBackupTest(BitcoinTestFramework): @@ -100,7 +98,7 @@ class WalletBackupTest(BitcoinTestFramework): os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat") def run_test(self): - logging.info("Generating initial blockchain") + self.log.info("Generating initial blockchain") self.nodes[0].generate(1) sync_blocks(self.nodes) self.nodes[1].generate(1) @@ -115,12 +113,12 @@ class WalletBackupTest(BitcoinTestFramework): assert_equal(self.nodes[2].getbalance(), 50) assert_equal(self.nodes[3].getbalance(), 0) - logging.info("Creating transactions") + self.log.info("Creating transactions") # Five rounds of sending each other transactions. for i in range(5): self.do_one_round() - logging.info("Backing up") + self.log.info("Backing up") tmpdir = self.options.tmpdir self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak") self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump") @@ -129,7 +127,7 @@ class WalletBackupTest(BitcoinTestFramework): self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak") self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump") - logging.info("More transactions") + self.log.info("More transactions") for i in range(5): self.do_one_round() @@ -150,7 +148,7 @@ class WalletBackupTest(BitcoinTestFramework): ## # Test restoring spender wallets from backups ## - logging.info("Restoring using wallet.dat") + self.log.info("Restoring using wallet.dat") self.stop_three() self.erase_three() @@ -163,7 +161,7 @@ class WalletBackupTest(BitcoinTestFramework): shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat") shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat") - logging.info("Re-starting nodes") + self.log.info("Re-starting nodes") self.start_three() sync_blocks(self.nodes) @@ -171,7 +169,7 @@ class WalletBackupTest(BitcoinTestFramework): assert_equal(self.nodes[1].getbalance(), balance1) assert_equal(self.nodes[2].getbalance(), balance2) - logging.info("Restoring using dumped wallet") + self.log.info("Restoring using dumped wallet") self.stop_three() self.erase_three() diff --git a/qa/rpc-tests/zapwallettxes.py b/test/functional/zapwallettxes.py index 9597d05f3a..ce446e44a3 100755 --- a/qa/rpc-tests/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -32,7 +32,7 @@ class ZapWalletTXesTest (BitcoinTestFramework): self.sync_all() def run_test (self): - print("Mining blocks...") + self.log.info("Mining blocks...") self.nodes[0].generate(1) self.sync_all() self.nodes[1].generate(101) diff --git a/qa/rpc-tests/zmq_test.py b/test/functional/zmq_test.py index 1e2f06bd54..9e27b46381 100755 --- a/qa/rpc-tests/zmq_test.py +++ b/test/functional/zmq_test.py @@ -36,12 +36,11 @@ class ZMQTest (BitcoinTestFramework): genhashes = self.nodes[0].generate(1) self.sync_all() - print("listen...") + self.log.info("listen...") msg = self.zmqSubSocket.recv_multipart() topic = msg[0] assert_equal(topic, b"hashtx") body = msg[1] - nseq = msg[2] msgSequence = struct.unpack('<I', msg[-1])[-1] assert_equal(msgSequence, 0) #must be sequence 0 on hashtx diff --git a/src/test/bctest.py b/test/util/bctest.py index c69f52afc3..dfe3a123d1 100644 --- a/src/test/bctest.py +++ b/test/util/bctest.py @@ -23,14 +23,14 @@ def parse_output(a, fmt): else: raise NotImplementedError("Don't know how to compare %s" % fmt) -def bctest(testDir, testObj, exeext): +def bctest(testDir, testObj, buildenv): """Runs a single test, comparing output and RC to expected output and RC. Raises an error if input can't be read, executable fails, or output/RC are not as expected. Error is caught by bctester() and reported. """ # Get the exec names and arguments - execprog = testObj['exec'] + exeext + execprog = buildenv.BUILDDIR + "/src/" + testObj['exec'] + buildenv.exeext execargs = testObj['args'] execrun = [execprog] + execargs @@ -112,7 +112,7 @@ def bctester(testDir, input_basename, buildenv): for testObj in input_data: try: - bctest(testDir, testObj, buildenv.exeext) + bctest(testDir, testObj, buildenv) logging.info("PASSED: " + testObj["description"]) except: logging.info("FAILED: " + testObj["description"]) diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py new file mode 100755 index 0000000000..e09a25159d --- /dev/null +++ b/test/util/bitcoin-util-test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# Copyright 2014 BitPay Inc. +# Copyright 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. +from __future__ import division,print_function,unicode_literals +import os +import sys +import argparse +import logging + +help_text="""Test framework for bitcoin utils. + +Runs automatically during `make check`. + +Can also be run manually.""" + +if __name__ == '__main__': + sys.path.append(os.path.dirname(os.path.abspath(__file__))) + import buildenv + import bctest + + parser = argparse.ArgumentParser(description=help_text) + parser.add_argument('-v', '--verbose', action='store_true') + args = parser.parse_args() + verbose = args.verbose + + if verbose: + level = logging.DEBUG + else: + level = logging.ERROR + formatter = '%(asctime)s - %(levelname)s - %(message)s' + # Add the format/level to the logger + logging.basicConfig(format = formatter, level=level) + + bctest.bctester(buildenv.SRCDIR + "/test/util/data", "bitcoin-util-test.json", buildenv) diff --git a/test/util/buildenv.py.in b/test/util/buildenv.py.in new file mode 100644 index 0000000000..33030b0348 --- /dev/null +++ b/test/util/buildenv.py.in @@ -0,0 +1,4 @@ +#!/usr/bin/env python +exeext="@EXEEXT@" +SRCDIR="@abs_top_srcdir@" +BUILDDIR="@abs_top_builddir@" diff --git a/src/test/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json index a80ab51901..a80ab51901 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json diff --git a/src/test/data/blanktxv1.hex b/test/util/data/blanktxv1.hex index 36b6f00fb6..36b6f00fb6 100644 --- a/src/test/data/blanktxv1.hex +++ b/test/util/data/blanktxv1.hex diff --git a/src/test/data/blanktxv1.json b/test/util/data/blanktxv1.json index 51c25a5a98..51c25a5a98 100644 --- a/src/test/data/blanktxv1.json +++ b/test/util/data/blanktxv1.json diff --git a/src/test/data/blanktxv2.hex b/test/util/data/blanktxv2.hex index 22d830eda1..22d830eda1 100644 --- a/src/test/data/blanktxv2.hex +++ b/test/util/data/blanktxv2.hex diff --git a/src/test/data/blanktxv2.json b/test/util/data/blanktxv2.json index 266919f445..266919f445 100644 --- a/src/test/data/blanktxv2.json +++ b/test/util/data/blanktxv2.json diff --git a/src/test/data/tt-delin1-out.hex b/test/util/data/tt-delin1-out.hex index 42ad840f43..42ad840f43 100644 --- a/src/test/data/tt-delin1-out.hex +++ b/test/util/data/tt-delin1-out.hex diff --git a/src/test/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json index 712a2c27f8..712a2c27f8 100644 --- a/src/test/data/tt-delin1-out.json +++ b/test/util/data/tt-delin1-out.json diff --git a/src/test/data/tt-delout1-out.hex b/test/util/data/tt-delout1-out.hex index cc60c3fac6..cc60c3fac6 100644 --- a/src/test/data/tt-delout1-out.hex +++ b/test/util/data/tt-delout1-out.hex diff --git a/src/test/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json index afc4e95762..afc4e95762 100644 --- a/src/test/data/tt-delout1-out.json +++ b/test/util/data/tt-delout1-out.json diff --git a/src/test/data/tt-locktime317000-out.hex b/test/util/data/tt-locktime317000-out.hex index 287f420a40..287f420a40 100644 --- a/src/test/data/tt-locktime317000-out.hex +++ b/test/util/data/tt-locktime317000-out.hex diff --git a/src/test/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json index 2b9075f8ac..2b9075f8ac 100644 --- a/src/test/data/tt-locktime317000-out.json +++ b/test/util/data/tt-locktime317000-out.json diff --git a/src/test/data/tx394b54bb.hex b/test/util/data/tx394b54bb.hex index 33f26cb4d6..33f26cb4d6 100644 --- a/src/test/data/tx394b54bb.hex +++ b/test/util/data/tx394b54bb.hex diff --git a/src/test/data/txcreate1.hex b/test/util/data/txcreate1.hex index 9ec6ee3531..9ec6ee3531 100644 --- a/src/test/data/txcreate1.hex +++ b/test/util/data/txcreate1.hex diff --git a/src/test/data/txcreate1.json b/test/util/data/txcreate1.json index f83e036f33..f83e036f33 100644 --- a/src/test/data/txcreate1.json +++ b/test/util/data/txcreate1.json diff --git a/src/test/data/txcreate2.hex b/test/util/data/txcreate2.hex index 38bb7b1046..38bb7b1046 100644 --- a/src/test/data/txcreate2.hex +++ b/test/util/data/txcreate2.hex diff --git a/src/test/data/txcreate2.json b/test/util/data/txcreate2.json index fb5e177db7..fb5e177db7 100644 --- a/src/test/data/txcreate2.json +++ b/test/util/data/txcreate2.json diff --git a/src/test/data/txcreatedata1.hex b/test/util/data/txcreatedata1.hex index cefd1a05a6..cefd1a05a6 100644 --- a/src/test/data/txcreatedata1.hex +++ b/test/util/data/txcreatedata1.hex diff --git a/src/test/data/txcreatedata1.json b/test/util/data/txcreatedata1.json index 760518d30a..760518d30a 100644 --- a/src/test/data/txcreatedata1.json +++ b/test/util/data/txcreatedata1.json diff --git a/src/test/data/txcreatedata2.hex b/test/util/data/txcreatedata2.hex index d69cf58ba1..d69cf58ba1 100644 --- a/src/test/data/txcreatedata2.hex +++ b/test/util/data/txcreatedata2.hex diff --git a/src/test/data/txcreatedata2.json b/test/util/data/txcreatedata2.json index 3c6da40f90..3c6da40f90 100644 --- a/src/test/data/txcreatedata2.json +++ b/test/util/data/txcreatedata2.json diff --git a/src/test/data/txcreatedata_seq0.hex b/test/util/data/txcreatedata_seq0.hex index 54b89d2381..54b89d2381 100644 --- a/src/test/data/txcreatedata_seq0.hex +++ b/test/util/data/txcreatedata_seq0.hex diff --git a/src/test/data/txcreatedata_seq0.json b/test/util/data/txcreatedata_seq0.json index d272a4c447..d272a4c447 100644 --- a/src/test/data/txcreatedata_seq0.json +++ b/test/util/data/txcreatedata_seq0.json diff --git a/src/test/data/txcreatedata_seq1.hex b/test/util/data/txcreatedata_seq1.hex index 4cedcd975c..4cedcd975c 100644 --- a/src/test/data/txcreatedata_seq1.hex +++ b/test/util/data/txcreatedata_seq1.hex diff --git a/src/test/data/txcreatedata_seq1.json b/test/util/data/txcreatedata_seq1.json index d323255418..d323255418 100644 --- a/src/test/data/txcreatedata_seq1.json +++ b/test/util/data/txcreatedata_seq1.json diff --git a/src/test/data/txcreatemultisig1.hex b/test/util/data/txcreatemultisig1.hex index 9c00004d38..9c00004d38 100644 --- a/src/test/data/txcreatemultisig1.hex +++ b/test/util/data/txcreatemultisig1.hex diff --git a/src/test/data/txcreatemultisig1.json b/test/util/data/txcreatemultisig1.json index f6ce43c202..f6ce43c202 100644 --- a/src/test/data/txcreatemultisig1.json +++ b/test/util/data/txcreatemultisig1.json diff --git a/src/test/data/txcreatemultisig2.hex b/test/util/data/txcreatemultisig2.hex index 07835c54d3..07835c54d3 100644 --- a/src/test/data/txcreatemultisig2.hex +++ b/test/util/data/txcreatemultisig2.hex diff --git a/src/test/data/txcreatemultisig2.json b/test/util/data/txcreatemultisig2.json index e09d22060f..e09d22060f 100644 --- a/src/test/data/txcreatemultisig2.json +++ b/test/util/data/txcreatemultisig2.json diff --git a/src/test/data/txcreatemultisig3.hex b/test/util/data/txcreatemultisig3.hex index 8d34f28f87..8d34f28f87 100644 --- a/src/test/data/txcreatemultisig3.hex +++ b/test/util/data/txcreatemultisig3.hex diff --git a/src/test/data/txcreatemultisig3.json b/test/util/data/txcreatemultisig3.json index 88e32bd310..88e32bd310 100644 --- a/src/test/data/txcreatemultisig3.json +++ b/test/util/data/txcreatemultisig3.json diff --git a/src/test/data/txcreatemultisig4.hex b/test/util/data/txcreatemultisig4.hex index 7da54366c7..7da54366c7 100644 --- a/src/test/data/txcreatemultisig4.hex +++ b/test/util/data/txcreatemultisig4.hex diff --git a/src/test/data/txcreatemultisig4.json b/test/util/data/txcreatemultisig4.json index fc69c7269c..fc69c7269c 100644 --- a/src/test/data/txcreatemultisig4.json +++ b/test/util/data/txcreatemultisig4.json diff --git a/src/test/data/txcreateoutpubkey1.hex b/test/util/data/txcreateoutpubkey1.hex index 4a08244b2f..4a08244b2f 100644 --- a/src/test/data/txcreateoutpubkey1.hex +++ b/test/util/data/txcreateoutpubkey1.hex diff --git a/src/test/data/txcreateoutpubkey1.json b/test/util/data/txcreateoutpubkey1.json index 6019fa2dcd..6019fa2dcd 100644 --- a/src/test/data/txcreateoutpubkey1.json +++ b/test/util/data/txcreateoutpubkey1.json diff --git a/src/test/data/txcreateoutpubkey2.hex b/test/util/data/txcreateoutpubkey2.hex index 8283c722ab..8283c722ab 100644 --- a/src/test/data/txcreateoutpubkey2.hex +++ b/test/util/data/txcreateoutpubkey2.hex diff --git a/src/test/data/txcreateoutpubkey2.json b/test/util/data/txcreateoutpubkey2.json index 6fc3d57527..6fc3d57527 100644 --- a/src/test/data/txcreateoutpubkey2.json +++ b/test/util/data/txcreateoutpubkey2.json diff --git a/src/test/data/txcreateoutpubkey3.hex b/test/util/data/txcreateoutpubkey3.hex index 84adff4d89..84adff4d89 100644 --- a/src/test/data/txcreateoutpubkey3.hex +++ b/test/util/data/txcreateoutpubkey3.hex diff --git a/src/test/data/txcreateoutpubkey3.json b/test/util/data/txcreateoutpubkey3.json index a1a25fc834..a1a25fc834 100644 --- a/src/test/data/txcreateoutpubkey3.json +++ b/test/util/data/txcreateoutpubkey3.json diff --git a/src/test/data/txcreatescript1.hex b/test/util/data/txcreatescript1.hex index 0adce270fb..0adce270fb 100644 --- a/src/test/data/txcreatescript1.hex +++ b/test/util/data/txcreatescript1.hex diff --git a/src/test/data/txcreatescript1.json b/test/util/data/txcreatescript1.json index 8ffecba411..8ffecba411 100644 --- a/src/test/data/txcreatescript1.json +++ b/test/util/data/txcreatescript1.json diff --git a/src/test/data/txcreatescript2.hex b/test/util/data/txcreatescript2.hex index 5afe8786e3..5afe8786e3 100644 --- a/src/test/data/txcreatescript2.hex +++ b/test/util/data/txcreatescript2.hex diff --git a/src/test/data/txcreatescript2.json b/test/util/data/txcreatescript2.json index 41eb69f1af..41eb69f1af 100644 --- a/src/test/data/txcreatescript2.json +++ b/test/util/data/txcreatescript2.json diff --git a/src/test/data/txcreatescript3.hex b/test/util/data/txcreatescript3.hex index 8a2b973bf0..8a2b973bf0 100644 --- a/src/test/data/txcreatescript3.hex +++ b/test/util/data/txcreatescript3.hex diff --git a/src/test/data/txcreatescript3.json b/test/util/data/txcreatescript3.json index 90e7e27f9f..90e7e27f9f 100644 --- a/src/test/data/txcreatescript3.json +++ b/test/util/data/txcreatescript3.json diff --git a/src/test/data/txcreatescript4.hex b/test/util/data/txcreatescript4.hex index b4cfe58f42..b4cfe58f42 100644 --- a/src/test/data/txcreatescript4.hex +++ b/test/util/data/txcreatescript4.hex diff --git a/src/test/data/txcreatescript4.json b/test/util/data/txcreatescript4.json index 11783751a4..11783751a4 100644 --- a/src/test/data/txcreatescript4.json +++ b/test/util/data/txcreatescript4.json diff --git a/src/test/data/txcreatesignv1.hex b/test/util/data/txcreatesignv1.hex index a46fcc88cb..a46fcc88cb 100644 --- a/src/test/data/txcreatesignv1.hex +++ b/test/util/data/txcreatesignv1.hex diff --git a/src/test/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json index ff39e71b40..ff39e71b40 100644 --- a/src/test/data/txcreatesignv1.json +++ b/test/util/data/txcreatesignv1.json diff --git a/src/test/data/txcreatesignv2.hex b/test/util/data/txcreatesignv2.hex index ee425cd98c..ee425cd98c 100644 --- a/src/test/data/txcreatesignv2.hex +++ b/test/util/data/txcreatesignv2.hex |